SM3 密码杂凑算法原理详解:从消息填充到压缩函数

算法原理 · 2026-05-31

概述

SM3 是中国国家密码管理局于 2008 年发布的密码杂凑算法,2012 年作为密码行业标准公开发布(GM/T 0004-2012),2016 年作为 GB/T 32905-2016(配套标准)的引用算法。该算法设计由中国科学院数据安全与通信保密研究中心主导。

SM3 的设计目标是对 SHA-256 提供国产替代方案,提供256-bit 的杂凑值输出,安全强度与 SHA-256 相当(128-bit 抗碰撞安全性)。SM3 适用于数字签名、消息认证码、随机数生成、密钥派生等场景。

在国际标准化方面,SM3 已通过 IETF 作为 draft-sca-cfrg-sm3-02 发布,逐步被纳入国际标准体系。

算法基本参数

参数SM3SHA-256MD5说明
标准编号GM/T 0004-2012FIPS 180-4RFC 1321
输出长度256 bit (32 字节)256 bit (32 字节)128 bit (16 字节)SM3 与 SHA-256 等长
分组长度512 bit (64 字节)512 bit (64 字节)512 bit (64 字节)相同的分组大小
轮数646464相同的轮数
结构Merkle-DamgårdMerkle-DamgårdMerkle-Damgård经典迭代结构
安全强度128 bit128 bit❌ < 64 bitMD5 已被破解
抗碰撞性SM3 与 SHA-256 相当

Merkle-Damgård 结构

SM3 采用经典的 Merkle-Damgård 迭代结构,将任意长度的消息压缩为固定长度的杂凑值。

算法整体流程

对于长度为 $l$ 比特的消息 $M$($l < 2^{64}$):

  • 消息填充(Padding):将 $M$ 填充为 512-bit 的倍数
  • 消息分组:将填充后的消息分为 $t$ 个 512-bit 块 $M^{(0)}, M^{(1)}, \ldots, M^{(t-1)}$
  • 迭代压缩:$CV_i = CF(CV_{i-1}, M^{(i)})$,初始值 $CV_0 = IV$
  • 输出截断:$H(M) = CV_t$
$$SM3(M) = CF(\ldots CF(CF(IV, M^{(0)}), M^{(1)}), \ldots, M^{(t-1)})$$

消息填充

填充规则与 SHA-256 类似:

  • 在消息末尾附加一个 1 比特
  • 填充 0 比特,直到消息长度 $\equiv 448 \pmod{512}$
  • 最后 64 比特存放原始消息长度 $l$(以大端序 64-bit 整数表示)
形式化表示: $$M' = M \| 1 \| 0^{447 - (l \bmod 512)} \| l_{64}$$

其中 $l_{64}$ 是 $l$ 的 64-bit 大端序编码。

示例:若原始消息长度为 55 字节(440 比特),则填充 1 比特 + 7 个 0 比特(使长度为 448 比特 = 56 字节),然后附加 8 字节的长度字段,总长度 = 64 字节 = 1 个分组。

压缩函数

压缩函数 $CF$ 是 SM3 的核心,它将一个 512-bit 的消息块和一个 256-bit 的中间值压缩为一个 256-bit 的输出。

状态表示

中间变量为 8 个 32-bit 字:$A, B, C, D, E, F, G, H$,每个 32 比特,共 256 比特。

初始值 $IV$(十六进制):

CODE
7380166f 4914b2b9 172442d7 da8a0600
a96f30bc 163138aa e38dee4b d0fb0e4e

消息扩展

每个 512-bit 的消息块 $M^{(i)}$ 被扩展为 132 个 32-bit 字 $W_0, W_1, \ldots, W_{67}, W'_0, W'_1, \ldots, W'_{63}$:

第一步:将 512-bit 消息块分为 16 个 32-bit 字 $W_0, W_1, \ldots, W_{15}$

$$M^{(i)} = W_0 \| W_1 \| \ldots \| W_{15}$$

第二步:扩展 $W_{16}$ 到 $W_{67}$

对于 $j = 16, 17, \ldots, 67$: $$W_j = P_1(W_{j-16} \oplus W_{j-9} \oplus (W_{j-3} \lll 15)) \oplus (W_{j-13} \lll 7) \oplus W_{j-6}$$

其中 $\lll$ 表示循环左移,$P_1(X) = X \oplus (X \lll 15) \oplus (X \lll 23)$

