国密算法核心原理:SM2、SM3、SM4

做国密 SSL 传输加密,绕不开这三驾马车。我个人习惯把国密算法分成三类来看:非对称、杂凑、对称。

SM2 管密钥协商和数字签名,SM3 管数据完整性,SM4 管数据加密。说白了——SSL 握手靠 SM2,握手通信用 SM4,中间任何篡改由 SM3 揪出来。

一句话理解:SM2 解决「你是谁」和「密钥怎么安全抵达」,SM3 解决「数据有没有被改过」,SM4 解决「数据只有你能看」。
国密算法核心关系图 SM2 / SM3 / SM4 在 SSL 传输加密中的角色 SM2 椭圆曲线公钥密码 密钥协商(密钥交换) 数字签名 & 验签 公钥加密(少量数据) 椭圆曲线点加 / 倍点 素域 Fp / 二进制域 密钥长度 256 比特 签名长度约 512 比特 ECC 安全性等价于 RSA-3072 SM3 密码杂凑算法 数据完整性校验 消息摘要 / 指纹 HMAC-SM3 消息认证码 填充 + 迭代压缩 64 步迭代 输出长度 256 比特 与 SHA-256 输出等长 国密 SSL 中用于证书摘要 SM4 分组密码算法 数据加解密 分组长度 128 比特 密钥长度 128 比特 32 轮非线性迭代 S 盒 + 线性变换 支持 ECB / CBC / CTR / GCM 国标 GM/T 0002 SSL 记录层加密首选 SM2 签名中 对摘要签名 SM4 加密前 计算消息摘要 SM2 协商出的对称密钥用于 SM4 加密
💡 我的习惯:画这种图帮你理清算法关系。SM2 管密钥分发,SM3 管签名摘要,SM4 管数据体。三者配合,才算一套完整的 SSL 加密通道。

SM2:椭圆曲线公钥密码

SM2 基于椭圆曲线上的离散对数难题。它比 RSA 更「省力气」——256 比特的密钥,能达到 RSA-3072 的安全强度。

我在项目里常见 SM2 用在两个场景:

  • 密钥协商:SSL 握手阶段,客户端和服务端各自生成临时 SM2 密钥对,通过交换公钥与各自的私钥算出一个共享秘密。具体流程叫 ECKA(基于椭圆曲线的密钥协商),和 ECDH 思路类似。
  • 数字签名:对 SM3 摘要签名。签名结果是一对整数 (r, s)。验签时用公钥算出 (x1, y1) 再恢复 r' 比较。

SM2 在 SSL 中主要做密钥协商。它不加密大量数据——公钥加密效率低,而且有密钥长度的限制,只能加密很短的消息。所以我们用它来「交换密钥」,真正的数据加密交给 SM4。

参数SM2RSA-2048
密钥长度256 比特2048 比特
签名长度约 512 比特2048 比特
签名速度快(ECC 点乘)慢(大数模幂)
验签速度快较快
密钥生成速度极快慢
避坑:SM2 密钥对必须使用安全随机数生成器。我曾经见过有人用伪随机种子生成 SM2 私钥,结果每次重启服务器得到相同密钥对——握手直接暴露。

SM3:密码杂凑算法

SM3 输出 256 比特(32 字节)的摘要。它和 SHA-256 结构很像,都用了 Merkle–Damgård 迭代结构,但在细节上有差异:

  • 消息分组 512 比特,填充方式与 SHA-256 类似
  • 64 步迭代压缩,每步 16 个字
  • 初始值 IV 与 SHA-256 不同
  • 压缩函数中的布尔函数和移位操作有区别

说白了,SM3 是国标自己设计的,不是 SHA-256 的拷贝。安全强度也达到了 128 比特。做 SSL 时,SM3 用于:

  • 证书签名摘要(对证书 DER 编码做 SM3 摘要,再用 SM2 签名)
  • HMAC-SM3 用于消息认证码(有些国密 SSL 库支持)
  • 密钥派生函数中的散列步骤
经验:我曾经在对接某国产密码机时,遇到 SM3 输出的摘要顺序问题和 HMAC 的 inner/outer padding 字节序不匹配。后来发现是平台大小端不同。建议写代码时统一用大端表示法,国密标准都是大端。

SM4:分组密码算法

SM4 是国标的分组密码,也叫 SMS4。它和 AES 一样是 128 比特分组、128 比特密钥,但内部结构完全不同:

  • 32 轮非线性迭代(AES 是 10 轮)
  • S 盒固定 8x8(AES 是 16x16)
  • 加解密结构完全对称(解密是加密的逆过程,使用相同的轮密钥顺序相反)

SM4 在 SSL 中用于记录层加密。握手完成后,双方用 SM4 加密传输的应用数据。支持的模式有:

  • ECB:不推荐,明文模式容易泄露模式
  • CBC:需要 IV,有填充,必须配合 HMAC 保证完整性
  • CTR:流密码模式,不需要填充,效率高
  • GCM:认证加密模式,同时保证机密性和完整性——我个人最推荐。
⚠️ 重要:国密 SSL 在记录层一般使用 SM4-GCM 或者 SM4-CBC + SM3-HMAC。GCM 模式自带认证标签,不需要额外 HMAC,但需要硬件支持加解密和 GHASH。如果你的密码机不支持 GCM,可以退而使用 CBC + HMAC,但要注意:先加密后 HMAC,不要反过来。

SM2 / SM3 / SM4 的协同工作

一个典型的国密 SSL 握手过程:

  1. 客户端和服务端交换 SM2 公钥证书
  2. 使用 SM2 密钥协商(ECKA)生成共享秘密
  3. 通过密钥派生函数(KDF,内部使用 SM3)派生出 SM4 的会话密钥
  4. 后续所有应用数据使用 SM4 加密,并对关键数据(如 Finished 消息)使用 SM3 计算摘要

你看,三个算法一个都不能少。我遇到过不少初学者只关注 SM4 加解密,忘了 SM2 的密钥协商和 SM3 的完整性校验,结果握手能通但安全强度大打折扣。

// C 伪代码:国密 SSL 密钥协商后派生会话密钥
// SM2 协商出共享秘密 Z,长度视曲线而定
byte Z[32]; // 256-bit 椭圆曲线共享秘密
// 使用 SM3 计算密钥派生
byte K[16]; // SM4 128-bit 密钥
KDF_SM3(Z, 32, "TLS1.3-GM", &K, 16);
// 派生出的 K 用于 SM4 加密
SM4_set_key(&key, K);
SM4_GCM_encrypt(plaintext, key, nonce, aad, ciphertext, tag);
📌 小提醒:KDF 的输入字符串(比如 "TLS1.3-GM")是国密 SSL 协议协商时双方约定好的。如果你自定义协议,注意使用固定的、不会产生歧义的字符串,防止不同实体派生出不同密钥。

好了,核心算法的原理先聊到这儿。接下来在实际的密钥边界设计中,你要不断回到这三个算法的基础上去思考——密钥怎么协商、怎么派生、怎么加密。搞懂它们,后面的边界设计才立得住。