hmacmd5算法
1. 简介
- HMAC-MD5算法是一种基于MD5散列函数和密钥的消息认证码算法,它通过结合密钥和消息内容来生成一个长度为128位的哈希值,用于验证消息的完整性和身份;
- 与普通的 MD5 哈希算法不同,HMAC-MD5 在计算过程中使用了一个密钥,使得攻击者无法仅凭猜测数据本身来伪造消息的认证码;
- 如果密钥太长,它需要被压缩;如果太短,它需要被填充到特定长度;
- 总结就是:两次加盐,两次哈希;
2. 算法流程
输入:
- 消息(Message):需要进行验证的消息数据;
- 密钥(Key):用于生成消息认证码的密钥;
输出:
- HMAC-MD5值:一个128位的签名值(32个十六进制位的数据),用于验证消息的完整性和真实性;
- 步骤详述:
步骤 1:密钥准备
- 如果密钥长度大于MD5的块大小(64字节),则先对密钥执行一次MD5哈希运算,生成一个16字节(128位)的密钥摘要(K'),然后再进行填充;
- 如果密钥长度小于64字节,则用零字节(0x00)填充密钥至64字节;
- 如果密钥长度正好是64字节,则直接使用密钥;
步骤2:异或0x36,也叫ipad
- 逐字节异或得到扩展密钥1;0x36的十进制是54;这里的ipad不是一个数据,应该是与key相同长度的数组;
步骤3:异或0x5c,也叫opad
- 逐字节异或得到扩展密钥2;0x54的十进制是92;
步骤5:第一次加盐
- 扩展密钥1与明文拼接;
步骤6:第一次哈希
- 加盐的结果进行哈希;
步骤7:第二次加盐
- 扩展密钥2与第一次哈希的结果拼接;
步骤8:第二次哈希
- 将上述拼接的结果进行哈希;
总结:
- HMAC(K, M) = H((K' ⊕ opad) || H((K' ⊕ ipad) || M))
- K:密钥
- M:明文
- H:哈希函数
- K':扩展密钥
- ⊕:逐字节异或
- opad:0x5c
- ipad:0x36
- || :拼接
- 算法流程简述如上,以一个简单的示例来看整体的流程;
3. 完整示例
- 以sana为明文,xiayutian为key,进行整个流程的介绍;
- 参考公式: H((K' ⊕ opad) || H((K' ⊕ ipad) || M))
3.1 密钥扩展
- 首先进行密钥扩展,xiayutian的十六进制表示为:
78 69 61 79 75 74 69 61 6e- 长度不够512个比特位,所以需要进行填充,填充后的结果如下:
78 69 61 79 75 74 69 61 6E 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 一共是55个零字节,加上原有的数据就是64个字节;
3.2 与0x36异或
- 随后密钥与0x36(ipad)逐字节异或,这里的0x36不是单独的一个数据,而是64个,毕竟要一一对应;
- 得到异或的结果,这就对应着第一个扩展密钥,也叫扩展密钥1;
4E 5F 57 4F 43 42 5F 57 58 36 36 36 36 36 36 36
36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36
36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36
36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 3.3 第一次加盐
- 然后拼接明文,将明文放在最后,这就是第一次加盐;
- 明文sana的十六进制:73 61 6e 61
拼接后数据(68字节):
4E 5F 57 4F 43 42 5F 57 58 36 36 36 36 36 36 36
36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36
36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36
36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36
73 61 6E 61 3.4 第一次哈希
- 将这个结果做一个md5加密,这就是第一次哈希;
fa23080448b15547fe4b2a19226cf9b73.5 与0x5c异或
- 获取扩展密钥2,也就是密钥与opad(0x5c)逐字节异或;
24 35 3D 25 29 28 35 3D 32 5C 5C 5C 5C 5C 5C 5C
5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C
5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C
5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 3.6 第二次加盐
- 将扩展密钥2与第一步哈希的结果拼接起来,这就是第二次加盐;
24 35 3D 25 29 28 35 3D 32 5C 5C 5C 5C 5C 5C 5C
5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C
5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C
5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C
fa 23 08 04 48 b1 55 47 fe 4b 2a 19 22 6c f9 b7 3.7 第二次哈希
- 将第二次加盐的结果进行哈希,这就是第二次哈希;
3d38802f21ef45a3eb05524f504810bc- 做一下结果对比;

- 结果是没问题的,主要的流程就是两次加盐两次哈希;
4. 总结
- 首先是流程:HMAC(K, M) = H((K' ⊕ opad) || H((K' ⊕ ipad) || M))
- 两次加盐、两次哈希;也有可能是三次哈希,密钥如果超过64字节则需要先哈希再填充;
- 算法的特征就是0x36和0x5c,也有可能是十进制的形式,54和92;
- 魔改的点一般在于载体哈希函数,并不去魔改两次加盐两次哈希这个流程,但也说不好;
5. 代码实现
import hmac
import hashlib
def hmac_md5(key, message):
# 将 key 和 message 转换为字节类型
key = bytes(key, 'utf-8')
message = bytes(message, 'utf-8')
# 计算 HMAC-MD5
hmac_md5_hash = hmac.new(key, message, hashlib.md5).hexdigest()
return hmac_md5_hash
# 示例使用
key = "xiayutian"
message = "sana"
result = hmac_md5(key, message)
print("HMAC-MD5:", result)
# 3d38802f21ef45a3eb05524f504810bc