5

Creating an HMAC steps by using CryptoAPI found here: http://msdn.microsoft.com/en-us/library/Aa379863

  • To compute an HMAC

    1. Get a pointer to the Microsoft Cryptographic Service Provider (CSP) by calling CryptAcquireContext.
    2. 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.
    3. 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.
    4. 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.
    5. 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;
}
bluish
  • 26,356
  • 27
  • 122
  • 180
user954753
  • 309
  • 1
  • 3
  • 14
  • 2
    What were the compile-time errors? – Andy Finkenstadt Sep 25 '11 at 19:02
  • Sorry, I meant to say Run, not compile. Errors I get when I run are: Error in CryptImportKey 0x8009007 Error in CryptCreatHash 0x8009003 Error in CryptSetHashParam 0x00000057 Error in CryptHashData 0x00000057 Error in CryptGetHashParam 0x00000057 – user954753 Sep 25 '11 at 19:22
  • This is by no stretch the sample app from MSDN. It was changed on multiple occasions: see http://msdn.microsoft.com/en-us/library/aa382379(v=VS.85).aspx – sehe Sep 25 '11 at 19:45
  • This does not return the true values as evidence by: http://buchananweb.co.uk/security01.aspx :-( – user954753 Sep 25 '11 at 20:51

1 Answers1

2

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 :))

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Added: #define CALG_HMAC CALG_SHA1 And now I get errros: CryptImportKey 0x80090007 and CryptSetHashParam 0x8009000A. Did you use the code I posted? – user954753 Sep 25 '11 at 19:33
  • @user954753: what else :) However, you posted the runtime error later - I got `Error in !CryptImportKey 0x80090005 Error in CryptSetHashParam 0x80090020` - seems similar enough. I'm afraid something else is going on (but I answered the question because you mentioned it wouldn't compile, and it didn't compile without that define, for me) – sehe Sep 25 '11 at 19:36
  • I dug in deeper and came up with a few clues that might help you. Especially the fact that you try to use CryptImportKey might have more consequences than you thought (as far as acquiring a provider context is concerned) – sehe Sep 25 '11 at 20:07
  • Why do you initialize dwDataLen = 20 (instead of 0)? -> I want output to be 20 bytes long. Why did you change the hash algorithm from SHA1 - > I was just trying to follow the 5 steps. I did everything the steps told me to-do. – user954753 Sep 25 '11 at 20:32
  • @user954753: the answer is: the problem is _NOT_ with the steps to do the HMAC. Instead, it is with the steps to do CryptImportKey. Different tutorial to read. – sehe Sep 25 '11 at 22:06