2. SM2/SM3 算法简介:国密体系、应用场景与国际对比
说实话,我刚开始接触国密算法那会儿,第一反应是:又一套新标准?后来参与了一个政务系统的密码改造项目,才真正意识到国密不是“折腾”你,而是信息安全自主可控的基石。
这节咱们聊聊国密算法体系的整体轮廓、SM2 和 SM3 到底用在哪儿,以及它们跟 RSA、ECC、SHA-256 这些国际算法的差异。我会结合自己踩过的坑来讲,希望能帮你少走弯路。
2.1 国密算法体系一览
国密算法是国家密码管理局发布的一套商用密码标准。目前最核心的几个算法分别是:
- SM1:对称加密算法,硬件实现,不公开算法细节,主要用于芯片级加密。
- SM2:椭圆曲线公钥密码算法,包括加密、签名、密钥交换。
- SM3:密码杂凑算法,输出 256 位摘要。
- SM4:对称分组密码算法,密钥长度 128 位,类似 AES。
- SM9:基于标识的密码算法,不需要证书。
咱们这门课重点讲 SM2 和 SM3,因为它们是公钥密码和哈希层面的关键组件。我个人的习惯是把算法分类画成一张图,方便对照。
2.2 SM2 算法:椭圆曲线公钥密码的中国方案
SM2 基于椭圆曲线密码学(ECC),跟我之前用过几年的 ECDSA、ECDH 是同一套数学基础。但 SM2 不是简单复制,它有一套完整的国标:GM/T 0003-2012。里面定义了签名、加密、密钥交换三个功能。
跟 ECC 相比,SM2 核心区别在于:
- 曲线参数不同:SM2 使用一条 256 位的素数域椭圆曲线,参数由国密局指定。我个人觉得这条曲线的设计比较保守,安全性有保证。
- 签名算法细节不同:SM2 签名先计算
e = HASH(M),然后生成随机数 k,计算椭圆曲线点,最后得到 (r, s)。跟 ECDSA 最大的区别是:SM2 在签名中加入了用户 ID 和曲线参数,能抵抗某种类型的攻击。 - 加密方式不同:SM2 加密采用“KDF + 异或”的混合加密,不是直接对消息做椭圆曲线运算。
我记得有一次项目中,客户要求同时支持 SM2 和 ECDSA 签名验证。我直接用同一份哈希值去验证两个算法的签名,结果就是死活不通过。后来才发现是两个算法对消息的预处理不同——比如 SM2 需要拼接 Z 值(用户标识和曲线参数散列)。
2.3 SM3 算法:密码杂凑的国内标准
SM3 是一个输出 256 位摘要的哈希算法,标准号 GM/T 0004-2012。它的结构类似 SHA-256,也是 Merkle-Damgård 结构,消息分块处理,每块 512 位,迭代压缩。
但 SM3 的压缩函数内部设计了更多“混淆”操作,比如 16 轮循环左移、置换函数、异或扩散等。从安全性上看,SM3 比 SHA-256 在抗碰撞性上要强一点——当然这只是理论分析,实际中 SHA-256 也足够安全。
SM3 的应用场景非常广:数字签名、消息认证码、密钥派生、随机数生成等等。我参与过一个电子病历项目,用 SM3 做文件的完整性校验,配合 SM2 签名,既防篡改又防抵赖。
2.4 应用场景:哪里该用 SM2 和 SM3?
下面这张表是我在项目里总结的常见场景,你直接用就对了。
| 场景 | 使用算法 | 我的实战经验 |
|---|---|---|
| 电子合同签名 | SM2 签名 + SM3 摘要 | 记得先计算合同原文的 SM3 值,再对哈希值签名。不要直接签原文。 |
| 安全通道握手 | SM2 密钥交换 + SM3 密钥派生 | 我在实现 TLS 国密套件时,就是用的 ECDHE_SM2_SM3。 |
| 文件完整性校验 | SM3 杂凑 | 与 SHA-256 用法完全相同,只是把算法名从 sha256sum 改成 sm3sum。 |
| 身份认证令牌 | SM2 签名 | 后端用 SM2 私钥对用户 ID + 时间戳签名,前端用公钥验证。 |
| 密钥封装与加密传输 | SM2 加密 | 实际项目中我很少直接用 SM2 加密大文件,通常用它加密对称密钥(SM4 密钥)。 |
2.5 与国际算法对比:SM2 vs RSA/ECC,SM3 vs SHA-256
很多人问我:国密到底比国际算法强在哪?弱在哪?我分别说说。
SM2 vs RSA
- 密钥长度:RSA 需要 2048 位才能保证安全,SM2 只要 256 位。SM2 的签名、加密、密钥交换都更短。
- 性能:SM2 签名和密钥交换比 RSA 快很多(尤其是私钥操作),但 SM2 验签略慢于 RSA 验签(因为椭圆曲线点乘)。
- 兼容性:RSA 在旧系统里遍地都是,SM2 需要额外适配。我遇到过一个银行前置机只支持 RSA,改造时肝了一周移植 SM2。
SM2 vs ECC(国际椭圆曲线,如 P-256)
- 数学基础相同,都是椭圆曲线离散对数问题。
- 曲线参数不同:SM2 使用国标定义的曲线,P-256 由 NIST 定义。两者安全性等价,没有谁明显优于谁。
- 协议细节不同:签名的消息预处理、编码方式有差异,不能互操作。
SM3 vs SHA-256
- 结构高度相似:都是 512 位分组,256 位输出。
- 安全强度:SM3 的轮函数更复杂,理论安全性略高。实际攻破两者都不可行。
- 性能:纯软件实现 SM3 略慢,但在 ARM 和飞腾上已经做了指令优化,差距不大。
2.6 避坑指南:从我的血泪史里总结
- 不要混用 hash 预处理:SM2 签名时对消息的哈希计算,需要先拼接 Z 值(用户标识 + 曲线参数哈希)。我刚开始没拼接,导致签名验证失败,debug 了一整天。
- 密钥格式别搞错:SM2 公钥长度 64 字节(未压缩),私钥 32 字节。有些库用 PEM 格式,有些用 DER,转换时注意标识符 OID 是
1.2.156.10197.1.301。 - SM3 不要当随机数用:哈希不是伪随机函数,做密钥派生时一定要用专门的 KDF(SM2 里定义了一种)。我之前图省事直接用 SM3 做 KDF,被安全审计打了回来。
- 测试向量要验证:国标文档
GM/T 0003-2012附录有详细的测试向量(明文、私钥、签名、加密结果)。建议你实现完成后先用这些向量跑一遍,确保没错。
#define SM2_DEBUG 来输出中间数据(比如随机数 k、椭圆曲线点坐标),调试完再关掉。超级有效。
好了,这一节的内容就到这儿。你先把国密体系的脉络理清,SM2 和 SM3 的核心差异记住,后面我们就要深入代码了。