跳到主要内容
加密解密2026-09-226 分钟阅读

国密算法实战指南:SM2、SM3、SM4 怎么选、怎么对接、怎么排查

国密不是可选项,是硬性合规

做政务、金融、国企项目的开发者迟早撞上同一句话:「系统需支持国密算法」。这不是技术偏好——等保 2.0 和商用密码评估(密评)把 SM 系列算法写进了验收标准,SHA-256 和 RSA 在这些场景不能替代 SM3 和 SM2。第一次对接时最容易犯的认知错误是拿国际算法类比硬套:「SM3 就是中国的 SHA-256 吧?」——设计上确实同构,但两端必须跑同一套算法才能对上:你用 SHA-256 算的摘要发给要求 SM3 的对端,永远校验失败。

三个算法各管一摊,选型一句话:

需求算法国际对应
数据加密(对称)SM4AES
哈希/摘要SM3SHA-256
签名/非对称加密SM2RSA/ECC

配套的浏览器本地工具:SM4 加解密、SM3 哈希、SM2 加解密签名——联调时快速造测试数据、验证中间结果,全程不上传。

SM4:对接失败 90% 死在这三处

SM4 是 128 位分组密码,对接时「我加密的对端解不开」的排查顺序(按命中率排):

1. 密钥格式。SM4 密钥固定 16 字节,联调最常见的错位是:你用 UTF-8 字符串直接当密钥("1234567890abcdef" 被当 16 个字符),对端按 32 位 hex 解析成 16 字节——同一个字符串,两种解释,密文必然不同。确认双方约定:hex 还是 utf8 直填,长度按字节算不是按字符算。

2. 工作模式与 IV。ECB 无 IV、CBC 必须带 16 字节 IV 且两端一致。模式错配的典型症状是:解密不报错但明文是乱码(前 16 字节对、后面全错——IV 错位的高频指纹)。真实业务应避开 ECB(相同明文块产出相同密文块,泄漏结构特征),测试连通性时才用它。

3. 输出编码。密文用 hex 还是 base64 传输,三方(你、对端、文档)必须写死同一个约定。这个排最后不是因为少见,是因为一旦约定了就不容易错——前提是真的约定了。

一个健康的调试习惯:联调前双方先用固定明文 + 固定密钥各出一份期望密文,肉眼比对不一致再逐项对上面三处,比对着黑盒猜快十倍。

SM3:哈希的「对不上」只有一种原因

SM3 输出固定 256 位(64 个 hex 字符)。它没有密钥、没有模式、没有 IV——所以两端算出来不一样时,原因只有一个:输入不一样。而输入不一样的头号惯犯是不可见字符:

  • 文档里复制出来的字符串带尾随换行或空格
  • 一端做了 trim 另一端没做
  • JSON 序列化的字段顺序或空格差异(对 JSON 做 SM3 摘要前必须约定规范化序列化)
  • 编码差异:UTF-8 vs GBK 对中文输入产出完全不同的哈希

排查法:把双方的原始输入按字节打出来(hex dump)对比,而不是对比字符串看着像。哈希算法本身没有「兼容性问题」——它是确定性的,输入相同输出必然相同,所以 SM3 对不上 = 输入不同,没有第二种可能。

SM2:三件事别搞混

SM2 是椭圆曲线体系,一次对接里通常出现三种操作,别混:

  • 加密/解密:公钥加密、私钥解密(给别人传敏感数据时用)
  • 签名/验签:私钥签名、公钥验签(证明「这是我发的、没被改过」)
  • 密钥协商:双方推导共享密钥(通信建连时用,工具里一般不涉及)

高频坑:验签失败的真正原因往往不在签名算法,而在被签名的原文——两端对「签名内容」的理解不一致(一端签的是原始报文,另一端验的是去掉换行的版本,或加了字段名前缀的版本)。排查顺序:先逐字节比对双方的待签原文,再看密钥对是否匹配。

密钥安全边界必须说清:测试密钥随便造(SM2 工具本地生成一对,加密→解密、签名→验签闭环验证流程),生产私钥永远不进任何网页、脚本参数或聊天工具——私钥管理属于密管系统/硬件加密机的职责,不属于联调工具。

