国密算法 SM2 / SM3 / SM4
说明
- 这三个算法分别对应什么
- SM3 是杂凑算法,输出 256 位,用法和 SHA-256 一样,但两者结果完全不同,不能互相替代。SM4 是分组密码,分组和密钥都是 128 位,站位相当于 AES-128。SM2 是椭圆曲线公钥算法,用的是国家指定的 sm2p256v1 曲线(不是 secp256r1),能做加解密也能做签名,安全强度大致对应 RSA-3072,但密钥短、运算快。三者的标准号分别是 GM/T 0004、GM/T 0002、GM/T 0003。
- SM4 的密文和别的实现对不上
- 先核对四件事:一是分组模式,ECB 不需要 IV,CBC 必须双方用同一个 IV;二是填充,国内实现基本都用 PKCS#7,但有些系统用零填充,那种情况下明文末尾的 0x00 会被吃掉;三是密钥的解释方式,同样一串
0123456789abcdef…,有的库当十六进制(16 字节),有的库当 ASCII 文本(32 字节,超长会被截断),本页用上面的「密钥格式」显式区分;四是密文编码,十六进制和 Base64 都很常见。本页的 SM4-CBC 输出与openssl enc -sm4-cbc逐字节一致。 - SM2 密文的两种排列和 04 前缀
- SM2 密文由三段拼成:C1 是临时公钥点(64 字节),C2 是与明文等长的密文,C3 是 32 字节校验值。2012 年的 GM/T 0009 把顺序规定为 C1C3C2,而更早的实现用的是 C1C2C3,两者只是拼接顺序不同,选错了解密会直接失败。另外 C1 是一个椭圆曲线点,按未压缩点格式本应有
04前缀,前端库(如 sm-crypto)习惯省略,而 Java 侧的 Hutool、BouncyCastle 通常带着。和后端联调解不开时,八成就是这两个开关没对齐——把「带 04」打开或关掉再试一次。 - 什么是 Z_A,为什么签名要带用户 ID
- SM2 签名并不是直接对消息做 SM3,而是先算一个 Z_A = SM3(ENTL ‖ ID ‖ a ‖ b ‖ xG ‖ yG ‖ xA ‖ yA),把曲线参数和签名者公钥揉进去,再对 Z_A ‖ M 做 SM3 得到待签杂凑值。这样同一段消息用不同公钥签出来的杂凑值也不同,能防止一类密钥替换攻击。ID 的国标缺省值就是字符串
1234567812345678,绝大多数系统都用它,除非对方明确要求换。如果你拿到的已经是算好的 32 字节杂凑值,把「杂凑方式」切成第二项即可。 - R‖S 和 DER 怎么选
- 签名的本质是两个 256 位整数 r 和 s。R‖S 就是把它们各补足 64 个十六进制字符直接拼起来,共 128 个字符,前端与部分国产中间件用这种;DER 是 ASN.1 编码的
SEQUENCE { INTEGER r, INTEGER s },长度在 70~72 字节之间浮动,Java 的 BouncyCastle、证书和 TLS 场景用这种。两种编码表达的是同一个签名,可以互转,选错了对方会报「签名格式错误」而不是「验签失败」。 - 安全提示
- 本页所有运算都在浏览器里用 JavaScript 完成,密钥不会离开你的电脑,但浏览器环境终究不是安全的密钥容器——生产环境的私钥应该放在加密机或密码卡里,这里生成的密钥对适合用在开发联调、接口调试和教学演示。另外 SM2 加密每次都会用到随机数,所以同一段明文两次加密得到的密文必然不同,这是正常的,不是出错。
- 相关工具
- 对称加密 AES/DES、RSA 加解密、Hash 计算、HMAC 计算、Base64 编解码。
- 开源致谢
- 本页的国密运算由 sm-crypto(MIT 协议)提供,已按 GM/T 0004、GM/T 0002 的标准测试向量逐条校验。