RE: Creating an HMAC for a string using a base64 encoded key



I'm all set. I grabbed the importkey snippet from the CyrptImportKey getting
invalid ALGID thread.

do this instead of the first hash / derive key of the "password"
HCRYPTKEY ImportKey(HCRYPTPROV hProv, BYTE *key, int keylen)
{
PLAINTEXTKEYBLOBSTRUCT *KeyBlob=NULL;
HCRYPTKEY hKey = NULL;

KeyBlob =(PLAINTEXTKEYBLOBSTRUCT *)LocalAlloc(LPTR,
sizeof(PLAINTEXTKEYBLOBSTRUCT) + keylen);
if (KeyBlob == NULL) {
return NULL;
}

KeyBlob->bh.bType = PLAINTEXTKEYBLOB;
KeyBlob->bh.bVersion=CUR_BLOB_VERSION;
KeyBlob->bh.reserved=0;
KeyBlob->bh.aiKeyAlg=CALG_RC2;
KeyBlob->dwKeyLen=(DWORD)keylen;
memcpy(KeyBlob +1,key,keylen);

CryptImportKey(hProv,
(BYTE*) KeyBlob,
sizeof(PLAINTEXTKEYBLOBSTRUCT),
0,
CRYPT_IPSEC_HMAC_KEY,
&hKey) ;

LocalFree(KeyBlob);
return hKey;
}


"David Moore" wrote:

Hi,
I'm looking at
http://windowssdk.msdn.microsoft.com/en-us/library/ms726871.aspx and
struggling to use this code sample correctly. I have a base64 encoded string
containing the key to sign a string with. I can decode the base64 key
correctly which yields a 16 byte key using some of my own code. I have
verified that against independent versions of base64 decoders on the net.

Can anybody give me some guidance why I'm getting incorrect values? The
person i'm working with has basically given me test values and results. They
match the results I see when I download a test program. He is using python's
crypto library.

my suspicion is that I need to import the key directly rather then hashing
it as in the example.



my code flow is as follows:

#define SIGNATURE_KEY_SIZE 16


string CIMPacketHandler::SignPayload(const string & string_to_sign, const
string & signature_key)
{
string rval=_T("");
string tmp = _T("");

// 2a) decode signature_key
DWORD nBufLen = signature_key.length();
BYTE bytEncryptionKey[SIGNATURE_KEY_SIZE];
Base64Coder mydecoder;

mydecoder.Decode(signature_key.c_str());
memcpy(bytEncryptionKey, mydecoder.DecodedMessage(), SIGNATURE_KEY_SIZE);

//--------------------------------------------------------------------
// Declare variables.
//
// hProv: Handle to a cryptographic service provider (CSP).
// This example retrieves the default provider for
// the PROV_RSA_FULL provider type.
// hHash: Handle to the hash object needed to create a hash.
// hKey: Handle to a symmetric key. This example creates a
// key for the RC4 algorithm.
// hHmacHash: Handle to an HMAC hash.
// pbHash: Pointer to the hash.
// dwDataLen: Length,in bytes, of the hash.
// bytEncryptionKey:Password string used to create a symmetric key.
// string_to_sign: Message string to be hashed.
// HmacInfo: Instance of an HMAC_INFO structure that contains
// information about the HMAC hash.
//
HCRYPTPROV hProv = NULL;
HCRYPTHASH hHash = NULL;
HCRYPTKEY hKey = NULL;
HCRYPTHASH hHmacHash = NULL;
PBYTE pbHash = NULL;
DWORD dwDataLen = 0;
//BYTE Data1[] = {0x70,0x61,0x73,0x73,0x77,0x6F,0x72,0x64};
//BYTE Data2[] = {0x6D,0x65,0x73,0x73,0x61,0x67,0x65};
HMAC_INFO HmacInfo;

//--------------------------------------------------------------------
// Zero the HMAC_INFO structure and use the SHA1 algorithm for
// hashing.

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

//--------------------------------------------------------------------
// Acquire a handle to the default RSA cryptographic service provider.

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());
goto ErrorExit;
}

//--------------------------------------------------------------------
// Derive a symmetric key from a hash object by performing the
// following steps:
// 1. Call CryptCreateHash to retrieve a handle to a hash object.
// 2. Call CryptHashData to add a text string (password) to the
// hash object.
// 3. Call CryptDeriveKey to create the symmetric key from the
// hashed password derived in step 2.
// You will use the key later to create an HMAC hash object.

if (!CryptCreateHash(
hProv, // handle of the CSP
CALG_SHA1, // hash algorithm to use
0, // hash key
0, // reserved
&hHash)) // address of hash object handle
{
printf("Error in CryptCreateHash 0x%08x \n",
GetLastError());
goto ErrorExit;
}