SM2 密文顺序:C1C3C2 与 C1C2C3

加密联调里第二高发的坑是密文分段顺序。SM2 密文由三段拼接:

段含义长度(hex 字符,未压缩点)
C1临时椭圆曲线点(x‖y,库侧常不带 04)128
C3杂凑校验值64
C2明文异或后的密文随明文变长

GB/T 32918.4-2016 推荐顺序是 C1‖C3‖C2;不少早期 SDK 与文档示例仍用 C1‖C2‖C3。两端顺序不一致时,解密几乎必然失败——症状像「密钥错了」,根因却是字段拼接。站内 SM2 工具 默认走 C1C3C2,并可一键切到 C1C2C3,用来当「已知正确的对端」做对照。

另外两处格式噪声也值得写进联调约定:

  1. 公钥:非压缩是 04 + 128 位坐标(共 130 hex);有的对端只给 128 位裸坐标——补上 04 即可。压缩公钥为 02/03 + 64 位 x。
  2. 密文前缀:部分库会给整段密文再套一层 04;若对端密文以 04 开头且长度明显偏长,先剥掉再解。本站工具会自动处理这两种常见形态。

签名侧还要单独核对:ASN.1 DER 包装的签名 与 裸 r‖s(128 hex)不可混用;SM3 杂凑时的 userId(默认常为 1234567812345678)两端必须一致。

SM4 编码与 IV:把约定写成接口契约

SM4 排查表里的「输出编码」值得再展开一层。本站工具默认密文为 hex,也可切 Base64——和 AES 联调时一样,肉眼能分,但不能靠猜。CBC 下 IV 是 16 字节(32 hex),且不可省略;缺 IV 或 IV 与加密端不一致时,常见指纹是「解密不报错但明文乱码,且首块还像可读」。密钥同样只认 16 字节:带 0x、中间空格的 hex 串应先规范化再喂给库——否则会和「UTF-8 直填 16 个字符当密钥」再次撞车。

第一次联调仍建议:固定明文 + 固定密钥(+ 固定 IV)双方各出一份期望密文,先对齐编码与模式,再接入真实业务字段。

一张联调自查表

症状先查
SM4 密文对端解不开密钥解释(hex/utf8)→ 模式与 IV → 输出编码(hex/Base64)
SM4 解密出乱码但首块正常IV 错位(CBC 的经典指纹)
SM4 CBC 直接报「需要 IV」加密/解密端是否都传了 16 字节 IV
SM3 两端哈希不一致不可见字符 / trim / 编码(输入必然不同)
SM2 解密失败、密钥看着对密文顺序 C1C3C2 vs C1C2C3 → 多余 04 前缀 → 公钥格式
SM2 验签失败待签原文逐字节比对 → DER vs r‖s → userId → 密钥对匹配
全部对不上先用固定明文+固定密钥交换期望密文基线

与国际算法并存的现实

多数系统在过渡期需要同时支持两套:配置里留算法开关(algorithm: SM4 | AES),按对接方的要求逐通道切换。工具层面两端都备齐:国密三件套之外,站内同样有 AES 加解密、RSA 工具和 SHA-256——同一份数据两套算法各算一遍比对,是过渡期排查的日常。

算法选型与合规语境的总览见姊妹篇《国密算法入门指南》;标准号对照(GM/T / GB/T / ISO)见《国密标准号速查》。

排查注记

SM4 三处排查按命中率排,且特意解释输出编码排最后「不是因为少见,是因为一旦约定了就不容易错」——排序依据是出错概率,不是重要性。SM3 一节把结论压到一句「对不上 = 输入不同,没有第二种可能」,因为哈希是确定性的、没有密钥模式 IV,头号惯犯是不可见字符,所以排查法是 hex dump 按字节对比、而不是对比字符串看着像。SM2 验签失败同样先怀疑原文而不是算法——两端对「签名内容」的理解不一致(换行、字段前缀)才是高频根因。

本文工具均来自 ToolVault——开发者工具均在浏览器本地运行,密钥与数据不出设备。