HMAC(基于哈希的消息认证码)算法
字数 2202 2025-10-28 00:29:09
HMAC(基于哈希的消息认证码)算法
题目描述:HMAC是一种使用密码散列函数(如SHA-256或MD5)结合一个秘密密钥来进行消息认证的机制。它不仅能验证数据的完整性,还能验证消息的真实性(即确认消息确实来自声称的发送方)。你的任务是理解HMAC的构造和工作原理,特别是它如何通过嵌套哈希操作来提供安全性。
解题过程:
-
核心概念与目标
- 问题:在网络传输或存储中,我们如何确保一段收到的消息(例如,一个API请求或软件更新包)在传输过程中没有被篡改(完整性),并且确实来自合法的发送方(真实性)?
- 简单思路:发送方和接收方共享一个秘密密钥。发送方用这个密钥对消息计算出一个“标签”(即MAC),并随消息一起发送。接收方用同样的密钥对收到的消息重新计算标签,并与收到的标签对比。如果一致,则验证通过。
- 直接哈希的缺陷:一个朴素的想法是
MAC = Hash(SecretKey + Message)。但这存在安全隐患,例如长度扩展攻击(攻击者可以在不知道密钥的情况下,在哈希值后附加新的数据并计算出有效的新MAC)。 - HMAC的解决方案:HMAC通过一种更复杂的、嵌套哈希的结构来避免这类攻击,其安全性可以归约到底层哈希函数的抗碰撞性等属性上。
-
HMAC的算法结构
HMAC的定义非常精妙,它使用两个哈希调用。其计算公式为:
HMAC(K, m) = H( (K' ⊕ opad) || H( (K' ⊕ ipad) || m ) )
这个公式看起来很复杂,我们将它分解成清晰的步骤。 -
步骤一:密钥预处理
- 输入:一个秘密密钥
K和选定的哈希函数H(例如,SHA-256的块大小是64字节)。 - 目标:将密钥
K调整为一个与哈希函数块长度一致的新密钥K'。 - 过程:
a. 如果密钥K的长度等于哈希函数的块长度(对于SHA-256是64字节),则直接使用K作为K'。
b. 如果密钥K的长度大于块长度,则先对K进行哈希H(K),然后用哈希结果(长度较短)后面补零,直到达到块长度,得到K'。
c. 如果密钥K的长度小于块长度,则在K的后面补零(字节0x00),直到其长度正好等于块长度,得到K'。 - 目的:确保后续的异或操作能够正确进行,并且密钥以固定长度参与运算。
- 输入:一个秘密密钥
-
步骤二:生成内部填充键和外部填充键
- 定义两个固定的常量:
ipad(inner pad):内部填充,是字节0x36重复block_size次。例如,对于64字节的块,ipad是64个0x36。opad(outer pad):外部填充,是字节0x5C重复block_size次。例如,对于64字节的块,opad是64个0x5C。
- 计算:
inner_key = K' ⊕ ipad(将预处理后的密钥K'的每一个字节与ipad的对应字节进行异或操作)。outer_key = K' ⊕ opad(将预处理后的密钥K'的每一个字节与opad的对应字节进行异或操作)。
- 效果:
ipad和opad是两个不同的、固定的值,通过异或操作,它们有效地将密钥K'“随机化”成了两个不同的、与密钥相关的值。
- 定义两个固定的常量:
-
步骤三:计算内部哈希
- 构造内部消息:将上一步得到的
inner_key与原始消息m拼接起来。即inner_message = inner_key || m。 - 计算内部哈希:对拼接后的内部消息应用哈希函数
H。得到inner_hash = H(inner_message)。 - 目的:这是第一次哈希。密钥的“内填充”版本与消息混合,确保了消息的完整性。即使攻击者篡改了消息,
inner_hash也会改变。
- 构造内部消息:将上一步得到的
-
步骤四:计算最终HMAC值
- 构造外部消息:将步骤二得到的
outer_key与步骤三得到的inner_hash拼接起来。即outer_message = outer_key || inner_hash。 - 计算最终哈希:对外部消息应用哈希函数
H。得到final_hash = H(outer_message)。这个final_hash就是最终的HMAC值。 - 目的:这是第二次哈希(嵌套哈希)。它确保了认证标签的真实性。因为攻击者不知道密钥
K,他无法构造出正确的outer_key,因此也无法计算出正确的最终HMAC值。这一步也有效地防御了长度扩展攻击,因为攻击者无法从inner_hash反推出(K' ⊕ ipad) || m的具体内容。
- 构造外部消息:将步骤二得到的
总结与验证过程:
发送方按照上述1-6步计算出消息 m 的HMAC值,然后将 (m, HMAC值) 发送给接收方。
接收方验证过程如下:
- 使用与发送方共享的同一个秘密密钥
K。 - 对收到的消息
m重新执行上述1-6步,计算出一个本地的HMAC值。 - 将计算出的本地HMAC值与接收到的HMAC值进行恒定时间比较(防止时序攻击)。
- 如果两者完全相同,则验证成功(消息完整且真实);否则,验证失败(消息可能被篡改或来源不可信)。