if (!CryptHashData(
hHash, // handle of the hash object
bytEncryptionKey, // password to hash
SIGNATURE_KEY_SIZE, // number of bytes of data to add
0)) // flags
{
printf("Error in CryptHashData 0x%08x \n",
GetLastError());
goto ErrorExit;
}

if (!CryptDeriveKey(
hProv, // handle of the CSP
CALG_RC4, // algorithm ID
hHash, // handle to the hash object
0, // flags
&hKey)) // address of the key handle
{
printf("Error in CryptDeriveKey 0x%08x \n",
GetLastError());
goto ErrorExit;
}

//if(!CryptImportKey(hProv, bytEncryptionKey, SIGNATURE_KEY_SIZE, NULL, 0,
&hKey))
//{
// printf("Error in CryptImportKey 0x%08x \n",
// GetLastError());
// goto ErrorExit;
//}
//--------------------------------------------------------------------
// Create an HMAC by performing the following steps:
// 1. Call CryptCreateHash to create a hash object and retrieve
// a handle to it.
// 2. Call CryptSetHashParam to set the instance of the HMAC_INFO
// structure into the hash object.
// 3. Call CryptHashData to compute a hash of the message.
// 4. Call CryptGetHashParam to retrieve the size, in bytes, of
// the hash.
// 5. Call malloc to allocate memory for the hash.
// 6. Call CryptGetHashParam again to retrieve the HMAC hash.

if (!CryptCreateHash(
hProv, // handle of the CSP.
CALG_HMAC, // HMAC hash algorithm ID
hKey, // key for the hash (see above)
0, // reserved
&hHmacHash)) // address of the hash handle
{
printf("Error in CryptCreateHash 0x%08x \n",
GetLastError());
goto ErrorExit;
}

if (!CryptSetHashParam(
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());
goto ErrorExit;
}

if (!CryptHashData(
hHmacHash, // handle of the HMAC hash object
(BYTE*)string_to_sign.c_str(), // message to hash
string_to_sign.length(), // number of bytes of data to add
0)) // flags
{
printf("Error in CryptHashData 0x%08x \n",
GetLastError());
goto ErrorExit;
}

//--------------------------------------------------------------------
// Call CryptGetHashParam twice. Call it the first time to retrieve
// the size, in bytes, of the hash. Allocate memory. Then call
// CryptGetHashParam again to retrieve the hash value.

if (!CryptGetHashParam(
hHmacHash, // handle of the HMAC hash object
HP_HASHVAL, // query on the hash value
NULL, // filled on second call
&dwDataLen, // length, in bytes,of the hash
0))
{
printf("Error in CryptGetHashParam 0x%08x \n",
GetLastError());
goto ErrorExit;
}

pbHash = (BYTE*)malloc(dwDataLen);
if(NULL == pbHash)
{
printf("unable to allocate memory\n");
goto ErrorExit;
}

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());
goto ErrorExit;
}

// encode the hash to base64

//printf("The hash is: ");
for(DWORD i = 0 ; i < dwDataLen ; i++)
{
tmp.Format(_T("%2x"), pbHash[i]);
rval += tmp;
}
//printf("%2x ",pbHash[i]);
//}
//printf("\n");

// Free resources.
ErrorExit:
if(hHmacHash)
CryptDestroyHash(hHmacHash);
if(hKey)
CryptDestroyKey(hKey);
if(hHash)
CryptDestroyHash(hHash);
if(hProv)
CryptReleaseContext(hProv, 0);
if(pbHash)
free(pbHash);
return rval;

}


.



Relevant Pages

  • Creating an HMAC for a string using a base64 encoded key
    ... I have a base64 encoded string ... containing the key to sign a string with. ... Length,in bytes, of the hash. ... goto ErrorExit; ...
    (microsoft.public.platformsdk.security)
  • [Full-disclosure] Advisory 06/2005: Geeklog SQL Injection Vulnerability
    ... Hash: SHA1 ... Vendor Status: Vendor has released an updated version ... "Geeklog is a weblog powered by PHP and MySQL. ... With similiar strings it is possible to retrieve the complete ...
    (Full-Disclosure)
  • Re: virtue of salted passwords
    ... Password hashes can be retrieved in any number of ... > hash would also retrieve the salt at the same time. ... Any ideas as to how to make it harder to retrieve salts for web ...
    (alt.computer.security)
  • Re: Hashes are good, but not good enough.
    ... more than one element while for a DAWG or tree it will be one RAM access ... In a hash without collisions there is ... the time it takes to retrieve this one element is a constant because ... it is retrieved by direct access instead of going through a chain of ...
    (comp.lang.perl.misc)
  • Re: How much data that bound form fetch at a time ?
    ... > Hash: SHA1 ... > The best way to reduce traffic is to only retrieve one record at a time. ... > Create a Search form that allows the user to create the criteria that ...
    (microsoft.public.access.adp.sqlserver)