2. 国密算法概述:SM2、SM3、SM4 标准解读

各位同学,今天我们来聊聊国密算法的三驾马车——SM2、SM3、SM4。说实话,我刚接触国密那会儿,第一反应是“这不就是 RSA 和 AES 的国产版吗?”后来踩了几个坑才明白,事情没那么简单。

国密算法不是简单地把国际算法换了个名字。它在设计理念、安全强度、实现细节上都有自己的考量。尤其当你要把它塞进 TrustZone 这种安全环境时,理解这些细节就变得至关重要。

2.1 SM2 椭圆曲线公钥密码算法

SM2 是我国发布的椭圆曲线公钥密码算法标准(GM/T 0003-2012)。它包含三个部分:数字签名算法、密钥交换协议、公钥加密算法。说白了,就是一套完整的公钥密码体系。

核心要点:SM2 基于椭圆曲线离散对数难题,使用 256 位素数域上的椭圆曲线。与国际主流的 ECDSA 相比,SM2 在签名生成和验证流程上有明显差异。

我记得第一次在项目中实现 SM2 签名时,按照 ECDSA 的流程写代码,结果验签死活过不去。后来才发现,SM2 的签名值顺序是 (r, s),而 ECDSA 是 (r, s) 但计算方式不同——SM2 在签名中加入了用户标识 ZA,这是很多人容易忽略的点。

SM2 签名算法流程

  1. 预处理:计算 ZA = H256(ENTLA || IDA || a || b || xG || yG || xA || yA)
  2. 消息摘要:计算 e = H256(ZA || M)
  3. 生成随机数:k ∈ [1, n-1]
  4. 计算椭圆曲线点:(x1, y1) = [k]G
  5. 计算 r:r = (e + x1) mod n,若 r=0 或 r+k=n 则返回步骤 3
  6. 计算 s:s = ((1 + dA)^(-1) * (k - r * dA)) mod n,若 s=0 则返回步骤 3
  7. 输出签名:(r, s)

我的经验:SM2 的签名验证中,计算 t = (r + s) mod n 这一步很关键。如果 t=0,直接拒绝签名。我曾经在移植一个开源库时,发现它没做这个检查,差点酿成大祸。

SM2 与国际算法的对比

特性 SM2 ECDSA RSA-2048
密钥长度 256 位 256 位 2048 位
签名长度 64 字节 64 字节 256 字节
安全强度 128 位 128 位 112 位
用户标识参与 是 否 否
计算效率 高 高 低

你想想看,RSA 要 2048 位才能达到 112 位安全强度,而 SM2 用 256 位就能到 128 位。这就是椭圆曲线的优势。在 TrustZone 这种资源受限的环境中,SM2 的短密钥和高效计算显得尤为重要。

2.2 SM3 密码杂凑算法

SM3(GM/T 0004-2012)是一种密码杂凑算法,输出 256 位(32 字节)的杂凑值。它的设计思路与 SHA-256 类似,但做了不少改进。

核心要点:SM3 的消息分组长度为 512 位,采用 Merkle-Damgård 结构,压缩函数包含 64 轮迭代。它的安全强度与 SHA-256 相当,但在某些攻击场景下表现更优。

我个人习惯把 SM3 看作是“加强版 SHA-256”。为什么这么说?因为 SM3 的压缩函数使用了更多的布尔函数和置换操作,对差分攻击的抵抗能力更强。我在做安全审计时,发现有些产品用 SM3 替代 SHA-256 后,整体安全性反而提升了。

SM3 算法结构

输入:消息 M(长度 < 2^64 位)
输出:杂凑值 V(256 位)

1. 填充:在 M 后补 1 和若干 0,使长度 mod 512 = 448
2. 附加长度:在填充后附加 64 位长度表示
3. 初始化:设置 8 个 32 位寄存器 V0 = 7380166f... 
4. 迭代压缩:
   for each 512 位分组 B:
       扩展生成 132 个 32 位字 W0-W67, W'0-W'63
       压缩函数 CF(V, B)
       更新 V
5. 输出 V

避坑指南:我曾经在实现 SM3 时,把消息填充的字节序搞反了。SM3 采用大端序,而我的平台默认是小端序。结果算出来的杂凑值完全不对。调试了整整两天才发现这个问题。记住:国密算法基本都是大端序!

SM3 与 SHA-256 的差异

