【加解密】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.