第三步:计算 $W'_0, W'_1, \ldots, W'_{63}$

对于 $j = 0, 1, \ldots, 63$: $$W'_j = W_j \oplus W_{j+4}$$

轮函数

压缩函数包含 64 轮运算,每轮更新状态变量:

对于 $j = 0, 1, \ldots, 63$:

$$SS_1 = ((A \lll 12) + E + (T_j \lll j)) \lll 7$$ $$SS_2 = SS_1 \oplus (A \lll 12)$$ $$TT_1 = FF_j(A, B, C) + D + SS_2 + W'_j$$ $$TT_2 = GG_j(E, F, G) + H + SS_1 + W_j$$ $$D = C$$ $$C = B \lll 9$$ $$B = A$$ $$A = TT_1$$ $$H = G$$ $$G = F \lll 19$$ $$F = E$$ $$E = P_0(TT_2)$$

其中:

  • $T_j$ 为常量:当 $0 \leq j \leq 15$ 时 $T_j = 0x79cc4519$;当 $16 \leq j \leq 63$ 时 $T_j = 0x7a879d8a$
  • $P_0(X) = X \oplus (X \lll 9) \oplus (X \lll 17)$

布尔函数

$FF_j$ 和 $GG_j$ 是轮函数中的非线性布尔函数,根据轮数 $j$ 的不同使用不同的定义:

$FF_j(X, Y, Z)$

$$FF_j(X, Y, Z) = \begin{cases} X \oplus Y \oplus Z & 0 \leq j \leq 15 \\ (X \wedge Y) \vee (X \wedge Z) \vee (Y \wedge Z) & 16 \leq j \leq 63 \end{cases}$$

$GG_j(X, Y, Z)$

$$GG_j(X, Y, Z) = \begin{cases} X \oplus Y \oplus Z & 0 \leq j \leq 15 \\ (X \wedge Y) \vee (\neg X \wedge Z) & 16 \leq j \leq 63 \end{cases}$$

设计分析:前 16 轮使用简单的异或函数(与 SHA-256 的 $Ch$ 函数类似),后 48 轮使用更复杂的布尔函数。这种设计提供了更强的扩散性和抗差分攻击能力。

常量 $T_j$

轮函数中使用的常量 $T_j$:

$$T_j = \begin{cases} \text{0x79cc4519} & 0 \leq j \leq 15 \\ \text{0x7a879d8a} & 16 \leq j \leq 63 \end{cases}$$

这些常量通过 $\sin$ 函数的小数部分生成(类似 SHA-1/SHA-256 的设计方法),确保没有后门或隐藏模式。

最终输出

64 轮运算完成后,新的中间值与旧的中间值进行异或:

$$CV_{i+1} = (A \| B \| C \| D \| E \| F \| G \| H) \oplus CV_i$$

安全性分析

抗差分攻击

SM3 的 64 轮设计提供了充分的安全边际。根据现有分析:

  • 最佳差分攻击覆盖约 26 轮(低于 64 轮设计)
  • 差分概率上限远低于安全阈值
  • 消息扩展的双路设计($W_j$ 和 $W'_j$)增加了差分路径的复杂性

抗碰撞攻击

SM3 提供 128-bit 的抗碰撞安全性(因为输出长度为 256 bit,生日攻击需要 $O(2^{128})$ 次运算),与 SHA-256 相当。

与 SHA-256 的结构差异

维度SM3SHA-256
消息扩展三路交叉($W_j$ 和 $W'_j$)单路线性扩展
布尔函数分段(前16/后48轮)统一使用 $Ch$ 和 $Maj$
轮常量2 个值交替64 个独立常量
状态更新8 个字全部更新8 个字全部更新
非线性来源$FF_j$, $GG_j$, $P_0$, $P_1$$Ch$, $Maj$, $\Sigma_0$, $\Sigma_1$

标准体系

SM3 的标准体系:

层级标准编号内容
行业标准GM/T 0004-2012SM3 密码杂凑算法
行业标准GM/T 0044-2016SM3 密码杂凑算法 第1部分:算法描述

性能特征

SM3 的性能特征(基于软件实现):

场景典型吞吐量说明
短消息(< 64 字节)~150 MB/s填充开销占比高
长消息(> 1 KB)~250 MB/s接近线性性能
硬件实现> 1 GB/s专用集成电路
注意:以上为典型参考值,实际性能取决于 CPU 架构、实现优化和编译器选项。

参考来源

相关实践