3. 国密算法与安全启动的结合:SM2、SM3、SM4 各司其职
安全启动的核心逻辑其实不复杂——就是确保你跑的第一行代码是可信的,并且后续每一级代码都经过验证。但具体怎么落地?这就得靠国密算法来撑场面了。
我个人习惯把安全启动拆成三个关键动作:验身份、量完整性、保机密。正好对应 SM2、SM3、SM4 三套算法。你想想看,这三件事要是做扎实了,攻击者基本就没什么空子可钻了。
3.1 三套算法在安全启动中的角色划分
先给个全景图。我做过好几个安全启动方案,每次画这张表给团队看,大家一下就明白了:
| 算法 | 核心用途 | 安全启动中的角色 | 典型场景 |
|---|---|---|---|
| SM2 | 公钥密码(签名/验签) | 身份认证与签名验证 | BootROM 验签 Bootloader 签名 |
| SM3 | 密码杂凑(哈希) | 完整性度量与摘要生成 | 度量内核镜像的哈希值 |
| SM4 | 对称分组密码 | 加密存储与机密性保护 | 加密固件分区或敏感配置 |
说白了,SM2 负责「你是谁」,SM3 负责「你有没有被改过」,SM4 负责「别人看不懂」。三缺一,安全启动就不完整。
3.2 SM2:签名验证——信任链的起点
安全启动的第一步,通常是从 BootROM 开始验证 Bootloader 的签名。这一步用的是 SM2 数字签名算法。
我记得第一次在 ARM Cortex-M 平台上移植 SM2 验签逻辑时,踩了个坑——SM2 的签名结果是一个 (r, s) 对,总共 64 字节。但有些芯片的 OTP 区域只给了 32 字节存公钥,导致我不得不重新规划密钥存储布局。
SM2 验签流程(简化版):
- BootROM 从固定地址读取 SM2 公钥(通常烧录在 OTP/eFuse 中)
- 读取 Bootloader 镜像和其附带的 SM2 签名值
(r, s) - 计算镜像的 SM3 摘要
e = SM3(image) - 使用公钥验证
(r, s)是否是对摘要e的有效签名 - 验签通过则跳转执行,否则进入恢复模式或死循环
这里有个关键点:公钥的完整性必须由硬件保证。如果公钥本身能被篡改,那整个信任链就崩塌了。我建议把 SM2 公钥的哈希值也锁在 eFuse 里,启动时先自检公钥是否被改过。
避坑指南:我曾经在一个项目里发现,SM2 验签的随机数生成器如果不够随机,攻击者可以通过侧信道攻击恢复私钥。所以,务必使用硬件 TRNG(真随机数发生器)来生成 SM2 签名时的随机数 k,别用软件伪随机。
3.3 SM3:完整性度量——确保代码没被动过手脚
SM3 在安全启动里干的是「脏活累活」——它要度量每一级镜像的完整性。从 Bootloader 到内核,再到文件系统,每一层都要算一遍哈希。
你可能会问:「SM2 验签的时候不是已经算过 SM3 了吗?」没错,但 SM3 的用途不止于此。在安全启动的后续阶段,比如加载内核模块或动态库时,我们通常不会每次都做 SM2 验签(太慢了),而是用 SM3 算个摘要,跟之前保存的「黄金摘要」比对一下。
我的经验:SM3 的输出是 32 字节(256 位),这个长度在嵌入式场景下非常友好。我习惯把关键镜像的 SM3 摘要存放在一个独立的、只读的安全存储区(比如另一个 eFuse 区域或安全 Flash 分区),启动时逐级比对。
SM3 还有一个容易被忽视的作用——防回滚。通过度量版本号的哈希值,可以防止攻击者把系统降级到有漏洞的旧版本。嗯,这里要注意,版本号本身也要参与 SM3 计算,不能只度量镜像内容。
3.4 SM4:加密存储——保护敏感数据
SM4 在安全启动里主要负责「锁柜子」。比如,有些设备的文件系统是加密的,密钥由安全启动流程派生出来。SM4 的加解密速度比 SM2 快得多,适合处理大量数据。
我参与过一个车机项目,要求把导航地图数据和用户配置文件用 SM4 加密存储。启动时,Bootloader 先验签,然后由内核从安全硬件中读取 SM4 密钥,解密文件系统。这样即使攻击者把 Flash 拆下来读,也拿不到明文数据。
SM4 的密钥管理是个大学问。我个人不建议把 SM4 密钥直接硬编码在代码里,而是应该通过安全启动的信任链来派生:
// 伪代码:SM4 密钥派生流程
// 1. BootROM 使用芯片唯一 ID 和 SM3 生成根密钥
root_key = SM3(chip_unique_id || secret_salt)
// 2. 使用 SM4 解密 Bootloader 的密钥密文
boot_key = SM4_decrypt(root_key, encrypted_boot_key)
// 3. 后续各级密钥依次派生
kernel_key = SM4_decrypt(boot_key, encrypted_kernel_key)
这样,每一级的密钥都只在前一级的上下文中可用,攻击者拿到任何一级的镜像都无法直接获取下一级的密钥。
3.5 三算法协同:安全启动的完整流程
光说单个算法不过瘾,咱们把三套算法串起来,看看一个典型的安全启动流程长什么样。下面这张图是我在多个项目中反复打磨出来的架构:
这张图里,信任链从左到右逐级传递。每一级只信任上一级的验签结果,然后用自己的能力保护下一级。SM2 是「守门员」,SM3 是「巡检员」,SM4 是「保管员」。
3.6 实际项目中的选型建议
最后聊点实在的。如果你正在设计一个安全启动方案,我建议你根据芯片资源做取舍:
- 资源受限的 MCU(比如 Cortex-M0+,几十 KB Flash):优先保证 SM2 验签和 SM3 度量。SM4 加密存储可以放到后面,或者只加密最关键的分区。我曾经在一个 32KB Flash 的芯片上硬塞进了 SM2 验签逻辑,代价是砍掉了 SM4 解密模块。
- 中高端应用处理器(比如 Cortex-A 系列):三套算法全上。SM2 用于 BootROM 验签,SM3 用于内核模块度量,SM4 用于文件系统加密。还可以考虑用 SM4 的 GCM 模式,同时提供加密和完整性校验。
- 车规或工业场景:除了三套算法,还要考虑安全存储(HSM 或 TEE)和防侧信道攻击。SM2 的签名时间如果波动太大,可能会被时序攻击利用。
一句话总结:SM2 建信任,SM3 保完整,SM4 守机密。三剑合璧,安全启动才能站得住脚。