HMAC (基于哈希的报文认证码) 算法中的密钥填充与哈希调用顺序
字数 2473 2025-12-12 18:35:45
HMAC (基于哈希的报文认证码) 算法中的密钥填充与哈希调用顺序
题目描述
HMAC 是一种基于加密哈希函数和密钥的报文认证码算法,用于同时验证数据完整性和真实性。本题将详细剖析 HMAC 算法的核心构造过程,特别聚焦于其标准中规定的密钥预处理步骤(填充、与常数的异或操作)以及两次哈希调用的具体顺序与原因,并解释为何这样的设计能提升安全性。
解题过程
我们将循序渐进地解析 HMAC 的计算过程,其通用公式为:
HMAC(K, m) = H( (K ⊕ opad) || H( (K ⊕ ipad) || m) )
其中:
H是所采用的哈希函数(如 SHA-256)。K是原始密钥。m是待认证的消息。||表示连接操作。⊕表示异或操作。ipad和opad是预定义的常量。
整个流程可分为五个关键步骤。
步骤一:密钥准备与规范化
此步骤确保密钥 K 的长度与哈希函数的输入分组长度 B(字节)一致。
- 输入检查:原始密钥
K可以为任意长度。但若长度超过哈希函数的分组长度B,则先用哈希函数H对其进行哈希,将结果作为新的密钥。即:如果len(K) > B,则K ← H(K)。此时K的长度等于哈希输出的长度L(例如 SHA-256 的 L=32 字节)。 - 填充到分组长度:如果密钥长度小于
B,则在其右侧填充足够数量的零字节 (0x00),使其总长度恰好等于B字节。我们记这个填充后的密钥为K0。
目标:无论原始密钥长短,经过此步后,我们都得到一个长度精确为B字节的密钥K0。这为后续与常量进行按字节的异或操作奠定了基础。
步骤二:生成内部填充密钥
此步骤创建一个用于处理消息内部的密钥。
- 定义内填充常量:
ipad是一个长度为B字节的常量,其每个字节的值均为0x36。 - 按字节异或:计算
S_i = K0 ⊕ ipad。由于ipad是固定值,这个操作相当于将K0的每个字节都与0x36进行异或,产生一个长度同样为B字节的串S_i。
作用:这个操作“扰乱”了原始密钥,为内部哈希计算准备了一个派生密钥。即使攻击者知道S_i,由于异或的不可逆性(不知道K0),他也难以恢复出原始密钥。
步骤三:计算内部哈希值
此步骤将消息与 S_i 结合,进行第一次哈希运算。
- 构造内部输入:将上一步得到的
S_i与原始消息m直接连接起来,形成一个新的字节串:S_i || m。 - 应用哈希函数:对这个连接后的字节串计算哈希值:
H_in = H(S_i || m)。H_in的长度是L字节。
作用:H_in本质上是“用密钥处理过的消息摘要”。消息的完整性首先在这里得到保护。即使攻击者篡改了消息m,在不知道K0的情况下,也无法伪造出正确的H_in。
步骤四:生成外部填充密钥
此步骤创建一个用于处理内部哈希结果的密钥。
- 定义外填充常量:
opad是一个长度为B字节的常量,其每个字节的值均为0x5c。 - 按字节异或:计算
S_o = K0 ⊕ opad。这产生另一个长度为B字节的派生密钥S_o。注意,opad(0x5c) 与ipad(0x36) 值不同,因此S_o与S_i也不同。
作用:S_o作为外部哈希的密钥,确保了内外两层哈希操作使用了不同的、但都源于K0的密钥材料。这增加了算法的强度。
步骤五:计算最终 HMAC 值(外部哈希)
此步骤输出最终的认证标签。
- 构造外部输入:将
S_o与上一步得到的内哈希值H_in连接起来:S_o || H_in。 - 应用哈希函数:对这个连接后的字节串计算最终的哈希值:
Tag = H(S_o || H_in)。这个Tag就是 HMAC 的输出,即消息认证码。
最终输出:Tag的长度同样是L字节。验证方在收到消息和Tag后,使用相同的密钥K和算法对消息重新计算 HMAC,如果结果与收到的Tag完全一致,则验证通过。
核心设计思想与安全性
- 密钥预处理(
ipad/opad异或):这保证了即使攻击者获得了S_i或S_o中的某一个,由于他不知道原始密钥K0且无法从异或结果中反推出K0,也无法计算出另一个派生密钥。同时,0x36和0x5c的选取使S_i和S_o有很高的汉明距离,进一步分化了内外路径。 - 嵌套哈希结构:
H( (K ⊕ opad) || H( (K ⊕ ipad) || m) )的顺序至关重要。内部哈希H( (K ⊕ ipad) || m)首先将任意长的消息压缩成固定长度的摘要。外部哈希的输入是(K ⊕ opad)与该摘要的连接。这种结构带来了两个关键安全优势:- 长度扩展攻击防护:许多哈希函数(如 MD5, SHA-1, SHA-256)存在长度扩展攻击漏洞。即知道
H(message1)和message1的长度(但不知内容),可以构造出H(message1 || padding || message2)。HMAC 的外层哈希将内部摘要作为输入的一部分,攻击者无法在不知道外层密钥S_o的情况下,对最终输出进行有效的长度扩展。 - 密钥与消息的强绑定:最终标签同时依赖于密钥(通过
S_o)和整个消息的完整摘要(H_in)。任何对消息或密钥的微小改动,都会以高概率导致完全不同的最终输出。
- 长度扩展攻击防护:许多哈希函数(如 MD5, SHA-1, SHA-256)存在长度扩展攻击漏洞。即知道
至此,我们完整剖析了 HMAC 算法的计算步骤,并重点解释了其密钥填充与特定哈希调用顺序背后的安全设计逻辑。