HMAC (基于哈希的报文认证码) 算法中的密钥填充与哈希调用顺序
字数 2051 2025-12-15 16:13:27
HMAC (基于哈希的报文认证码) 算法中的密钥填充与哈希调用顺序
题目描述
HMAC 是一种基于密码哈希函数(如 SHA-256、MD5 等)和密钥生成消息认证码的算法,用于同时验证数据完整性和真实性。本题目要求详细解析 HMAC 算法在计算过程中,密钥如何被填充或调整,以及哈希函数被调用的顺序。重点是理解算法如何将密钥与消息通过两次哈希调用组合,并解释每一步的设计目的。
解题过程
- HMAC 的基本结构
HMAC 的定义为:
\[ \text{HMAC}(K, m) = H\left( (K' \oplus \text{opad}) \parallel H\left( (K' \oplus \text{ipad}) \parallel m \right) \right) \]
其中:
- \(K\) 是输入密钥(长度可变),\(m\) 是消息。
- \(H\) 是哈希函数(如 SHA-256)。
- \(K'\) 是经过处理的密钥,长度等于哈希函数的输入块大小。
- \(\text{ipad}\) 和 \(\text{opad}\) 是固定的常量。
- \(\oplus\) 表示异或操作,\(\parallel\) 表示拼接。
核心思想是通过两次哈希调用,将密钥与消息混合,防止长度扩展攻击等漏洞。
-
密钥填充与调整步骤
- 步骤 1:确定块大小
哈希函数 \(H\) 的输入块大小记为 \(B\)(单位:字节)。例如 SHA-256 的 \(B = 64\) 字节,SHA-1 的 \(B = 64\) 字节,SHA-512 的 \(B = 128\) 字节。 - 步骤 2:密钥处理
- 如果原始密钥 \(K\) 的长度等于 \(B\):直接设 \(K' = K\)。
- 如果 \(K\) 长度大于 \(B\):先用哈希函数 \(H\) 压缩 \(K\) 得到长度为 \(L\)(哈希输出长度)的结果,然后右补零到 \(B\) 字节,得到 \(K'\)。
例如,使用 SHA-256 时,若 \(K\) 长度为 100 字节,则先计算 \(H(K)\) 得到 32 字节哈希值,再补充 32 个零字节至 64 字节。 - 如果 \(K\) 长度小于 \(B\):右补零直到长度恰好为 \(B\) 字节,得到 \(K'\)。
此步骤确保 \(K'\) 长度始终为 \(B\),避免密钥长度不匹配导致的实现不一致。
- 步骤 1:确定块大小
-
内部哈希调用(第一次哈希)
- 定义常量 \(\text{ipad}\) 为重复的字节
0x36(即二进制00110110),长度 \(B\) 字节。 - 计算 \(S_i = K' \oplus \text{ipad}\)。这相当于将 \(K'\) 的每个字节与
0x36异或。 - 拼接 \(S_i\) 与原始消息 \(m\),得到 \(S_i \parallel m\)。
- 计算内部哈希结果:\(H_i = H(S_i \parallel m)\)。
这一步将密钥与消息混合后哈希,但结果不会直接输出,防止攻击者从输出反推密钥。
- 定义常量 \(\text{ipad}\) 为重复的字节
-
外部哈希调用(第二次哈希)
- 定义常量 \(\text{opad}\) 为重复的字节
0x5C(即二进制01011100),长度 \(B\) 字节。 - 计算 \(S_o = K' \oplus \text{opad}\)。这相当于将 \(K'\) 的每个字节与
0x5C异或。 - 拼接 \(S_o\) 与内部哈希结果 \(H_i\),得到 \(S_o \parallel H_i\)。
- 计算最终 HMAC 值:\(\text{HMAC} = H(S_o \parallel H_i)\)。
第二次哈希将密钥再次混合,并哈希内部结果,使攻击者无法通过控制消息前缀伪造认证码。
- 定义常量 \(\text{opad}\) 为重复的字节
-
关键设计解析
- 填充目的:密钥填充到固定长度 \(B\) 确保哈希函数输入对齐,避免因密钥长度差异导致的安全弱点。
- 两次哈希顺序:先与
ipad混合哈希消息,再与opad混合哈希结果,形成“嵌套”结构,增强对生日攻击和长度扩展攻击的抵抗力。 - 常量选择:
ipad和opad的值(0x36和0x5C)任意但不同,确保两次混合产生独立结果。它们二进制表示有足够差异,使 \(S_i\) 和 \(S_o\) 无明显相关性。 - 安全性依赖:HMAC 的安全性归约到底层哈希函数的抗碰撞性和伪随机性,且即使哈希函数存在弱点,HMAC 仍能提供一定保护。
通过以上步骤,HMAC 以固定模式调用哈希函数,将密钥与消息绑定,生成固定长度的认证码。实际应用中,只需确保密钥 \(K\) 保密,即可验证消息来源和完整性。