Skip to content

Instantly share code, notes, and snippets.

@pps83
Created July 11, 2018 03:21
Show Gist options
  • Save pps83/51064f120aedb3835636581cc7275f46 to your computer and use it in GitHub Desktop.
Save pps83/51064f120aedb3835636581cc7275f46 to your computer and use it in GitHub Desktop.
Compute sha1/md5/hmac-sha1/hmac-md5 using windows API
#ifdef _WIN32
#include <windows.h>
#if !defined(PLATFORM_XBOX) && !defined(PLATFORM_UWP)
#include <wincrypt.h>
#else
#include <bcrypt.h>
#pragma comment(lib, "bcrypt.lib")
#endif
int computeHash(const void* data, unsigned dataSize, unsigned char hashBuf[64], const void *hmacSecret, unsigned hmacSecretSize, bool isMD5)
{
int ret = 0;
const int hashBufSize = 64;
unsigned char hashBuf1[64] = { 0 };
assert((hmacSecret && hmacSecretSize > 0) || (!hmacSecret && hmacSecretSize == 0));
DWORD hashSize, hashSizeSize = sizeof(hashSize);
#if !defined(PLATFORM_XBOX) && !defined(PLATFORM_UWP)
HCRYPTPROV context;
if (CryptAcquireContext(&context, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
HCRYPTKEY hmackey = 0;
if (hmacSecret)
{
struct HmacSecretBlob
{
BLOBHEADER header;
DWORD hmacSecretSize;
BYTE hmacSecret[1];
};
size_t hmacSecretBlobSize = std::max(offsetof(HmacSecretBlob, hmacSecret) + hmacSecretSize, sizeof(HmacSecretBlob));
std::vector<uint8_t> blobData(hmacSecretBlobSize);
HmacSecretBlob* hmacSecretBlob = reinterpret_cast<HmacSecretBlob*>(blobData.data());
hmacSecretBlob->header.bType = PLAINTEXTKEYBLOB;
hmacSecretBlob->header.bVersion = CUR_BLOB_VERSION;
hmacSecretBlob->header.reserved = 0;
hmacSecretBlob->header.aiKeyAlg = CALG_RC2;
hmacSecretBlob->hmacSecretSize = hmacSecretSize;
memcpy(hmacSecretBlob->hmacSecret, hmacSecret, hmacSecretSize);
if (!CryptImportKey(context, blobData.data(), blobData.size(), 0, CRYPT_IPSEC_HMAC_KEY, &hmackey))
{
CryptReleaseContext(context, 0);
return 0;
}
}
HCRYPTHASH hash;
if (CryptCreateHash(context, hmacSecret ? CALG_HMAC : (isMD5 ? CALG_MD5 : CALG_SHA1), hmackey, 0, &hash))
{
if (hmacSecret)
{
HMAC_INFO info = { 0 };
info.HashAlgid = isMD5 ? CALG_MD5 : CALG_SHA1;
if (!CryptSetHashParam(hash, HP_HMAC_INFO, (BYTE *)&info, 0))
{
CryptReleaseContext(context, 0);
CryptDestroyHash(hash);
return 0;
}
}
if (CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *)&hashSize, &hashSizeSize, 0) && hashSize <= hashBufSize)
{
assert((isMD5 && hashSize == 16) || (!isMD5 && hashSize == 20)); // 16 bytes for MD5, 20 bytes for sha1
if (CryptHashData(hash, (BYTE*)data, dataSize, 0))
{
if (CryptGetHashParam(hash, HP_HASHVAL, hashBuf, &hashSize, 0))
ret = (int)hashSize;
}
}
CryptDestroyHash(hash);
}
if (hmacSecret)
CryptDestroyKey(hmackey);
CryptReleaseContext(context, 0);
}
#else
BCRYPT_ALG_HANDLE context;
if (BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&context, isMD5 ? BCRYPT_MD5_ALGORITHM : BCRYPT_SHA1_ALGORITHM, NULL, hmacSecret ? BCRYPT_ALG_HANDLE_HMAC_FLAG : 0)))
{
BCRYPT_HASH_HANDLE hash;
if (BCRYPT_SUCCESS(BCryptGetProperty(context, BCRYPT_HASH_LENGTH, (PUCHAR)&hashSize, sizeof(hashSize), &hashSizeSize, 0)) && hashSize <= hashBufSize)
{
assert((isMD5 && hashSize == 16) || (!isMD5 && hashSize == 20)); // 16 bytes for MD5, 20 bytes for sha1
if (BCRYPT_SUCCESS(BCryptCreateHash(context, &hash, NULL, 0, (PUCHAR)hmacSecret, hmacSecretSize, 0)))
{
if (BCRYPT_SUCCESS(BCryptHashData(hash, (PUCHAR)data, dataSize, 0)))
{
if (BCRYPT_SUCCESS(BCryptFinishHash(hash, hashBuf, hashSize, 0)))
ret = hashSize;
}
BCryptDestroyHash(hash);
}
}
BCryptCloseAlgorithmProvider(context, 0);
}
#endif
return ret;
}
#endif // _WIN32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment