HMAC(基于哈希的报文认证码)算法中的密钥填充与哈希调用顺序
1. 题目描述
HMAC(Hash-based Message Authentication Code)是一种利用加密哈希函数(如SHA-256、MD5)和秘密密钥,为消息生成认证码的算法。它广泛应用于网络协议(如TLS、IPsec)和数据完整性验证。本题要求详细解释HMAC算法中密钥填充(Key Padding) 和 两次哈希调用顺序 的设计原理与具体步骤,说明其如何确保安全性和防止长度扩展攻击。
2. HMAC算法的基本结构
HMAC算法可定义为:
\[\text{HMAC}(K, m) = H\left( (K \oplus opad) \;||\; H\left( (K \oplus ipad) \;||\; m \right) \right) \]
其中:
- \(H\)是哈希函数(如SHA-256)。
- \(K\)是秘密密钥。
- \(m\)是输入消息。
- \(ipad\)(inner pad)和\(opad\)(outer pad)是两个固定的常量。
- \(||\)表示拼接操作。
- \(\oplus\)表示异或运算。
核心思想:通过两层哈希调用,将密钥与消息混合,确保即使哈希函数本身存在弱点(如长度扩展攻击),HMAC仍能保持安全性。
3. 密钥填充(Key Padding)步骤
哈希函数(如SHA-256)的输入是固定长度的分组。如果密钥\(K\)的长度不符合哈希函数的输入块大小,就需要进行填充。
步骤1:确定密钥长度与块大小
- 设哈希函数\(H\)的输入块大小为\(B\)字节(例如SHA-256的\(B=64\)字节)。
- 如果密钥\(K\)的长度大于\(B\)字节,则先用\(H\)对\(K\)进行哈希,将哈希结果作为新密钥(此时长度等于哈希输出长度,如SHA-256为32字节),然后继续后续处理。
- 如果密钥\(K\)的长度小于\(B\)字节,则在末尾填充零字节(0x00),使其长度变为\(B\)字节。
示例:使用SHA-256(\(B=64\)字节):
- 若密钥\(K\)为20字节,则填充44个0x00,得到64字节的\(K'\)。
- 若密钥\(K\)为80字节(>64),则先计算\(K_{\text{hash}} = \text{SHA-256}(K)\)(32字节),再填充32个0x00,得到64字节的\(K'\)。
目的:确保所有情况下,用于异或操作的密钥都是\(B\)字节,与哈希函数的分块对齐。
4. 两次哈希调用的顺序与细节
设填充后的密钥为\(K'\)(长度为\(B\)字节)。定义两个固定常量:
- \(ipad\) = 字节0x36重复\(B\)次。
- \(opad\) = 字节0x5C重复\(B\)次。
步骤2:生成内层哈希的输入
计算:
\[S_i = K' \oplus ipad \]
即,将\(K'\)的每个字节与0x36异或。然后,将\(S_i\)与原始消息\(m\)拼接:
\[\text{inner\_input} = S_i \;||\; m \]
对inner_input进行哈希:
\[H_{\text{inner}} = H(\text{inner\_input}) \]
示例:若\(K'\)的第一个字节为0x42,则\(S_i\)的第一个字节为0x42 ⊕ 0x36 = 0x74。整个\(S_i\)看起来像随机数据,但与\(K'\)相关。
步骤3:生成外层哈希的输入
计算:
\[S_o = K' \oplus opad \]
即,将\(K'\)的每个字节与0x5C异或。然后,将\(S_o\)与内层哈希结果\(H_{\text{inner}}\)拼接:
\[\text{outer\_input} = S_o \;||\; H_{\text{inner}} \]
对outer_input进行哈希:
\[\text{HMAC} = H(\text{outer\_input}) \]
最终输出:哈希结果就是HMAC值,长度等于哈希函数的输出长度(如SHA-256为32字节)。
5. 安全性设计原理
防止长度扩展攻击
- 长度扩展攻击:对于某些哈希函数(如MD5、SHA-1),知道\(H(m)\)后,即使不知道\(m\),也可以计算\(H(m || \text{padding} || \text{extension})\)。
- HMAC的防御:在HMAC中,攻击者不知道密钥\(K'\),因此无法构造合法的\(S_i = K' \oplus ipad\)作为哈希的初始状态。即使攻击者获得\(H_{\text{inner}}\),也无法在不知道\(K'\)的情况下生成有效的\(S_o\)进行外层哈希。
密钥与常量异或的作用
- \(ipad\)和\(opad\)将密钥\(K'\)转换为两个不同的伪随机密钥(\(S_i\)和\(S_o\))。
- 异或操作确保即使\(K'\)全零或全一,\(S_i\)和\(S_o\)也具有高熵。
- 两次哈希调用提供了“密钥先哈希消息,再哈希结果”的双重结构,增强了混淆效果。
6. 总结与实例
假设使用SHA-256,密钥\(K=\text{"secret"}\)(6字节),消息\(m=\text{"Hello"}\):
- 密钥填充:SHA-256的\(B=64\)字节。\(K\)填充58个0x00,得到64字节的\(K'\)。
- 内层哈希:
- 计算\(S_i = K' \oplus ipad\)(ipad为64个0x36)。
- 拼接\(S_i\)和\(m\),计算SHA-256得到\(H_{\text{inner}}\)。
- 外层哈希:
- 计算\(S_o = K' \oplus opad\)(opad为64个0x5C)。
- 拼接\(S_o\)和\(H_{\text{inner}}\),计算SHA-256得到最终HMAC。
输出:一个32字节的认证码,可用于验证消息完整性和真实性。
通过以上步骤,HMAC利用密钥填充和两次哈希调用,构建了一个简单而强大的消息认证码算法,其安全性依赖于底层哈希函数的抗碰撞性和密钥的保密性。