一、简介
HMAC是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code)。 HMAC运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。也就是说HMAC通过将哈希算法(SHA1, MD5)与密钥进行计算生成摘要。
HMAC与哈希算法一起使用。
二、实现原理
HMAC的计算公式为:
HMAC(K,M)=H(K⊕opad∣H(K⊕ipad∣M))
运算步骤:
(1)检查密钥K的长度。如果K的长度大于B则先使用摘要算法计算出一个长度为L的新密钥。如果K的长度小于B,则在其后面追加0来使其长度达到B。
(2)将上一步生成的B字长的密钥字符串与ipad做异或运算,得到比特序列ipadkey。
(3)将ipadkey附加在消息M的开头;
(4)使用哈希函数H计算第3步中生成的数据流的信息摘要值。
(5) 将第1步生成的B字长密钥字符串与opad做异或运算,得到opadkey。
(6)再将第4步得到的结果填充到opadkey之后。
(7)使用哈希函数H计算第6步中生成的数据流的信息摘要值,输出结果就是最终的HMAC值。
三、Hmac代码实现
对hmac-sha256 加密使用示例
- swift系统代码
public func hmacsha256(_ key: String) -> String {
let cData = self.cString(using: .utf8) ?? []
let cKey = key.cString(using: .utf8) ?? []
var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), cKey, key.count, cData, self.count, &digest)
let outData = Data(bytes: digest, count: Int(CC_SHA256_DIGEST_LENGTH))
let hash = outData.hexString()
return hash
}
- C语言代码示例
#define B SHA256_CBLOCK
#define L (SHA256_DIGEST_LENGTH)
#define K (SHA256_DIGEST_LENGTH * 2)
#define I_PAD 0x36
#define O_PAD 0x5C
/*
* HMAC(H, K) == H(K ^ opad, H(K ^ ipad, text))
*
* H: Hash function (sha256)
* K: Secret key
* B: Block byte length
* L: Byte length of hash function output
*
* https://tools.ietf.org/html/rfc2104
*/
void hmac_sha256(const unsigned char *key, int key_len, const unsigned char *d, size_t n,
unsigned char *md, unsigned int *md_len) {
assert(key);
assert(d);
assert(md);
if (*md_len < SHA256_DIGEST_LENGTH){
return;
}
SHA256_CTX shaCtx;
uint8_t kh[SHA256_DIGEST_LENGTH];
/*
* If the key length is bigger than the buffer size B, apply the hash
* function to it first and use the result instead.
*/
if (key_len > B) {
SHA256_Init(&shaCtx);
SHA256_Update(&shaCtx, key, key_len);
SHA256_Final(kh, &shaCtx);
key_len = SHA256_DIGEST_LENGTH;
key = kh;
}
/*
* (1) append zeros to the end of K to create a B byte string
* (e.g., if K is of length 20 bytes and B=64, then K will be
* appended with 44 zero bytes 0x00)
* (2) XOR (bitwise exclusive-OR) the B byte string computed in step
* (1) with ipad
*/
uint8_t kx[B];
for (size_t i = 0; i < key_len; i++) kx[i] = I_PAD ^ key[i];
for (size_t i = key_len; i < B; i++) kx[i] = I_PAD ^ 0;
/*
* (3) append the stream of data 'text' to the B byte string resulting
* from step (2)
* (4) apply H to the stream generated in step (3)
*/
SHA256_Init(&shaCtx);
SHA256_Update(&shaCtx, kx, B);
SHA256_Update(&shaCtx, d, n);
SHA256_Final(md, &shaCtx);
/*
* (5) XOR (bitwise exclusive-OR) the B byte string computed in
* step (1) with opad
*
* NOTE: The "kx" variable is reused.
*/
for (size_t i = 0; i < key_len; i++) kx[i] = O_PAD ^ key[i];
for (size_t i = key_len; i < B; i++) kx[i] = O_PAD ^ 0;
/*
* (6) append the H result from step (4) to the B byte string
* resulting from step (5)
* (7) apply H to the stream generated in step (6) and output
* the result
*/
SHA256_Init(&shaCtx);
SHA256_Update(&shaCtx, kx, B);
SHA256_Update(&shaCtx, md, SHA256_DIGEST_LENGTH);
SHA256_Final(md, &shaCtx);
*md_len = SHA256_DIGEST_LENGTH;
}