MSDN HMAC-SHA1 example not working - c++

Creating an HMAC steps by using CryptoAPI found here: http://msdn.microsoft.com/en-us/library/Aa379863
To compute an HMAC
Get a pointer to the Microsoft Cryptographic Service Provider
(CSP) by calling CryptAcquireContext.
Create a handle to an HMAChash object by calling
CryptCreateHash. Pass CALG_HMAC in the Algid parameter. Pass the
handle of a symmetric key in the hKey parameter. This symmetric key
is the key used to compute the HMAC.
Specify the type of hash to be used by calling
CryptSetHashParam with the dwParam parameter set to the value
HP_HMAC_INFO. The pbData parameter must point to an initialized
HMAC_INFO structure.
Call CryptHashData to begin computing the HMAC of the data. The
first call to CryptHashData causes the key value to be combined using
the XOR operator with the inner string and the data. The result of
the XOR operation is hashed, and then the target data for the HMAC
(pointed to by the pbData parameter passed in the call to
CryptHashData) is hashed. If necessary, subsequent calls to
CryptHashData may then be made to finish the hashing of the target
data.
Call CryptGetHashParam with the dwParam parameter set to
HP_HASHVAL. This call causes the inner hash to be finished and the
outer string to be combined using XOR with the key. The result of the
XOR operation is hashed, and then the result of the inner hash
(completed in the previous step) is hashed. The outer hash is then
finished and returned in the pbData parameter and the length in the
dwDataLen parameter.
I can not, for the life of me get this working. I have all the steps in order, and still can not even run my program. Errors while running:
Error in CryptImportKey 0x8009007
Error in CryptCreatHash 0x8009003
Error in CryptSetHashParam 0x00000057
Error in CryptHashData 0x00000057
Error in CryptGetHashParam 0x00000057
Can anyone help?
#include <iostream>
#include <windows.h>
#include <wincrypt.h>
using namespace std;
#define CALG_HMAC CALG_SHA1
int main()
{
//--------------------------------------------------------------------
// Declare variables.
HCRYPTPROV hProv = NULL;
HCRYPTHASH hHash = NULL;
HCRYPTKEY hKey = NULL;
BYTE DesKeyBlob[] = { 0x70,0x61,0x73,0x73,0x77,0x6F,0x72,0x64 };
HCRYPTHASH hHmacHash = NULL;
PBYTE pbHash = NULL;
DWORD dwDataLen = 20;
BYTE Data[] = {0x6D,0x65,0x73,0x73,0x61,0x67,0x65};
HMAC_INFO HmacInfo;
//--------------------------------------------------------------------
// Zero the HMAC_INFO structure
ZeroMemory(&HmacInfo, sizeof(HmacInfo));
HmacInfo.HashAlgid = CALG_HMAC;
HmacInfo.pbInnerString = (BYTE*)0x36;
HmacInfo.cbInnerString = 0;
HmacInfo.pbOuterString = (BYTE*)0x5C;
HmacInfo.cbOuterString = 0;
// Step 1
if (!CryptAcquireContext(
&hProv, // handle of the CSP
NULL, // key container name
NULL, // CSP name
PROV_RSA_FULL, // provider type
CRYPT_VERIFYCONTEXT)) // no key access is requested
{
printf(" Error in AcquireContext 0x%08x \n",
GetLastError());
}
//--------------------------------------------------------------------
//Step 2
//in step two, we need the hash key used to be imported?
//imports the key used... as hKey1
if(!CryptImportKey(
hProv,
DesKeyBlob,
sizeof(DesKeyBlob),
0,
CRYPT_EXPORTABLE,
&hKey ))
{
printf("Error in !CryptImportKey 0x%08x \n",
GetLastError());
}
if (!CryptCreateHash(
hProv, // handle of the CSP
CALG_HMAC, // hash algorithm to use
hKey, // hash key this shoudl point to a key used to compute the HMAC?
0, // reserved
&hHmacHash // address of hash object handle
)){
printf("Error in CryptCreateHash 0x%08x \n",
GetLastError());
}
// Step 3
if (!CryptSetHashParam(
hHmacHash,//hProv,//hHash,//hHmacHash, // handle of the HMAC hash object
HP_HMAC_INFO, // setting an HMAC_INFO object
(BYTE*)&HmacInfo, // the HMAC_INFO object
0)) // reserved
{
printf("Error in CryptSetHashParam 0x%08x \n",
GetLastError());
}
//Step 4
if (!CryptHashData(
hHmacHash, // handle of the HMAC hash object
Data, // message to hash
sizeof(Data), // number of bytes of data to add
0)) // flags
{
printf("Error in CryptHashData 0x%08x \n",
GetLastError());
}
//Step 5
if (!CryptGetHashParam(
hHmacHash, // handle of the HMAC hash object
HP_HASHVAL, // query on the hash value
pbHash, // pointer to the HMAC hash value
&dwDataLen, // length, in bytes, of the hash
0))
{
printf("Error in CryptGetHashParam 0x%08x \n", GetLastError());
}
// Print the hash to the console.
printf("The hash is: ");
for(DWORD i = 0 ; i < dwDataLen ; i++)
{
printf("%2.2x ",pbHash[i]);
}
printf("\n");
int a;
std::cin >> a;
return 0;
}

