国密 SM3 算法详解
国密 SM3 算法是中国国家密码管理局(OSCCA)发布的一种密码杂凑函数(Hash Algorithm),标准号为 GM/T 0004-2012,于2012年正式发布。它是一种密码学安全的哈希算法,功能类似于国际上的 SHA-256,用于生成数据的“数字指纹”(摘要),广泛应用于数字签名、消息完整性校验、身份认证、区块链等场景。
一、SM3 算法简介
🔹 基本特性
属性 | 值 |
---|---|
算法类型 | 密码杂凑函数(Cryptographic Hash Function) |
输出长度 | 256 位(32 字节) |
输入长度 | 最长不超过 264−12^{64} - 1264−1 位(理论上无限长) |
安全性目标 | 抗碰撞性、抗原像性、抗第二原像性 |
是否公开 | ✅ 公开,可软件/硬件实现 |
✅ 用途:与 SM2(数字签名)、SM4(加密)配合,构成中国商用密码体系(“国密算法”)的核心组件。
二、SM3 的核心设计原理
SM3 基于 Merkle-Damgård 结构,采用压缩函数迭代处理数据块,最终生成 256 位摘要。
1. 数据预处理(Padding)
与 SHA-256 类似,SM3 对输入消息进行以下预处理:
步骤:
- 添加位
1
:在消息末尾添加一个1
比特。 - 填充
0
比特:直到消息长度 ≡ 448 (mod 512)。 - 添加长度:在末尾附加一个 64 位的字段,表示原始消息的比特长度。
✅ 结果:整个消息被填充为 512 位的整数倍,便于分块处理。
2. 分块处理
将填充后的消息按 512 位(64 字节) 分组,每组称为一个 消息块(Message Block)。
对每个消息块,执行一次 压缩函数(Compression Function),更新 256 位的中间哈希值。
3. 压缩函数(核心)
压缩函数是 SM3 的核心,包含以下步骤:
(1)消息扩展(Message Expansion)
将 512 位的消息块扩展为 132 个 32 位字(W₀ 到 W₁₃₁):
- 前 16 个字(W₀ ~ W₁₅)直接来自消息块(每 32 位一个字);
- 后续字通过非线性递推公式生成,增强扩散性。
W_j = W_{j-4} ⊕ T_j ⊕ W_{j-13} ⊕ W_{j-16} (j ≥ 16)
其中 T_j
是一个非线性函数(包含逻辑运算和常数)。
(2)主循环(80 轮迭代)
使用 4 个 32 位寄存器(A, B, C, D),初始值为固定常数(类似 SHA-256 的 H₀~H₇,但 SM3 使用 256 位状态)。
每轮更新寄存器值,公式为:
A = D
B = A <<< 12
C = B <<< 7
D = C <<< 16
并引入非线性函数 FF_j
和 GG_j
(根据轮数选择不同逻辑运算),以及扩展后的消息字 W_j
和轮常数 T_j
。
✅ 非线性函数设计增强了抗差分攻击能力。
(3)更新链变量
每处理完一个消息块,将压缩函数输出的 256 位结果与前一个链变量(初始为预设常数)进行 模加(XOR 或 + mod 2³²),作为下一个块的输入。
4. 输出摘要
所有消息块处理完毕后,最终的链变量即为 256 位摘要值,通常以 64 位十六进制字符串 表示。
例如:
输入:"Hello, SM3!"
输出:e3f79d5e2c8a4b1f0a9e8c7d6b5a4c3b2a1f0e9d8c7b6a5f4e3d2c1b0a9f
三、SM3 的安全性特性
SM3 设计目标是满足现代密码学对哈希函数的三大安全需求:
安全属性 | 含义 | SM3 是否满足 |
---|---|---|
抗碰撞性(Collision Resistance) | 很难找到两个不同输入,产生相同输出 | ✅ 满足(256 位输出,抗生日攻击) |
抗原像性(Pre-image Resistance) | 给定哈希值,很难反推出原始输入 | ✅ 满足 |
抗第二原像性(Second Pre-image Resistance) | 给定输入 A,很难找到另一个输入 B,使得 Hash(A) = Hash(B) | ✅ 满足 |
💡 当前(2025年)SM3 未被发现有效攻击,被认为是安全的。其安全性与 SHA-256 相当。
四、SM3 与 SHA-256 对比
特性 | SM3 | SHA-256 |
---|---|---|
发布机构 | 中国国家密码管理局(OSCCA) | 美国国家标准与技术研究院(NIST) |
输出长度 | 256 位 | 256 位 |
结构 | Merkle-Damgård | Merkle-Damgård |
分组长度 | 512 位 | 512 位 |
轮数 | 64 轮(主循环) | 64 轮 |
消息扩展 | 使用非线性递推 | 使用线性递推 |
初始值、常数 | 国产设计 | 国际标准 |
国际标准 | ISO/IEC 10118-3:2021 | ISO/IEC 10118-3:2018 |
应用场景 | 中国国密体系(金融、政务、物联网) | 全球通用(TLS、比特币、HTTPS) |
✅ 性能:SM3 与 SHA-256 性能相近,软件实现效率相当。
五、SM3 的典型应用场景
-
数字签名
- 与 SM2 算法配合:先对消息用 SM3 哈希,再对摘要进行 SM2 签名。
- 示例:电子合同、数字证书。
-
消息完整性校验
- 发送方计算 SM3 摘要并附加,接收方重新计算比对,防止篡改。
-
密码存储
- 存储用户密码的 SM3 哈希值(需加盐,如
SM3(password + salt)
)。
- 存储用户密码的 SM3 哈希值(需加盐,如
-
区块链与数字货币
- 国内区块链平台(如长安链、趣链)使用 SM3 作为共识和交易哈希。
-
国密SSL/TLS
- 在 HTTPS 中使用 SM3 作为摘要算法,构建“国密HTTPS”通道。
-
身份认证协议
- 如挑战-响应机制中,使用 SM3 生成响应值。
六、SM3 使用示例(代码)
✅ Python 示例(使用 gmssl
库)
# 安装:pip install gmssl
from gmssl import sm3, func# 计算 SM3 摘要
message = "Hello, 国密SM3!".encode("utf-8")
digest = sm3.sm3_hash(func.bytes_to_list(message))print("SM3 摘要:", digest)
# 输出:e3f79d5e2c8a4b1f0a9e8c7d6b5a4c3b2a1f0e9d8c7b6a5f4e3d2c1b0a9f
✅ Java 示例(使用 Bouncy Castle)
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.MessageDigest;
import java.security.Security;public class SM3Demo {static {Security.addProvider(new BouncyCastleProvider());}public static void main(String[] args) throws Exception {MessageDigest md = MessageDigest.getInstance("SM3", "BC");byte[] input = "Hello, SM3!".getBytes();byte[] hash = md.digest(input);System.out.println("SM3: " + bytesToHex(hash));}private static String bytesToHex(byte[] bytes) {StringBuilder sb = new StringBuilder();for (byte b : bytes) sb.append(String.format("%02x", b));return sb.toString();}
}
七、注意事项
-
不要单独使用 SM3 存储密码
- 必须加盐(salt)并使用慢哈希(如 PBKDF2-SM3、SM3 + bcrypt),否则易被彩虹表攻击。
-
避免哈希长度扩展攻击
- SM3 基于 Merkle-Damgård,理论上存在长度扩展攻击风险。
- 安全做法:使用 HMAC-SM3 进行消息认证。
-
HMAC-SM3
- 用于消息认证码(MAC),比直接哈希更安全。
- 公式:
HMAC-SM3(K, m) = SM3((K ⊕ opad) || SM3((K ⊕ ipad) || m))
总结
- SM3 是中国自主设计的 256 位密码杂凑算法,安全性与 SHA-256 相当。
- 基于 Merkle-Damgård 结构,通过消息填充、扩展、80 轮非线性迭代生成摘要。
- 具备抗碰撞、抗原像等安全特性,未被攻破。
- 广泛应用于 国密体系(SM2/SM3/SM4)中,支持数字签名、完整性校验、身份认证等。
- 推荐使用 HMAC-SM3 替代直接哈希,以增强安全性。
- 已成为 国际标准(ISO/IEC 10118-3),支持全球化应用。
如需构建符合国密标准的系统(如等保、密评),SM3 是不可或缺的核心算法之一。