特性 SM3 SHA-256
输出长度 256 位 256 位
轮数 64 64
消息扩展 132 个字 64 个字
布尔函数 4 个(含 P0、P1 置换) 3 个
安全余量 更高 标准

嗯,这里要注意:SM3 的 64 轮迭代中,每轮使用的消息字是经过扩展的。这个扩展过程比 SHA-256 复杂,但也带来了更好的雪崩效应。说白了,就是输入稍微变一点,输出就会天翻地覆。

2.3 SM4 分组密码算法

SM4(GM/T 0002-2012)是我国的分组密码标准,分组长度 128 位,密钥长度 128 位。它采用非平衡 Feistel 结构,轮数为 32 轮。

核心要点:SM4 的加密和解密结构完全相同,只是轮密钥的使用顺序相反。这个特性在硬件实现中非常友好,可以复用同一套电路。

我记得第一次看 SM4 的 S 盒时,觉得它设计得很巧妙。SM4 的 S 盒是 8×8 的,基于仿射变换和逆映射构造。相比 AES 的 S 盒,SM4 的 S 盒在硬件实现上更紧凑,占用的逻辑门更少。

SM4 加密流程

输入:明文 (X0, X1, X2, X3),轮密钥 rk0-rk31
输出:密文 (Y0, Y1, Y2, Y3)

for i = 0 to 31:
    Xi+4 = Xi ⊕ T(Xi+1 ⊕ Xi+2 ⊕ Xi+3 ⊕ rki)

其中 T 函数 = L(τ(X))
τ:4 个 S 盒并行替换
L:线性变换 L(B) = B ⊕ (B <<< 2) ⊕ (B <<< 10) ⊕ (B <<< 18) ⊕ (B <<< 24)

最终输出 (Y0, Y1, Y2, Y3) = (X35, X34, X33, X32)

我的经验:SM4 的密钥扩展算法和加密算法结构相同,只是使用了不同的常数 FK 和 CK。这意味着你可以用同一套代码实现密钥扩展和加解密,减少代码量。在 TrustZone 的安全世界实现中,代码体积越小,攻击面就越小。

SM4 的工作模式

SM4 标准定义了多种工作模式,我建议在 TrustZone 环境中优先使用以下模式:

  • ECB 模式:简单但不安全,不推荐用于实际数据
  • CBC 模式:需要随机 IV,适合块数据加密
  • CTR 模式:可并行计算,适合流式数据
  • GCM 模式:提供认证加密,推荐用于安全通信

避坑指南:我曾经在一个项目中看到有人用 SM4-ECB 模式加密固件镜像。结果呢?因为固件头部有固定模式,攻击者通过统计就能推断出密钥。记住:永远不要用 ECB 模式加密结构化数据!

2.4 国密算法知识体系

下面这张图展示了 SM2、SM3、SM4 在国密体系中的位置和相互关系。你想想看,这三者组合起来,就能构建一套完整的密码应用方案。

国密算法知识体系 国密算法知识体系 国密算法标准体系 SM2 椭圆曲线公钥密码 SM3 密码杂凑算法 SM4 分组密码算法 数字签名 密钥交换 公钥加密 消息摘要 数据完整性 身份认证 数据加密 数据解密 密钥派生 三者组合可构建完整密码应用方案 SM2 密钥交换 + SM3 摘要 + SM4 加密 = 安全通信

从这张图可以看出,SM2 负责密钥交换和数字签名,SM3 提供完整性校验,SM4 完成数据加密。三者配合,就能构建一个完整的密码应用方案。在 TrustZone 环境中,我们通常把 SM2 的私钥和 SM4 的密钥存储在安全世界,SM3 用于校验数据的完整性。

2.5 国密算法在 TrustZone 中的选型建议

基于我在多个 TrustZone 项目中的经验,我给出以下选型建议:

  • 密钥协商:优先使用 SM2 密钥交换协议,避免直接传输 SM4 密钥
  • 数据完整性:使用 SM3 对关键数据进行杂凑校验
  • 数据加密:使用 SM4-GCM 模式,同时提供机密性和完整性保护
  • 数字签名:使用 SM2 签名算法,确保数据的不可否认性

我的建议:在 TrustZone 的安全世界实现国密算法时,尽量使用硬件加速器。如果硬件不支持,优先实现 SM4 的软件优化版本,因为 SM4 的计算量最大。SM2 的椭圆曲线运算可以考虑使用 Montgomery 乘法加速。