Fork me on GitHub

【加解密】HMac基本介绍

基本介绍

HMAC(散列消息身份验证码: Hashed Message Authentication Code)

它不是散列函数,而是采用散列函数(MD5 or 或SHA)与共享密钥一起使用的消息身份验证机制。

详细见 RFC 2104

 

使用场景

  • 服务端生成key,传给客户端;
  • 客户端使用key将帐号和密码做HMAC,生成一串散列值,传给服务端;
  • 服务端使用key和数据库中用户和密码做HMAC计算散列值,比对来自客户端的散列值。

 

按照散列函数的不同,可以有如下实现。

Hmac_MD5,Hmac_sha1,Hmac_sha224,Hmac_sha256,Hmac_sha384,Hmac_sha512。

Hmac_MD5:

/**
 * MD5(Key XOR opad, MD5(Key XOR ipad, text))
 *
 * where K is an n byte key
 * ipad is the byte 0x36 repeated 64 times
 * opad is the byte 0x5c repeated 64 times
 * and text is the data being protected(maybe user or password).
 */

    if(key_len <= KEY_IOPAD_SIZE)
    {
        memcpy( k_ipad, key, key_len);
        memcpy( k_opad, key, key_len);
    }
    else
    {
        MD5Calc(key, key_len, k_ipad);
        memcpy(k_opad, k_ipad, KEY_IOPAD_SIZE);
    }

    /* XOR key with ipad and opad values */
    for (i = 0; i < KEY_IOPAD_SIZE; i++) {
        k_ipad[i] ^= 0x36;
        k_opad[i] ^= 0x5c;
    }
    // perform inner MD5
    MD5Init(&context);                    /* init context for 1st pass */
    MD5Update(&context, k_ipad, KEY_IOPAD_SIZE);      /* start with inner pad */
    MD5Update(&context, (unsigned char*)text, text_len); /* then text of datagram */
    MD5Final(hmac, &context);             /* finish up 1st pass */

    // perform outer MD5
    MD5Init(&context);                   /* init context for 2nd pass */
    MD5Update(&context, k_opad, KEY_IOPAD_SIZE);     /* start with outer pad */
    MD5Update(&context, hmac, MD5_DIGEST_SIZE);     /* then results of 1st hash */
    MD5Final(hmac, &context);          /* finish up 2nd pass */

Hmac_sha1:

    /**
     * SHA(Key XOR opad, SHA(Key XOR ipad, text))
     *
     * where K is an n byte key
     * ipad is the byte 0x36 repeated 64 times
     * opad is the byte 0x5c repeated 64 times
     * and text is the data being protected(maybe user or password).
     */

    if(key_len <= KEY_IOPAD_SIZE)
    {
        memcpy( k_ipad, key, key_len);
        memcpy( k_opad, key, key_len);
    }
    else
    {
        SHA1Calc(key, key_len, k_ipad);
        memcpy(k_opad, k_ipad, KEY_IOPAD_SIZE);
    }
    /* XOR key with ipad and opad values */
    for (i = 0; i < KEY_IOPAD_SIZE; i++) {
        k_ipad[i] ^= 0x36;
        k_opad[i] ^= 0x5c;
    }

    // perform inner SHA
    SHA_Init(&context);                    /* init context for 1st pass */
    SHA_Bytes(&context, k_ipad, KEY_IOPAD_SIZE);      /* start with inner pad */
    SHA_Bytes(&context, text, text_len);   /* then text of datagram */
    SHA_Final(&context, hmac);             /* finish up 1st pass */

    // perform outer SHA
    SHA_Init(&context);                   /* init context for 2nd pass */
    SHA_Bytes(&context, k_opad, KEY_IOPAD_SIZE);     /* start with outer pad */
    SHA_Bytes(&context, hmac, SHA1_DIGEST_SIZE);     /* then results of 1st hash */
    SHA_Final(&context, hmac);          /* finish up 2nd pass */

Hmac_sha224,mac_sha256 和 Hmac_sh啊类似,把SHA换成SHA224或SHA256即可,注意 ipad和opad的长度为64.

Hmac_sha384:Hmac_sha512和Hmac_sha384类似,把SHA384换成SHA512即可,注意 ipad和opad的长度为128.

    /**
     * SHA384(Key XOR opad, SHA(Key XOR ipad, text))
     *
     * where K is an n byte key
     * ipad is the byte 0x36 repeated 128 times
     * opad is the byte 0x5c repeated 128 times
     * and text is the data being protected(maybe user or password).
     */

    if(key_len <= KEY_IOPAD_SIZE)
    {
        memcpy( k_ipad, key, key_len);
        memcpy( k_opad, key, key_len);
    }
    else
    {
        SHA384_Simple(key, key_len, k_ipad);
        memcpy(k_opad, k_ipad, KEY_IOPAD_SIZE);
    }
    /* XOR key with ipad and opad values */
    for (i = 0; i < KEY_IOPAD_SIZE128; i++) {
        k_ipad[i] ^= 0x36;
        k_opad[i] ^= 0x5c;
    }

    // perform inner SHA384
    SHA384_Init(&context);                    /* init context for 1st pass */
    SHA384_Bytes(&context, k_ipad, KEY_IOPAD_SIZE128);      /* start with inner pad */
    SHA384_Bytes(&context, text, text_len); /* then text of datagram */
    SHA384_Final(&context, hmac);             /* finish up 1st pass */

    // perform outer SHA384
    SHA384_Init(&context);                   /* init context for 2nd pass */
    SHA384_Bytes(&context, k_opad, KEY_IOPAD_SIZE128);     /* start with outer pad */
    SHA384_Bytes(&context, hmac, SHA384_DIGEST_SIZE);     /* then results of 1st hash */
    SHA384_Final(&context, hmac);          /* finish up 2nd pass */

  

C implement at github: https://github.com/mygityf/cipher/blob/master/cipher/hmac.c

Done.

posted @ 2016-03-25 17:12  Mr.YF  阅读(9813)  评论(0编辑  收藏  举报