RESTful接口国密封装教程 - 第3节
国密算法,到底怎么定义?
做接口加密时,很多人上来就问:“国密算法到底是什么?跟国际算法有啥区别?”我刚开始接触时也懵过。其实国家密码管理局(简称“国密局”)从2010年左右就开始系统性发布一系列密码行业标准,后来逐步升级为国家标准(GB/T 开头)。这套算法体系,说白了就是咱们自己的“密码工具箱”。
嗯,这里面有哈希算法、分组密码、公钥密码,还有标识密码。名字你可能听过:SM2、SM3、SM4、SM9。每个算法都有对应的标准文档,定义了具体的参数、运算规则、接口格式。做RESTful接口封装时,你必须严格按照这些标准来,否则合规过不了,甚至系统间互不认。
标准体系一览
先看一张总览图,帮你快速建立整体认知:
一个实用小经验:我在项目中遇到过客户只要求“国密合规”,但对具体用哪个算法并无概念。这时候我一般建议:身份认证用 SM2 签名,数据加密用 SM4,完整性校验用 SM3。这个组合能覆盖大部分 RESTful 接口的安全需求。
SM3 杂凑算法:国标里的“SHA-256”
先聊 SM3。它的标准编号是 GB/T 32905-2016。我个人习惯把它叫作“国产 SHA-256”,因为输出长度也是 256 位(32 字节),但内部结构不一样。
核心参数
| 参数项 | 值 |
|---|---|
| 输出长度 | 256 bits (32 bytes) |
| 消息分组长度 | 512 bits (64 bytes) |
| 字长 | 32 bits |
| 迭代轮数 | 64 轮 |
| 安全强度 | 128 bits(抗碰撞) |
| 标准文档 | GB/T 32905-2016 |
你想想看,SM3 跟 SHA-256 比,主要区别在于消息扩展算法和压缩函数的布尔函数设计。我在一次合规审查中做过对比测试,同样长度的消息,SM3 运算比 SHA-256 慢大约 10%~15%,但完全能接受。而且 SM3 的置换函数对某些攻击路径有更强的抵抗。
注意:不要直接把 SHA-256 的哈希值拿来“宣称”国密合规。我曾经遇到一个项目,开发觉得“反正都是 256 位,先上线再改”,结果被监管点名整改。必须使用标准库中的 SM3 实现,不能自行“映射”。
SM4 分组密码:对称加密的国标选择
SM4 对应的标准是 GB/T 32907-2016。它是分组密码,分组长度 128 位,密钥长度也是 128 位。我最早接触 SM4 是在替换 DES/3DES 的政府项目中,后来发现它用在 RESTful 接口的数据加密上非常顺手。
核心参数
| 参数项 | 值 |
|---|---|
| 分组大小 | 128 bits |
| 密钥长度 | 128 bits |
| 轮数 | 32 轮 |
| 密钥扩展算法 | 32 轮非线性迭代 |
| 安全强度 | 128 bits |
| 标准文档 | GB/T 32907-2016 |
工作模式与填充
SM4 本身只是一个加密算法,具体怎么用还要搭配工作模式。RESTful 接口中最常用的是 ECB 和 CBC,但 ECB 模式不安全,我建议优先用 CBC 模式 + PKCS7 填充。如果你需要并行加密或流式加密,可以考虑 CTR 模式。
避坑指南:我曾经在接口联调时发现两边 SM4 加密结果一直对不上,折腾半天才发现一方的 IV 写死了全零,另一方用的随机 IV。国标中没有规定 IV 必须随机还是固定,但为了安全,我建议每次加密都生成新的随机 IV,并作为密文的一部分传给对方。
SM2 椭圆曲线公钥密码:签名、加密、密钥交换
SM2 是一套公钥密码体系,包含数字签名算法(SM2-2)、公钥加密算法(SM2-3)和密钥交换协议(SM2-4)。标准编号 GB/T 32918.1~5。它使用 256 位素域上的椭圆曲线,安全强度与 3072 位 RSA 相当。
关键参数
| 参数项 | 值 |
|---|---|
| 曲线方程 | y² = x³ + ax + b,p = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF |
| 基点 G 坐标 | (Gx, Gy)由标准定义 |
| 阶 n | 略小于 2²⁵⁶ |
| 签名长度 | 64 bytes(r, s 各 32) |
| 密文长度 | 明文长度 + 97 bytes(SM2 混合加密) |
| 标准文档 | GB/T 32918.1~5 |
我个人习惯:在 RESTful API 中,SM2 主要用于两个地方:一是客户端对请求参数做数字签名,服务端验签;二是双方用 SM2 密钥交换协商出一个临时会话密钥,然后用 SM4 加密后续通信。这样既能解决身份认证,又能保证数据机密性。
SM9 标识密码:不需要证书的公钥体系
SM9 标准编号 GB/T 38635.1~2。它的特点是直接用用户标识(比如手机号、邮箱)作为公钥,省去了证书管理和 PKI 基础设施。实现上基于双线性对(配对运算),计算量比 SM2 大。
我平时不主张在内部 RESTful API 中一上来就用 SM9,因为它的运算速度是 SM2 的 3~5 倍,对接口延时影响明显。但如果是开放平台,需要大量用户、又不方便托管证书的场景,SM9 就是一个很优雅的解法。
算法参数对比总表
| 算法 | 标准编号 | 密钥/输出长度 | 分组/消息块 | 算法类型 | 主要用途 |
|---|---|---|---|---|---|
| SM3 | GB/T 32905 | 256 bits | 512 bits | 杂凑 | 完整性校验、数字签名基础 |
| SM4 | GB/T 32907 | 128 bits | 128 bits | 对称分组密码 | 数据加密 |
| SM2 | GB/T 32918 | 256 bits(私钥) | — | 椭圆曲线公钥密码 | 签名、加密、密钥交换 |
| SM9 | GB/T 38635 | 无固定(基于标识) | — | 标识密码(双线性对) | 无证书签名/加密 |
小结:选型思路
做 RESTful 接口封装时,我的默认选型是这样:
- 不要自己实现算法 —— 使用经过国密局认证的密码库(如 GmSSL、腾讯的 Tencrypt、华为的 SecC)。
- 签名 + 完整性:SM2 签名 + SM3 哈希。签名前先对参数按字典序排序、拼接、SM3 摘要。
- 加密传输:SM4-CBC-PKCS7,密钥用 SM2 密钥交换或预置。IV 随机,附在消息头里。
- 密钥长度必须严格按标准,不要自作聪明“改小”或“改大”。
特别提醒:SM2 公钥格式有 ASN.1 和原始坐标两种编码方式,接口对接前一定要确认双方用的格式一致。我遇到过因为一方用 DER 编码、一方用未编码的 64 字节串,导致联调了整整两天才发现。