Note

  1. 共享密钥建议选择大于等于杂凑值的长度
  2. 根据需要使用的hash算法确定块大小,下面过程依赖SM3,所以都为64字节

定义

      基于散列的消息认证码。利用哈希算法以及结合共享密钥通过特定的计算方式生成消息认证码;hash算法用以校验数据的完整性、防纂改,共享密钥可以保证数据的真实性、来源

原理

a 计算公式 HMAC(H,key,M) = H((k xor opad) || H((k xor ipad) || M))
  
  H:hash算法

  key:共享密钥

  M:消息

  ipad:内部填充 重复0x36

  opad:外部填充 重复0x5c
  
  k: key经密钥扩展的结果

b key密钥扩展到k
  
  key长度小于等于64字节时,在key的右侧补零到64字节
  
  key长度大于64字节时,计算H(key),并在其右侧补零到64字节

c k 异或 重复64字节的0x36,异或结果的后面拼接消息M,对拼接结果进行哈希运算

d k 异或 重复64字节的0x5c,异或结果的后面拼接上步哈希运算的结果,对拼接结果进行哈希运算得到mac

伪代码

int Hmac(hashAlg, key, M) {
  int blockSize = 64;
  char k[blockSize] = {0};
  std::string digest;
  char k2[blockSize] = {0};

  // key密钥扩展k
  if (key.length() <= blockSize) {
    memcpy(k, key.c_str(), key.length());
  } else {
    Hash(key, hashAlg, digest);
    memcpy(k, digest.c_str(), digest.length());
  }

  // k异或内部填充0x36
  for (int i = 0; i < blockSize; i++) {
    k2[i] = k[i] ^ 0x36;
  }

  // 异或结果拼接M
  auto tmpData = std::make_unique<uint8_t[]>(blockSize + M.length());
  memcpy(tmpData.get(), k2, blockSize);
  memcpy(tmpData.get() + blockSize, M.c_str(), M.length());

  // 拼接结果哈希运算
  Hash(tmpData , hashAlg, digest);

  // k异或外部填充0x5c
  for (int i = 0; i < blockSize; i++) {
    k[i] ^= 0x5c;
  }

  // 异或结果拼接哈希结果
  auto tmpData2 = std::make_unique<uint8_t[]>(blockSize + digest.length());
  memcpy(tmpData2.get(), k, blockSize);
  memcpy(tmpData2.get() + blockSize, digest.c_str(), digest.length());

  // 拼接结果哈希运算,最后一次哈希结果即为mac值
  Hash(tmpData2, hashAlg, digest);
 
  return 0;
}
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