I'm trying to implement HMAC-SHA256 using Crypto API. The results are
not the same using the test vectors described in RFC 4231.
I'm not expert in using Crypto Api so I have added the code below. I
may do something wrong, but I'm not sure what.
Here is the code:
/*
* Hash the password key using HMAC-SHA-256
* Test cases are defined in rfc4231.txt
* Encrypt-then-MAC
*/
long CWinNativeCrypt::HashKey(void *szKey, DWORD cbKey,
void *pbData, DWORD cbData,
LPBYTE *pbHMAC, LPDWORD pcbHMAC)
{
long err = ERROR_OK;
HCRYPTPROV hCryptProv = 0;
err = InitializeCryptoApi(&hCryptProv);
// Create an empty hash object.
HCRYPTHASH hKeyHash = 0;
if(!CryptCreateHash(hCryptProv, CALG_SHA_256, 0, 0, &hKeyHash))
{
err = E_FAIL;
// NTE_BAD_ALGID
DWORD dwError = GetLastError();
LOG(L"Error during CryptCreateHash!");
}
if (SUCCEEDED(err))
{
// Hash the password string.
if(!CryptHashData(hKeyHash, (BYTE*)szKey, cbKey, 0))
{
err = E_FAIL;
LOG(L"Error during CryptHashData!");
}
}
if (SUCCEEDED(err))
{
HCRYPTKEY hKey = 0;
HCRYPTHASH hHash = 0;
if (CryptDeriveKey(hCryptProv, CALG_RC4, hKeyHash, 0, &hKey))
{
if ( CryptCreateHash(hCryptProv, CALG_HMAC, hKey, 0,
&hHash))
{
HMAC_INFO hmacInfo;
ZeroMemory(&hmacInfo, sizeof(HMAC_INFO));
hmacInfo.HashAlgid = CALG_SHA_256;
if ( CryptSetHashParam(hHash, HP_HMAC_INFO,
(BYTE*)&hmacInfo, 0))
{
BYTE *data = (BYTE*)pbData;
if (CryptHashData(hHash, data, cbData, 0))
{
// Allocate memory, and get the HMAC.
DWORD cbHMAC = 0;
if(CryptGetHashParam(hHash, HP_HASHVAL, NULL,
&cbHMAC, 0))
{
// Retrieve the size of the hash.
*pcbHMAC = cbHMAC;
*pbHMAC = new BYTE[cbHMAC];
if(!CryptGetHashParam(hHash,
HP_HASHVAL, *pbHMAC, &cbHMAC, 0))
{
// could not get the hmac
err = E_FAIL;
}
}
else
{
// error GetHashParam()
err = E_FAIL;
}
}
else
{
// error CryptHashData();
err = E_FAIL;
}
}
else
{
// error CryptSetHashParam();
err = E_FAIL;
}
}
else
{
// error CreateHash
err = E_FAIL;
}
}
else
{
// error CryptDeriveKey
err = E_FAIL;
}
// Destroy the hash object.
if(hHash)
{
CryptDestroyHash(hHash);
}
if (hKey)
{
CryptDestroyKey(hKey);
}
}
if (hKeyHash)
{
CryptDestroyHash(hKeyHash);
}
if (hCryptProv)
err = ReleaseCryptoApi(hCryptProv);
return err;
}
Thanks,
Gabi
You are testing HMAC(SHA-256(Key), Data) instead of HMAC(Key, Data)
that is specified in the RFC test vectors. To use a plaintext HMAC
key instead of a hashed key you need to create the key with
CryptImportKey - see the description of CRYPT_IPSEC_HMAC_KEY at
http://msdn2.microsoft.com/en-us/library/aa380207.aspx for details.