C++、C#、HMACSHA1、HMACSHA256


ついでに、CryptAPIでHMACSHA256を作成しました。
当たり前ですが、C#のHMACSHA256と同じ結果を出力します。
HMACSHA1も可。
返り値であるCStringAはバイナリのコンテナとして使用しているので、読める字に直すにはBase64Encodeが必要。


CStringA HMACSHA( const CStringA& key, const CStringA& data, DWORD algid )
{
//ttp://codebrook.wordpress.com/2010/07/14/twitter-oauth-in-c-for-win32-part-2/

HCRYPTPROV hProv = NULL;
HCRYPTKEY hKey = NULL;
HCRYPTHASH hHmacHash = NULL;
PBYTE pbHash = NULL;
DWORD dwDataLen = 0;
HMAC_INFO HmacInfo;

ATLASSERT( algid == CALG_SHA_256 || algid == CALG_SHA1 );

ZeroMemory(&HmacInfo, sizeof(HmacInfo));
HmacInfo.HashAlgid = algid;

BOOL bl = CryptAcquireContext( &hProv,NULL,MS_ENH_RSA_AES_PROV,PROV_RSA_AES,CRYPT_VERIFYCONTEXT);
ATLASSERT( bl );


struct KeyBLOBHead
{
BLOBHEADER hdr;
DWORD len;
};

int KeyBLOBSize = sizeof(KeyBLOBHead) + key.GetLength(); // KeyBLOBHeadの後ろにキーデータ

byte* ph = new byte[KeyBLOBSize];

//CRYPT_IPSEC_HMAC_KEY:
//Note: Allows for the import of an RC2 key that is larger than 16 bytes.
//If this flag is not set, calls to the CryptImportKey function with RC2 keys
//that are greater than 16 bytes fail, and a call to GetLastError will return NTE_BAD_DATA.


KeyBLOBHead* pbh = (KeyBLOBHead*)ph;
pbh->hdr.bType = PLAINTEXTKEYBLOB;
pbh->hdr.bVersion = CUR_BLOB_VERSION;
pbh->hdr.reserved = 0;
pbh->hdr.aiKeyAlg = CALG_RC2;
pbh->len = key.GetLength();

byte* keyblob = (byte*)pbh + sizeof(KeyBLOBHead);

CopyMemory(keyblob, (LPCSTR)key, pbh->len );

bl = CryptImportKey(hProv, ph,KeyBLOBSize, 0,CRYPT_IPSEC_HMAC_KEY, OUT &hKey);
ATLASSERT( bl );

delete [] ph;


bl = CryptCreateHash(hProv,CALG_HMAC,hKey, 0, OUT &hHmacHash);
ATLASSERT( bl );

bl = CryptSetHashParam(hHmacHash, HP_HMAC_INFO,(BYTE*)&HmacInfo,0);
ATLASSERT( bl );

bl = CryptHashData(hHmacHash, (BYTE*)(LPCSTR)data, data.GetLength(),0);
ATLASSERT( bl );


bl = CryptGetHashParam(hHmacHash, HP_HASHVAL,NULL,&dwDataLen, 0); // calc length
ATLASSERT( bl );

pbHash = new BYTE[dwDataLen];

bl = CryptGetHashParam(hHmacHash, HP_HASHVAL, pbHash,&dwDataLen, 0);
ATLASSERT( bl );

CStringA hmacsha( (LPCSTR)pbHash, dwDataLen );

delete [] pbHash;



if(hHmacHash)
CryptDestroyHash(hHmacHash);
if(hKey)
CryptDestroyKey(hKey);
if(hProv)
CryptReleaseContext(hProv, 0);

return hmacsha;
}