3. 哈希函数与消息认证:哈希算法(SHA-256、SM3)、消息认证码(HMAC)、数字签名原理
哈希函数、消息认证码(MAC)与数字签名是保障数据完整性、真实性与不可否认性的三大核心密码原语。面试中,面试官通常从算法特性、安全假设、构造差异以及实际应用场景四个维度进行考察。本章系统梳理 SHA-256 与 SM3 的算法结构、HMAC 的密钥化构造原理,以及数字签名中签名与验证的完整流程。
3.1 哈希函数:SHA-256 与 SM3
哈希函数将任意长度的输入映射为固定长度的摘要值,具备抗原像性、抗第二原像性与抗碰撞性。SHA-256 与 SM3 是目前最广泛使用的两类哈希算法,前者为国际标准,后者为中国国家密码标准(GM/T 0004-2012)。
3.1.1 算法核心参数对比
| 参数项 | SHA-256 | SM3 |
|---|---|---|
| 输出长度 | 256 bits | 256 bits |
| 消息分组长度 | 512 bits | 512 bits |
| 字长 | 32 bits | 32 bits |
| 压缩函数轮数 | 64 轮 | 64 轮 |
| 初始向量 IV | 8 个 32 位常量 | 8 个 32 位常量(与 SHA-256 不同) |
| 消息扩展方式 | 线性递推 + 移位 | 非线性置换 + 异或 |
| 布尔函数 | Ch, Maj, Σ0, Σ1 | FF, GG, P0, P1(含循环移位与异或) |
| 安全强度 | 128 bits(抗碰撞) | 128 bits(抗碰撞) |
3.1.2 SHA-256 迭代结构
SHA-256 采用 Merkle-Damgård 结构,消息经填充(补 1 加 0 至 448 mod 512,附加 64 位长度)后按 512 位分组依次进入压缩函数。每轮压缩使用 64 个轮常数 K 和消息扩展生成的 W 值更新 8 个工作变量。
面试高频点: 长度扩展攻击是 Merkle-Damgård 结构的固有缺陷。攻击者已知 H(M) 和 M 长度,可在不掌握 M 的情况下计算 H(M || padding || extra)。SM3 在设计时通过更复杂的消息扩展与布尔函数增强了对此类攻击的抵抗能力。
3.1.3 SM3 算法特点
- 消息扩展: 将 16 个字扩展为 132 个字(W0~W67 + W'0~W'63),引入非线性置换 P1,扩散性更强。
- 压缩函数: 使用 64 轮双字迭代,每轮同时更新 A~H 共 8 个 32 位寄存器,布尔函数 FF 与 GG 在不同轮段采用不同逻辑。
- 性能: 软件实现上 SM3 略慢于 SHA-256(约慢 10%~15%),但硬件实现效率接近。
3.2 消息认证码(HMAC)
哈希函数本身不包含密钥,无法直接提供身份验证。消息认证码(MAC)通过引入共享密钥,确保只有持有密钥的通信双方能够生成和验证认证标签。HMAC 是使用最广泛的密钥化哈希构造方案。
3.2.1 HMAC 构造公式
HMAC(K, M) = H( (K' ⊕ opad) || H( (K' ⊕ ipad) || M ) )
其中:
K' = 如果 K 长度 > B,则 K' = H(K);否则 K' = K 右补 0 至 B 字节
B = 哈希函数分组长度(SHA-256/SM3 均为 64 字节)
ipad = 0x36 重复 B 次
opad = 0x5C 重复 B 次
H = 底层哈希函数
M = 消息
3.2.2 HMAC 安全优势
| 特性 | 说明 |
|---|---|
| 抗长度扩展攻击 | 即使底层哈希存在长度扩展缺陷,HMAC 的双重哈希结构使攻击者无法从已知标签推导新标签。 |
| 密钥独立于消息 | 密钥通过 ipad/opad 异或后分别参与内外两次哈希,避免密钥直接暴露在哈希输入中。 |
| 可证明安全性 | 若底层哈希是伪随机函数(PRF),则 HMAC 是安全的 MAC。该归约在标准模型下成立。 |
| 算法无关性 | HMAC 可套用任何哈希函数(SHA-256、SM3、SHA-3 等),替换底层算法不影响构造逻辑。 |
面试常见追问: “为什么 HMAC 需要两次哈希而不是一次?”
答:一次哈希构造 H(K || M) 存在长度扩展攻击风险,且无法提供密钥与消息的强绑定。两次哈希确保密钥同时影响内外两层,即使内层哈希被部分破解,外层仍提供保护。
答:一次哈希构造 H(K || M) 存在长度扩展攻击风险,且无法提供密钥与消息的强绑定。两次哈希确保密钥同时影响内外两层,即使内层哈希被部分破解,外层仍提供保护。
3.3 数字签名原理
数字签名是公钥密码学中实现不可否认性的核心机制。签名者使用私钥对消息摘要签名,验证者使用对应公钥验证签名有效性。与 HMAC 不同,数字签名不需要共享密钥,适用于开放网络环境。
3.3.1 数字签名通用流程
- 密钥生成: 签名者生成公私钥对 (sk, pk)。
- 签名: 对消息 M 计算哈希摘要 h = H(M),使用私钥 sk 对 h 签名得到 σ。
- 验证: 验证者计算 h' = H(M),使用公钥 pk 验证 σ 是否与 h' 匹配。
3.3.2 主流数字签名算法对比
| 算法 | 基础困难问题 | 签名长度 | 典型应用 |
|---|---|---|---|
| RSA-PSS | 大整数分解 | 256~512 字节 | HTTPS 证书、代码签名 |
| ECDSA | 椭圆曲线离散对数 | 64~72 字节 | 区块链、TLS 1.3 |
| SM2 | 椭圆曲线离散对数(国密) | 64 字节 | 电子政务、金融国密改造 |
| EdDSA (Ed25519) | 扭曲爱德华曲线离散对数 | 64 字节 | SSH、OpenPGP、现代协议 |
3.3.3 数字签名与 HMAC 的关键区别
| 维度 | HMAC | 数字签名 |
|---|---|---|
| 密钥管理 | 对称密钥,双方共享 | 非对称密钥,私钥唯一持有 |
| 不可否认性 | 不支持(双方均可生成标签) | 支持(仅私钥持有者可签名) |
| 计算开销 | 低(仅哈希运算) | 高(模幂或点乘运算) |
| 密钥分发 | 需安全信道预共享 | 公钥可公开分发 |
| 典型场景 | API 认证、消息完整性校验 | 数字证书、电子合同、区块链交易 |
3.4 哈希、MAC 与数字签名的组合关系
在实际安全通信协议(如 TLS 1.3、SSH、IPsec)中,这三类原语通常协同工作:
- 哈希函数 提供消息摘要,压缩签名或 MAC 的输入长度。
- HMAC 用于对称场景下的会话消息认证,如 TLS 记录层的消息认证。
- 数字签名 用于握手阶段的身份认证与密钥交换的签名验证。
常见面试陷阱: 面试者容易混淆“消息认证码”与“数字签名”的不可否认性。请牢记:HMAC 不能提供不可否认性,因为通信双方持有相同密钥,无法向第三方证明消息由哪一方生成。数字签名依赖私钥唯一性,天然具备不可否认性。
3.5 面试高频问题与避坑指南
| 问题 | 考察点 | 回答要点 |
|---|---|---|
| SHA-256 与 SM3 哪个更安全? | 算法分析与国密标准理解 | 两者安全强度均为 128 位抗碰撞;SM3 在消息扩展和布尔函数设计上更保守,对长度扩展攻击的抵抗优于 SHA-256。 |
| HMAC 为什么能抵抗长度扩展攻击? | HMAC 构造原理 | 外层哈希使用 opad 异或后的密钥作为输入,攻击者无法从内层哈希输出直接构造外层哈希的输入。 |
| 数字签名中为什么先哈希再签名? | 签名效率与安全 | 直接对长消息签名效率低且存在代数攻击风险;先哈希将任意长度消息压缩为固定摘要,再对摘要签名,保证安全性与效率。 |
| HMAC 能否替代数字签名? | 对称与非对称密码的适用边界 | 不能。HMAC 无法提供不可否认性,且需要安全信道预共享密钥,不适合开放网络中的多方互信场景。 |
面试加分项: 提及“SM3 在国密 SSL 协议中与 HMAC-SM3 配合使用,数字签名则采用 SM2 算法,形成完整的国密认证体系”。展示对国产密码生态的整体认知。