国密算法概述:SM2、SM3、SM4、SM9 算法原理与规范
说到国密,很多做对接的同学第一反应是「头疼」。其实说白了,国密就是一套我们自己写的密码算法标准,跟国际上的 RSA、AES、SHA-256 是同一个赛道的选手。我刚开始接触时也觉得跟 RSA 差不多,直到被 SM2 的签名格式卡了整整一下午。嗯,从那以后我学乖了——先弄清楚这些算法到底长什么样。
SM2:椭圆曲线公钥密码算法
SM2 是非对称算法,对标国际上的 ECDSA / ECDH。它可以用在数字签名、密钥交换和公钥加密上。我个人习惯把 SM2 理解为「椭圆曲线版的 RSA」,但它的密钥长度更短、安全强度更高——256 位的 SM2 密钥等价于 3072 位的 RSA。
标准规范方面,你得记住这三个编号:
- GB/T 32918.1-2016 — 总则,告诉你椭圆曲线怎么选
- GB/T 32918.2-2016 — 数字签名算法,签名验签流程
- GB/T 32918.4-2016 — 公钥加密算法,加密解密流程
SM3:密码杂凑算法
SM3 是哈希算法,输出 256 位的摘要。它跟 SHA-256 长度一样,但算法细节不同。我在实际对接中见过最多的场景是:先做 SM3 摘要,再用 SM2 签名。说白了,SM3 的作用就是给任意长的数据「提取指纹」。
标准规范是 GB/T 32905-2016。你可能会问:直接用 SHA-256 不行吗?从算法本身来说不行——国密合规要求必须是 SM3。而且 SM3 的压缩函数的轮数设计使得它在软件实现上比 SHA-256 稍慢,但安全冗余更高。
| 特性 | SM3 | SHA-256 |
|---|---|---|
| 输出长度 | 256 bit | 256 bit |
| 消息分组 | 512 bit | 512 bit |
| 压缩轮数 | 64 轮 | 64 轮 |
| 消息扩展 | 132 字 | 64 字 |
嗯,这里要注意:SM3 的扩展算法和 SHA-256 完全不同,所以它们的输出值不可能一样。做兼容性测试时,必须确认双方用的都是 SM3,否则验签永远不会通过。
SM4:分组密码算法
SM4 是对称加密算法,跟 AES 对标。它的分组长度是 128 位,密钥长度也是 128 位。我觉得 SM4 比 SM2 简单得多——没有椭圆曲线,就是加解密。标准规范是 GB/T 32907-2016。
SM4 使用 Feistel 结构,跟我以前做过的 DES 有一点点像,但轮数更多(32 轮),安全性也高得多。它的 S 盒是国密自己设计的,不依赖任何国际标准。
SM9:标识密码算法
SM9 是最新的国密公钥算法,跟 SM2 一样是非对称的,但有一个巨大的区别——它不需要证书。SM9 用「标识」来做公钥,比如用户的邮箱、手机号、QQ 号。标准规范是 GB/T 38635-2020。
你说这不就是 IBE(标识加密)吗?对,它就是基于双线性对的 IBE。我在项目中遇到过 SM9 的场景:两个系统要安全通信,但没有 CA 做证书。用 SM9 就直接拿对方的 ID 当公钥用,省掉了证书管理的麻烦。
四种算法的核心对比
| 算法 | 类型 | 密钥长度 | 主要用途 | 标准编号 |
|---|---|---|---|---|
| SM2 | 非对称(椭圆曲线) | 256 bit | 签名 / 加密 / 密钥交换 | GB/T 32918 |
| SM3 | 哈希 | 256 bit(输出) | 数据完整性 / 消息摘要 | GB/T 32905 |
| SM4 | 对称(分组密码) | 128 bit | 数据加密 | GB/T 32907 |
| SM9 | 非对称(标识密码) | 256 bit | 签名 / 加密(无证书) | GB/T 38635 |
一个简单的示例:SM2 签名验签(Python)
我在写这个示例前,踩过一个大坑:SM2 的签名数据是 DER 编码的,很多人直接用原始 R/S 值拿去验签,结果通不过。下面是一个标准的签名流程:
from gmssl import sm2, func
# 生成密钥对
private_key = '00B9AB0B828FF68872F21A837FC303668428DEA11DCD1B24429D0C99E24EED83D5'
public_key = 'B9C9A6E04E9C91F7BA880429473747DB7D9F6C2E8B8F8C6C8A8B8F8C0A8F8E8D8'
sm2_crypt = sm2.CryptSM2(public_key=public_key, private_key=private_key)
# 待签名数据
data = b"hello, gmssl"
# 签名
sign = sm2_crypt.sign(data, random_hex=func.random_hex(32))
print("SM2 签名结果 (hex):", sign)
# 验签
verify = sm2_crypt.verify(sign, data)
print("验签通过:", verify)
国密算法家族关系图
你看,从结构上看,SM2 和 SM9 都属于公钥密码体系,但 SM9 不需要证书。SM3 是摘要算法,SM4 是对称加密。这四种算法覆盖了现代密码学的全部核心场景:加密、签名、摘要、密钥交换。
标准规范速查表
我习惯把这几个标准编号贴在墙上,调试接口时直接翻:
- SM2:GB/T 32918.1~5-2016
- SM3:GB/T 32905-2016
- SM4:GB/T 32907-2016
- SM9:GB/T 38635.1~2-2020
- 通用指导:GM/T 0009-2012(SM2 密钥格式)
说白了,这些标准文件才是第一手参考。网上很多博客连密钥长度都写错了,我建议你还是拿标准原文来对照。好,这一章我们先把算法的轮廓画清楚,后面章节再一个个拆开来细说。