2. 国密算法基础:SM2、SM3、SM4

各位同学,咱们今天聊聊国密算法的三大支柱。说实话,我在做安全启动方案时,最常打交道的就这三个算法:SM2、SM3、SM4。它们分别对应了公钥密码、哈希函数和对称密码,缺一个都不行。

你想想看,一个完整的嵌入式安全启动流程,需要签名验签、完整性校验、数据加密解密。这三个算法正好各司其职。我个人习惯把这三者比作“钥匙、指纹、保险箱”——SM2是钥匙,SM3是指纹,SM4是保险箱。下面咱们一个一个拆开讲。

核心认知: 国密算法不是简单的“国产版AES/RSA/SHA”,它们在设计上有很多独特考量。SM2基于椭圆曲线,SM3有独特的消息扩展,SM4的S盒设计也很有讲究。理解这些差异,才能真正用好它们。
国密算法三大支柱关系图 国密算法三大支柱 安全启动应用 SM2 椭圆曲线 公钥密码 / 签名验签 SM3 密码杂凑 完整性校验 / 摘要 SM4 分组密码 数据加密 / 解密 三者协同工作流程 SM3 计算镜像摘要 → SM2 签名 → 启动时 SM2 验签 → SM4 解密固件 任何一个环节出问题,安全启动都会失败

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

SM2 是国密标准中的公钥密码算法,基于椭圆曲线密码学(ECC)。说白了,它跟国际上的 ECDSA、ECDH 是同类,但曲线参数是咱们自己定义的。

我记得第一次在嵌入式芯片上移植 SM2 时,踩了个大坑——椭圆曲线点乘运算太慢了。后来发现是模逆运算没优化好。嗯,这里要注意,SM2 的推荐曲线是 256 位的素域曲线,参数如下:

参数 值 说明
p FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF 素域模数
a FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFC 曲线系数
b 28E9FA9E 9D9F5E34 4D5A9E4B CF6509A7 F39789F5 15AB8F92 DDBCBD41 4D940E93 曲线系数
n FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF 7203DF6B 21C6052B 53BBF409 39D54123 基点阶
Gx 32C4AE2C 1F198119 5F990446 6A39C994 8FE30BBF F2660BE1 715A4589 334C74C7 基点 x 坐标
Gy BC3736A2 F4F6779C 59BDCEE3 6B692153 D0A9877C C62A4740 02DF32E5 2139F0A0 基点 y 坐标

SM2 的核心操作包括:密钥生成、签名、验签、加密、解密。在安全启动场景中,我们最常用的是签名和验签。流程大致是这样的:

  1. 密钥生成: 随机选取私钥 d,计算公钥 P = d * G
  2. 签名: 对消息 M 的哈希值进行签名,输出 (r, s) 对
  3. 验签: 用公钥 P 验证 (r, s) 是否匹配消息 M
实战经验: 我在做安全启动时,SM2 私钥通常存储在芯片的 OTP(一次性可编程)区域或安全元件中。公钥可以放在固件头部,但一定要用硬件熔丝保护,防止被篡改。曾经有个项目,客户把私钥放在 Flash 里,结果被逆向出来了……嗯,那场面,你懂的。

2.2 SM3:密码杂凑算法

SM3 是国密标准的哈希算法,输出 256 位摘要。它的设计思路跟 SHA-256 类似,但消息扩展和压缩函数有自己的一套。

我个人觉得 SM3 最值得关注的是它的消息扩展部分——它将 16 个字的消息扩展成 68 个字,再用 64 轮压缩函数处理。这种设计让 SM3 的抗碰撞能力很强。

SM3 的算法流程可以概括为:

输入:消息 M(任意长度)
输出:256 位摘要值

1. 消息填充:在 M 末尾补 1 和若干个 0,最后 64 位放原始长度
2. 分组处理:每 512 位(16 个字)为一组
3. 消息扩展:16 个字 → 68 个字(W0~W67)+ 64 个字(W'0~W'63)
4. 压缩函数:64 轮迭代,每轮用 Wj 和 W'j 更新 8 个状态字
5. 输出:8 个状态字拼接成 256 位摘要

在安全启动中,SM3 的典型用途是计算固件镜像的哈希值。比如,我们先把整个固件镜像用 SM3 算一遍,得到一个 256 位的摘要,然后用 SM2 对这个摘要签名。启动时,BootROM 先算镜像的 SM3 摘要,再用 SM2 验签。这样就能保证固件没有被篡改过。

避坑指南: 我曾经遇到过一个案例,开发者在计算 SM3 时忘了对消息进行填充,直接拿原始数据算哈希。结果验签死活过不了。查了两天才发现是填充逻辑写错了。记住:SM3 的输入必须是经过标准填充的完整消息块,不能偷懒。

2.3 SM4:分组密码算法

SM4 是国密标准的对称分组密码算法,分组长度 128 位,密钥长度 128 位。它采用 32 轮 Feistel 结构,每轮用一个 32 位的轮密钥。

说实话,SM4 的设计很精巧。它的 S 盒只有 256 个元素,但非线性度很高。密钥扩展算法也很有意思——它用跟加密相同的结构来生成轮密钥,只是常数不同。

SM4 的加密流程:

输入:128 位明文 (X0, X1, X2, X3)
输出:128 位密文 (Y0, Y1, Y2, Y3)

1. 密钥扩展:128 位密钥 → 32 个 32 位轮密钥 (rk0~rk31)
2. 32 轮迭代:
   for i = 0 to 31:
       Xi+4 = Xi XOR T(Xi+1 XOR Xi+2 XOR Xi+3 XOR rki)
3. 反序变换:
   (Y0, Y1, Y2, Y3) = (X35, X34, X33, X32)

在安全启动中,SM4 通常用于加密固件镜像。比如,固件在工厂烧录时用 SM4 加密,启动时 BootROM 用预置的密钥解密。这样即使有人读出了 Flash 里的数据,也拿不到明文固件。

工作模式 适用场景 注意事项
ECB 单块数据加密 相同明文块产生相同密文块,不推荐用于固件加密
CBC 固件镜像加密 需要 IV,IV 可以放在固件头部
CTR 流式加密 可以并行计算,适合高性能场景
GCM 加密+认证 同时提供机密性和完整性,推荐用于安全启动
我的建议: 在安全启动场景中,我强烈推荐使用 SM4-GCM 模式。它不仅能加密数据,还能提供认证标签,防止密文被篡改。曾经有个项目,客户用 SM4-CBC 加密固件,结果攻击者通过修改密文块来触发缓冲区溢出……嗯,从那以后,我所有项目都强制要求用 GCM 模式。

2.4 三种算法的协同关系

好了,三个算法都讲完了。你可能会问:安全启动中它们怎么配合?

我画个简单的流程:

  1. 固件打包阶段: 用 SM3 计算固件镜像的摘要 → 用 SM2 私钥对摘要签名 → 用 SM4 加密固件镜像
  2. 启动验证阶段: BootROM 用 SM4 解密固件 → 用 SM3 计算解密后固件的摘要 → 用 SM2 公钥验签

这个流程中,SM3 保证完整性,SM2 保证真实性,SM4 保证机密性。三者缺一不可。

关键点: 安全启动的强度取决于最薄弱的环节。如果 SM2 私钥泄露,整个安全体系就崩了。如果 SM4 密钥被提取,固件内容就暴露了。所以,密钥管理才是安全启动的核心——算法只是工具。

嗯,这一章的内容就到这里。记住这三个算法的核心参数和适用场景,后面讲安全启动架构时,我们会反复用到它们。