You might (?1) need to specify what hash algorithm you want to use.
#define CALG_HMAC CALG_SHA1 // or CALG_MD5 etc
Edit
Why do you initialize dwDataLen = 20 (instead of 0)?
Why did you change the hash algorithm from SHA1
Why do you not exit on ErrorExit anymore (that alone will prevent the crash instead of proper error message)
You use CryptImportKey instead of CryptDeriveKey -- no such thing even exists in the sample on MSDN. It can't be a coincidence that CryptImportKey is the call failing with 0x80090005 (NTE_BAD_DATA). The key is not supported by your CSP!
For that to work, you need key access so you'd at least need to change CRYPT_VERIFY_CONTEXT into something else (don't know what); I tried using
.
if (!CryptAcquireContext(
&hProv,
NULL,
MS_STRONG_PROV, // allow 2048 bit keys, in case you need it
PROV_RSA_FULL,
CRYPT_MACHINE_KEYSET)) // just a guess
Now my program results in 0x80090016: Keyset does not exist. This might simply be because I don't have that keyset, or because I'm running on Linux under Wine.
Hope this helps.
1 Compiled on Linux using:
i586-mingw32msvc-g++ -m32 -O2 -g test.cpp -o test.exe
It did crash when run (without parameters) but that might be wine incompatibility (or the fact that I haven't read the source to see what it does :))

Related

RegOpenKeyEx Not finding an existing value

I am checking to see if the value "XXS" exists in the run registry
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\XXS", 0, KEY_READ | KEY_WOW64_64KEY, &hkey) == ERROR_FILE_NOT_FOUND)
{
std::cout << "KEY NOT FOUND";
LONG createStatus = RegCreateKey(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", &hkey); //Creates a key
LONG status = RegSetValueEx(hkey, L"XXS", 0, REG_SZ, (LPBYTE)path, (size + 1) * sizeof(WCHAR));
}
I am not sure why this is happening and if I am using this function right. The key does exist but it says it does not. The program is 64 bit running on 64 bit pc
I think the issue here is that you do not differentiate between keys and values.
Registry keys are container objects similar to folders. Registry values are non-container objects similar to files. Keys may contain values and subkeys.
So you basically need to open/create a key and then handle the values in it.
In your case, i'd try something like this (but be aware, from the top of my head, not tested):
#define HKLM_BASE L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"
HKEY hKey;
wchar_t buf[256] = { 0 };
LONG regError = RegOpenKeyEx(HKEY_LOCAL_MACHINE,HKLM_BASE,0, KEY_WOW64_64KEY | KEY_ALL_ACCESS,&hKey);
if (regError == ERROR_SUCCESS)
{
DWORD dwDataSize = sizeof(buf);
regError = RegQueryValueEx(hKey,L"XXS", NULL, NULL,(LPBYTE)&buf,&dwDataSize);
if ((regError != ERROR_SUCCESS) )
{
wchar_t *path =L"your value";
if (ERROR_SUCCESS != RegSetValueEx(hKey,L"XXS",NULL,REG_SZ,((const BYTE*)&path),wcslen (path)))
{
/* handle error */
}
} else {
/* current value in buf */
}
RegFlushKey( hKey );
RegCloseKey( hKey );
} else {
/* handle error */
}
Welcome to stack overflow! While typing this I see Morphine was just a little bit quicker. But he forgot to explain most of the the changes he made. So here are my 2 cents. The example of Morphine is fine , I won't provide another one.
I think XXS is a value (since you create a value, not a key, if it does not exist). This means you need to check if the value exist, right after you open the registry key. I also advise you to check on any error returning from the function RegOpenKeyEx, not only the ERROR_FILE_NOT_FOUND error.
Another thing I recommend is using RegCreateKeyEx instead of RegCreateKey, this since the documentation says the following:
Note This function is provided only for compatibility with 16-bit
versions of Windows. Applications should use the RegCreateKeyEx
function. However, applications that back up or restore system state
including system files and registry hives should use the Volume Shadow
Copy Service instead of the registry functions.
Last but not least, don't forget to close the keys once you do not need them anymore. You don't have to close values.

Will this digital signing code work with a Qualified Digital Certificate?

I was recently asked if our existing signing code will work with a European Qualified Digital Certificate in place of the RSA signing certificate we normally use. As far as I can tell it should, but I haven't found anything that actually confirms this theory.
Short of figuring out how to acquire a qualified certificate and actually testing it, I'm not sure how to answer this question definitively. Anybody happen to have experience with this?
The code in question is shown below. It's a Windows-based C++ application that is using Microsoft's Cryptographic API for signing.
int SignData(
const std::string &data, // Data to be signed
const char *containerName, // Name of key container to use
std::string &signature) // Returns the signature
{
HCRYPTPROV hProv = NULL;
HCRYPTHASH hHash = NULL;
HCRYPTKEY hKey = NULL;
DWORD dwLength;
int status = 0;
// Attempt to open the key container as a LocalMachine key.
if (CryptAcquireContext(
&hProv,
containerName,
NULL,
PROV_RSA_FULL,
CRYPT_MACHINE_KEYSET | CRYPT_SILENT))
{
// Create a SHA-1 hash context.
if (CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
{
// Calculate hash of the buffer.
if (CryptHashData(hHash, (const BYTE *)data.data(), (DWORD)data.size(), 0))
{
// Determine the size of the signature and allocate memory.
if (CryptSignHash(hHash, AT_SIGNATURE, 0, 0, NULL, &dwLength))
{
signature.resize(dwLength);
// Sign the hash object.
if (!CryptSignHash(hHash, AT_SIGNATURE, 0, 0, (BYTE*)&signature[0], &dwLength))
status = HandleCryptError("CryptSignHash failed");
}
else
status = HandleCryptError("CryptSignHash failed");
}
else
status = HandleCryptError("CryptHashData failed");
}
else
status = HandleCryptError("CryptCreateHash failed");
}
else
status = HandleCryptError("CryptAcquireContext failed");
return status;
}
The above code is using the default Microsoft software cryptographic provider which doesn't meet the requirements of eIDAS.
If you replace the default Microsoft provider by an eIDAS compliant provider in the above code then this approach of performing signature is OK. Under the hood, the compliant CSP will take care of non-repudiation requirement of the key usage, for example by displaying a PIN popup or if the key is stored remotely in a server by sending a 2FA notification to the key owner.

What is the preferred way to get a device path for CreateFile() in a UWP C++ App?

I am converting a project to a UWP App, and thus have been following guidelines outlined in the MSDN post here. The existing project heavily relies on CreateFile() to communicate with connected devices.
There are many posts in SO that show us how to get a CreateFile()-accepted device path using SetupAPI's SetupDiGetDeviceInterfaceDetail() Is there an alternative way to do this using the PnP Configuration Manager API? Or an alternative, user-mode way at all?
I had some hope when I saw this example in Windows Driver Samples github, but quickly became dismayed when I saw that the function they used in the sample is ironically not intended for developer use, as noted in this MSDN page.
function GetDevicePath in general correct and can be used as is. about difference between CM_*(..) and CM_*_Ex(.., HMACHINE hMachine) - the CM_*(..) simply call CM_*_Ex(.., NULL) - so for local computer versions with and without _Ex suffix the same.
about concrete GetDevicePath code - call CM_Get_Device_Interface_List_Size and than CM_Get_Device_Interface_List only once not 100% correct - because between this two calls new device with this interface can be arrived to system and buffer size returned by CM_Get_Device_Interface_List_Size can be already not enough for CM_Get_Device_Interface_List. of course possibility of this very low, and you can ignore this. but i prefer make code maximum theoretical correct and call this in loop, until we not receive error other than CR_BUFFER_SMALL. also need understand that CM_Get_Device_Interface_List return multiple, NULL-terminated Unicode strings - so we need iterate here. in [example] always used only first returned symbolic link name of an interface instance. but it can be more than 1 or at all - 0 (empty). so better name function - GetDevicePaths - note s at the end. i be use code like this:
ULONG GetDevicePaths(LPGUID InterfaceClassGuid, PWSTR* pbuf)
{
CONFIGRET err;
ULONG len = 1024;//first try with some reasonable buffer size, without call *_List_SizeW
for(PWSTR buf;;)
{
if (!(buf = (PWSTR)LocalAlloc(0, len * sizeof(WCHAR))))
{
return ERROR_NO_SYSTEM_RESOURCES;
}
switch (err = CM_Get_Device_Interface_ListW(InterfaceClassGuid, 0, buf, len, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
case CR_BUFFER_SMALL:
err = CM_Get_Device_Interface_List_SizeW(&len, InterfaceClassGuid, 0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
default:
LocalFree(buf);
if (err)
{
return CM_MapCrToWin32Err(err, ERROR_UNIDENTIFIED_ERROR);
}
continue;
case CR_SUCCESS:
*pbuf = buf;
return NOERROR;
}
}
}
and usage example:
void example()
{
PWSTR buf, sz;
if (NOERROR == GetDevicePaths((GUID*)&GUID_DEVINTERFACE_VOLUME, &buf))
{
sz = buf;
while (*sz)
{
DbgPrint("%S\n", sz);
HANDLE hFile = CreateFile(sz, FILE_GENERIC_READ, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
// do something
CloseHandle(hFile);
}
sz += 1 + wcslen(sz);
}
LocalFree(buf);
}
}
so we must not simply use in returned DevicePathS (sz) only first string, but iterate it
while (*sz)
{
// use sz
sz += 1 + wcslen(sz);
}
I got a valid Device Path to a USB Hub Device, and used it successfully to get various device descriptors by sending some IOCTLs, by using the function I posted in my own answer to another question
I'm reporting the same function below:
This function returns a list of NULL-terminated Device Paths (that's what we get from CM_Get_Device_Interface_List())
You need to pass it the DEVINST, and the wanted interface GUID.
Since both the DEVINST and interface GUID are specified, it is highly likely that CM_Get_Device_Interface_List() will return a single Device Path for that interface, but technically you should be prepared to get more than one result.
It is responsibility of the caller to delete[] the returned list if the function returns successfully (return code 0)
int GetDevInstInterfaces(DEVINST dev, LPGUID interfaceGUID, wchar_t**outIfaces, ULONG* outIfacesLen)
{
CONFIGRET cres;
if (!outIfaces)
return -1;
if (!outIfacesLen)
return -2;
// Get System Device ID
WCHAR sysDeviceID[256];
cres = CM_Get_Device_ID(dev, sysDeviceID, sizeof(sysDeviceID) / sizeof(sysDeviceID[0]), 0);
if (cres != CR_SUCCESS)
return -11;
// Get list size
ULONG ifaceListSize = 0;
cres = CM_Get_Device_Interface_List_Size(&ifaceListSize, interfaceGUID, sysDeviceID, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cres != CR_SUCCESS)
return -12;
// Allocate memory for the list
wchar_t* ifaceList = new wchar_t[ifaceListSize];
// Populate the list
cres = CM_Get_Device_Interface_List(interfaceGUID, sysDeviceID, ifaceList, ifaceListSize, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cres != CR_SUCCESS) {
delete[] ifaceList;
return -13;
}
// Return list
*outIfaces = ifaceList;
*outIfacesLen = ifaceListSize;
return 0;
}
Please note that, as RbMm already said in his answer, you may get a CR_BUFFER_SMALL error from the last CM_Get_Device_Interface_List() call, since the device list may have been changed in the time between the CM_Get_Device_Interface_List_Size() and CM_Get_Device_Interface_List() calls.

CreateFileMapping returns ERROR_INVALID_HANDLE

I am trying to use CreateFileMapping for the first time and it is giving me this error when I use GetLastError():
ERROR_INVALID_HANDLE: The handle is invalid.
Here is my code:
// create the name of our file-mapping object
nTry++; // Ensures a unique string is used in case user closes and reopens
wsprintfA(szName, FS6IPC_MSGNAME1 ":%X:%X", GetCurrentProcessId(), nTry);
// stuff the name into a global atom
m_atom = GlobalAddAtomA(szName);
if (m_atom == 0)
{ *pdwResult = ERR_ATOM;
return FALSE;
}
// create the file-mapping object
m_hMap = CreateFileMappingA(
(HANDLE)0xFFFFFFFF, // use system paging file
NULL, // security
PAGE_READWRITE, // protection
0, MAX_SIZE+256, // size
szName); //
EDIT:
The first issue was resolved, but now my program crashes somewhere else.
#define FS6IPC_MESSAGE_SUCCESS 1
#define FS6IPC_MESSAGE_FAILURE 0
// IPC message types
#define FS6IPC_READSTATEDATA_ID 1
#define FS6IPC_WRITESTATEDATA_ID 2
// read request structure
typedef struct tagFS6IPC_READSTATEDATA_HDR
{
DWORD dwId; // FS6IPC_READSTATEDATA_ID
DWORD dwOffset; // state table offset
DWORD nBytes; // number of bytes of state data to read
void* pDest; // destination buffer for data (client use only)
} FS6IPC_READSTATEDATA_HDR;
// write request structure
typedef struct tagFS6IPC_WRITESTATEDATA_HDR
{
DWORD dwId; // FS6IPC_WRITESTATEDATA_ID
DWORD dwOffset; // state table offset
DWORD nBytes; // number of bytes of state data to write
} FS6IPC_WRITESTATEDATA_HDR;
while (*pdw)
{ switch (*pdw)
{ case FS6IPC_READSTATEDATA_ID:
pHdrR = (FS6IPC_READSTATEDATA_HDR *) pdw;
m_pNext += sizeof(FS6IPC_READSTATEDATA_HDR);
if (pHdrR->pDest && pHdrR->nBytes)
CopyMemory(pHdrR->pDest, m_pNext, pHdrR->nBytes);
m_pNext += pHdrR->nBytes; // Debugger says the issue is here
break;
case FS6IPC_WRITESTATEDATA_ID:
// This is a write, so there's no returned data to store
pHdrW = (FS6IPC_WRITESTATEDATA_HDR *) pdw;
m_pNext += sizeof(FS6IPC_WRITESTATEDATA_HDR) + pHdrW->nBytes;
break;
default:
// Error! So terminate the scan
*pdw = 0;
break;
}
pdw = (DWORD *) m_pNext;
}
I'm guessing you're running on a 64-bit system, on which HANDLEs are 64 bits. The OS is quite right—the handle value 0x00000000FFFFFFFF is an invalid handle value for your process.
What exactly are you trying to do? If you want to create a file mapping backed by an actual file, pass in the handle for that file. If you want to a create a file mapping backed by the paging file instead, pass in INVALID_HANDLE_VALUE. INVALID_HANDLE_VALUE happens to be (HANDLE)-1, which is 0xFFFFFFFF on 32-bit systems but 0xFFFFFFFFFFFFFFFF on 64-bit systems, but that doesn't really matter since you should just use the symbolic value INVALID_HANDLE_VALUE in any case.
If your application is crashing when you pass in INVALID_HANDLE_VALUE, it's not because the call to CreateFileMapping is failing, it's for some other reason, and you should debug that.

Simple AES encryption using WinAPI

I need to do simple single-block AES encryption / decryption in my Qt / C++ application. This is a "keep the honest people honest" implementation, so just a basic encrypt(key, data) is necessary--I'm not worried about initialization vectors, etc. My input and key will always be exactly 16 bytes.
I'd really like to avoid another dependency to compile / link / ship with my application, so I'm trying to use what's available on each platform. On the Mac, this was a one-liner to CCCrypt. On Windows, I'm getting lost in the API from WinCrypt.h. Their example of encrypting a file is almost 600 lines long. Seriously?
I'm looking at CryptEncrypt, but I'm falling down the rabbit hole of dependencies you have to create before you can call that.
Can anyone provide a simple example of doing AES encryption using the Windows API? Surely there's a way to do this in a line or two. Assume you already have a 128-bit key and 128-bits of data to encrypt.
Here's the best I've been able to come up with. Suggestions for improvement are welcome!
static void encrypt(const QByteArray &data,
const QByteArray &key,
QByteArray *encrypted) {
// Create the crypto provider context.
HCRYPTPROV hProvider = NULL;
if (!CryptAcquireContext(&hProvider,
NULL, // pszContainer = no named container
NULL, // pszProvider = default provider
PROV_RSA_AES,
CRYPT_VERIFYCONTEXT)) {
throw std::runtime_error("Unable to create crypto provider context.");
}
// Construct the blob necessary for the key generation.
AesBlob128 aes_blob;
aes_blob.header.bType = PLAINTEXTKEYBLOB;
aes_blob.header.bVersion = CUR_BLOB_VERSION;
aes_blob.header.reserved = 0;
aes_blob.header.aiKeyAlg = CALG_AES_128;
aes_blob.key_length = kAesBytes128;
memcpy(aes_blob.key_bytes, key.constData(), kAesBytes128);
// Create the crypto key struct that Windows needs.
HCRYPTKEY hKey = NULL;
if (!CryptImportKey(hProvider,
reinterpret_cast<BYTE*>(&aes_blob),
sizeof(AesBlob128),
NULL, // hPubKey = not encrypted
0, // dwFlags
&hKey)) {
throw std::runtime_error("Unable to create crypto key.");
}
// The CryptEncrypt method uses the *same* buffer for both the input and
// output (!), so we copy the data to be encrypted into the output array.
// Also, for some reason, the AES-128 block cipher on Windows requires twice
// the block size in the output buffer. So we resize it to that length and
// then chop off the excess after we are done.
encrypted->clear();
encrypted->append(data);
encrypted->resize(kAesBytes128 * 2);
// This acts as both the length of bytes to be encoded (on input) and the
// number of bytes used in the resulting encrypted data (on output).
DWORD length = kAesBytes128;
if (!CryptEncrypt(hKey,
NULL, // hHash = no hash
true, // Final
0, // dwFlags
reinterpret_cast<BYTE*>(encrypted->data()),
&length,
encrypted->length())) {
throw std::runtime_error("Encryption failed");
}
// See comment above.
encrypted->chop(length - kAesBytes128);
CryptDestroyKey(hKey);
CryptReleaseContext(hProvider, 0);
}