HMAC implementation based on OPENSSL, Crypto API(CSP) and third party algorithm library

Platform: android native, windows mobile, Symbian

1.      HMAC introduction

You may regard it as a Hash algorithm with a secret key. The output of HMAC is based on the Hash algorithm.

HMAC http://tools.ietf.org/html/rfc2104

HMAC 256 http://tools.ietf.org/html/rfc4231

 

2.      Implementation based on OPENSSL

The OPENSSL provide an API that encapsulates the HMAC calculation, you only need to choose a Hash algorithm. Sample code:

      const EVP_MD *mdsha = EVP_sha();

      HMAC(mdsha, pKey->bytes, pKey->length,

            pPlain->bytes, pPlain->length,

            pHmac->bytes, &iOutLen);

 

3.      Implementation based on Crypto API(CSP)

a.      The first question is how to import a known key into the key handle.

The Microsoft CSP provides many ways to generated or derive a session key, but never provides as API that with a parameter to pass a secrete key. It seems that the Microsoft does not like the session key (symmetric key) being exposed outside the key container. In terms of security, it is a good solution.

We need a CRYPT_DATA_BLOB to import secrete key into a HMAC key handle.

Here we need to pay attention to the length of the HMAC key. According to the HMAC specification the length of HMAC key is not fixed. So we need to choose a encryption algorithm that has the same key length as your HMAC key length. I recommend for 5-16 use RC4.

Sample code

      // we prepare the HMAC key handle here

      unsigned char pKeyData[128] = {0};

      unsigned int keyDataSize = 32;

      unsigned char messageData[128] = {0};

      unsigned int messageDataSize = 40;

 

      strcpy((char *)pKeyData, "12345678901234567890123456789012" );

      strncpy((char *)messageData, "1234567890123456789012345678901234567890" , messageDataSize);

 

      typedef struct _keyBlob{

            BLOBHEADER hdr;

            DWORD cbKeySize;

            BYTE rgbKeyData [];

      } keyBlob;

 

      BYTE bKeyBuf[1024] = {0};

      keyBlob *pBlob = NULL;

      int iBlobLen = 0;

      pBlob = (keyBlob *)bKeyBuf;

 

      pBlob->hdr.bType = PLAINTEXTKEYBLOB;

      pBlob->hdr.aiKeyAlg = CALG_AES_256; // we need a 32 key length alg

      pBlob->hdr.bVersion = 0x02;

      pBlob->cbKeySize = keyDataSize;

      memcpy(pBlob->rgbKeyData, pKeyData, keyDataSize);

      iBlobLen = sizeof (BLOBHEADER) + sizeof (DWORD) + keyDataSize;

      if (!CryptImportKey(

            hProv,   // handle of the CSP

            bKeyBuf, // key container name

            iBlobLen, //sizeof(HmacKeyBlob),

            NULL,

            0,

            &hKey))

      {

         printf(" Error in AcquireContext 0x%08x /n" ,

                    GetLastError());

         goto ErrorExit;

      }

b.      Get hash value

Sample code

      HMAC_INFO   HmacInfo;

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

      ZeroMemory(&HmacInfo, sizeof (HmacInfo));

      // choose a Hash alg

      HmacInfo.HashAlgid = CALG_SHA_256;

 

      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

            messageData,                    // message to hash

            messageDataSize,            // 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;

      }

For more info:

http://msdn.microsoft.com/en-us/library/aa382383%28v=vs.85%29.aspx

http://msdn.microsoft.com/en-us/library/aa387453%28v=vs.85%29.aspx

http://msdn.microsoft.com/en-us/library/aa380207%28v=vs.85%29.aspx

 

4.      Implementation based on third party algorithm library

According to the specification rfc2104, we may implement the HMAC calculation, what we need is a third party Hash algorithm.

Sample code

        unsigned char k_ipad[65] = {0};    /* inner padding - key XORd with ipad */

      unsigned char k_opad[97] = {0};    /* outer padding - key XORd with opad */

      const int iPadLen = 64;

      int i = 0;

      unsigned char out1[1024] = {0};

      unsigned char out2[1024] = {0};

 

      unsigned int iOutLen = 0;

      sha256_ctx  cx[1];      // for multiply clock of first round hash

 

      memcpy( k_ipad, pKey->bytes, pKey->length);

      memcpy( k_opad, pKey->bytes, pKey->length);

 

      for (i = 0; i < iPadLen; i++) {

                  k_ipad[i] ^= 0x36;

                  k_opad[i] ^= 0x5c;

      }

 

      // first hash

      sha256_begin(cx);

      sha256_hash(k_ipad, iPadLen, cx);

      sha256_hash(pPlain->bytes, pPlain->length, cx);

      sha256_end(out1, cx);

 

      // second hash

      memcpy(k_opad + iPadLen, out1, MAC_LEN);

 

      sha256(pHmac->bytes, k_opad, iPadLen + MAC_LEN);

      pHmac->length = MAC_LEN;

5.      Some concern on the majority mobile platform.

a.      For the android you may use the crypto package. But for the sake of security I recommend to implement HMAC with third party hash library at the android native side.

b.      For the windows mobile, you may use the CSP directly, and use the derived HMAC key instead of the imported HMAC key.

c.       The Symbian provides a simplified Openssl API, you may use it directly.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值