4、密码学基础:哈希算法(SHA-256)、非对称加密(RSA/ECC)、数字签名、密钥管理基础
Secure Boot 的信任根建立与链式校验机制,本质上是一套精心设计的密码学协议。在 MCU 资源受限的背景下,理解哈希、非对称加密、数字签名与密钥管理的数学原理和工程约束,是进行移植与配置的前提。本章将聚焦这四大核心模块,从算法本质到 MCU 上的工程落地,建立完整的密码学知识框架。
4.1 哈希算法 SHA-256:完整性校验的基石
4.1.1 核心原理与数学特性
SHA-256(Secure Hash Algorithm 256-bit)是 SHA-2 家族的一员,由美国国家安全局(NSA)设计,并于 2001 年由 NIST 发布为 FIPS PUB 180-4 标准。它将任意长度的输入消息,经过填充、分块、压缩函数迭代等步骤,输出固定 256 位(32 字节)的摘要值。其核心安全属性包括:
- 抗原像性(Preimage Resistance):给定摘要值 y,找到满足 H(x)=y 的输入 x 在计算上不可行。这意味着攻击者无法从哈希值反推出原始固件内容。
- 抗第二原像性(Second Preimage Resistance):给定输入 x₁,找到另一个输入 x₂(x₁≠x₂)使得 H(x₁)=H(x₂) 在计算上不可行。这防止攻击者用恶意固件替换合法固件而不改变哈希值。
- 抗碰撞性(Collision Resistance):找到任意两个不同的输入 x₁ 和 x₂ 使得 H(x₁)=H(x₂) 在计算上不可行。虽然理论上存在碰撞,但 SHA-256 的碰撞复杂度为 2^128,在当前算力下不可实现。
在 MCU 的 Secure Boot 场景中,SHA-256 主要用于两个关键环节:一是对固件镜像进行哈希计算,生成摘要值用于签名;二是在启动时重新计算固件哈希,与解密后的摘要值进行比对,以验证固件在传输或存储过程中是否被篡改。
4.1.2 MCU 上的实现方式与性能考量
在资源受限的 MCU 上实现 SHA-256,通常有三种途径:
| 实现方式 | 典型吞吐量 | 代码/资源占用 | 适用场景 |
|---|---|---|---|
| 纯软件实现(C语言) | 5-20 MB/s(Cortex-M4 @ 100MHz) | 约 2-4 KB Flash,256B RAM | 低成本 MCU,无硬件加速器 |
| 硬件加速器(SHA Engine) | 50-200 MB/s | 寄存器配置,DMA 支持 | 中高端 MCU(如 STM32L5、NXP i.MX RT) |
| 指令集加速(如 ARMv8-M SHA 扩展) | 30-80 MB/s | 专用指令,减少循环开销 | ARMv8-M 架构 MCU |
对于 1MB 的固件镜像,纯软件实现大约需要 50-200ms(取决于主频),而硬件加速器可将时间缩短至 5-20ms。在启动时间敏感的工业控制或汽车电子场景中,硬件加速几乎是必须的。
4.1.3 实战场景:固件完整性校验流程
假设我们使用 STM32L552(Cortex-M33,带硬件 SHA-256 加速器)进行 Secure Boot 设计。启动流程中的哈希校验环节如下:
- BootROM 从固定地址读取固件头部信息,获取固件长度、版本号、签名偏移量等元数据。
- 配置 SHA 硬件外设,设置输入数据源为 Flash 中的固件区域,输出为 32 字节摘要。
- 启动 DMA 传输,将固件数据流式送入 SHA 引擎,避免 CPU 逐字节搬运。
- 计算完成后,将硬件生成的摘要与固件头中存储的参考摘要进行常量时间比较(防止时序攻击)。
- 若匹配,则继续执行签名验证;若不匹配,则进入错误处理流程(如 LED 指示、进入恢复模式)。
4.2 非对称加密:RSA 与 ECC 的工程选型
4.2.1 RSA 算法原理与参数选择
RSA 的安全性基于大整数分解的困难性。其密钥生成过程为:选择两个大素数 p 和 q,计算 n=p×q,选取公钥指数 e(通常为 65537),计算私钥 d 满足 e×d ≡ 1 (mod φ(n))。公钥为 (n, e),私钥为 (n, d)。
在 MCU 上使用 RSA 进行签名验证时,通常采用 RSA2048 或 RSA3072。RSA2048 的模数长度为 2048 位(256 字节),签名验证需要进行一次模幂运算,即计算 m^e mod n。虽然公钥指数 e=65537 只有 17 位,但模幂运算仍需要约 300-500ms(Cortex-M4 @ 100MHz,无硬件加速)。
RSA 的优点是算法成熟、实现简单、公钥短小(256 字节),适合在资源极受限的 BootROM 中硬编码公钥。缺点是签名验证速度慢,且密钥生成需要大素数筛选,不适合在 MCU 上动态生成密钥对。
4.2.2 ECC 算法原理与曲线选择
椭圆曲线密码学(ECC)的安全性基于椭圆曲线离散对数问题(ECDLP)。在相同的安全强度下,ECC 的密钥长度远短于 RSA。例如,256 位 ECC(如 secp256r1/P-256)提供与 3072 位 RSA 相当的安全性。
ECC 的签名算法通常使用 ECDSA(Elliptic Curve Digital Signature Algorithm)。签名过程涉及标量乘法 k×G,验证过程涉及两个标量乘法。在 MCU 上,P-256 曲线的签名验证时间约为 50-150ms(Cortex-M4 @ 100MHz),比 RSA2048 快 3-5 倍。
ECC 的工程挑战在于:
- 侧信道防护:标量乘法需要采用固定时间算法(如 Montgomery Ladder),防止通过功耗分析提取私钥。
- 曲线参数验证:验证公钥时需检查点是否在曲线上,防止无效曲线攻击。
- 随机数质量:ECDSA 要求每次签名使用唯一的随机数 k,若 k 泄露或重复,私钥可被直接恢复。
4.2.3 案例拆解:RSA vs ECC 在车规 MCU 上的对比
某车规级 MCU(Cortex-R5F @ 200MHz)需要实现 Secure Boot,固件大小为 2MB,启动时间预算为 200ms。我们对比两种方案:
| 指标 | RSA2048 | ECC P-256 |
|---|---|---|
| 签名验证时间 | 约 180ms | 约 45ms |
| SHA-256 计算时间(2MB) | 约 20ms(硬件加速) | 约 20ms(硬件加速) |
| 公钥存储空间 | 256 字节 | 64 字节(x 坐标 + y 坐标) |
| 总启动时间 | 约 200ms(临界) | 约 65ms(充裕) |
| 代码复杂度 | 低(模幂运算) | 中(标量乘法 + 点运算) |
从结果看,ECC 在启动时间上具有明显优势,但需要更复杂的代码实现和更严格的侧信道防护。最终该方案选择了 ECC P-256,并配合硬件加密协处理器(支持 ECC 点运算)将验证时间进一步压缩至 15ms。
4.3 数字签名:从理论到固件验证
4.3.1 签名生成与验证的完整流程
数字签名结合了哈希算法和非对称加密,提供真实性、完整性和不可否认性。在 Secure Boot 场景中,签名由开发服务器(离线)生成,验证在 MCU 上执行。流程如下:
- 签名生成(开发环境):计算固件镜像的 SHA-256 摘要 H(m);使用私钥对摘要进行签名,得到签名值 S = Sign_priv(H(m));将 S 附加到固件镜像中,生成带签名的固件包。
- 签名验证(MCU 启动):读取固件镜像,计算 SHA-256 摘要 H'(m);使用公钥验证签名,即验证 Verify_pub(S, H'(m)) 是否通过;若通过,则固件未被篡改且来源可信。
对于 RSA,签名验证实质上是计算 S^e mod n,并与 H'(m) 比较。对于 ECDSA,验证涉及计算 u₁×G + u₂×Q(其中 Q 为公钥点),并比较结果点的 x 坐标与签名中的 r 值。
4.3.2 签名方案的安全增强:哈希截断与填充
在实际工程中,直接对摘要进行签名存在理论风险(如长度扩展攻击)。因此,标准方案使用 RSA-PSS(Probabilistic Signature Scheme)或 ECDSA 的标准流程。RSA-PSS 引入了随机盐值,使得相同消息在不同签名下产生不同签名值,增强了安全性。在 MCU 上实现时,需要注意:
- RSA-PSS 需要额外的编码/解码逻辑,代码量增加约 1-2KB。
- ECDSA 的签名值由 (r, s) 两个 32 字节整数组成,共 64 字节,比 RSA2048 的 256 字节签名短得多。
- 验证时需检查签名值是否在有效范围内(如 r, s ∈ [1, n-1]),防止伪造签名。
4.3.3 实战场景:多级签名链的验证顺序
在复杂的 Secure Boot 架构中,通常存在多级引导:BootROM → 一级引导加载器(SPL)→ 主固件。每一级都需要验证下一级的签名。签名链如下:
BootROM (信任根)
└─ 验证 SPL 的签名 (使用 SPL 公钥)
└─ SPL 验证主固件的签名 (使用主固件公钥)
└─ 主固件运行
这种链式验证的优点是:即使主固件被攻破,攻击者也无法伪造 SPL,因为 SPL 的签名由 BootROM 中的根公钥验证。但需要注意:
- 每一级验证都会增加启动时间,需合理分配各级的算法选择(如 BootROM 使用 ECC,SPL 使用 RSA)。
- 公钥的存储位置应逐级隔离:根公钥存储在 OTP/eFuse 中,SPL 公钥存储在 SPL 固件中,主固件公钥存储在主固件头中。
- 如果某一级验证失败,应进入安全恢复模式,而不是继续执行。
4.4 密钥管理基础:信任根的建立与保护
4.4.1 密钥生命周期与存储介质
密钥管理是 Secure Boot 安全性的最终保障。即使算法再强,如果私钥泄露或公钥被替换,整个信任链将崩溃。密钥生命周期包括:生成、分发、存储、使用、轮换、撤销、销毁。
在 MCU 上,密钥存储介质的选择至关重要:
| 存储介质 | 容量 | 可写性 | 安全性 | 典型用途 |
|---|---|---|---|---|
| OTP (One-Time Programmable) | 1-8 KB | 仅一次写入 | 高(物理不可复制) | 根公钥哈希、设备唯一密钥 |
| eFuse | 1-4 KB | 可多次烧写(有限次) | 高 | 安全启动配置、密钥版本号 |
| Flash 安全区域 | 16-64 KB | 可擦写 | 中(依赖 Flash 保护) | 应用固件密钥、更新密钥 |
| 外部安全芯片(如 ATECC608) | 16 KB | 硬件保护 | 极高 | 高安全场景的密钥托管 |
根公钥通常以哈希值形式存储在 OTP 中。BootROM 在启动时计算待加载公钥的 SHA-256,与 OTP 中的哈希比对,若匹配则信任该公钥。这种方式允许公钥存储在 Flash 中(便于更新),但哈希值锁定在 OTP 中,防止攻击者替换公钥。
4.4.2 密钥轮换与版本回滚防护
密钥轮换是应对密钥泄露或算法弱化的必要手段。在 Secure Boot 中,密钥轮换需要谨慎设计,因为一旦新密钥不被旧 BootROM 信任,设备将变砖。常见的策略包括:
- 密钥版本号:在固件头中增加密钥版本字段,BootROM 比较版本号,只允许加载版本号 ≥ 当前版本的固件。
- 密钥撤销列表:在 OTP 中维护已撤销的密钥 ID 列表,BootROM 在验证前检查。
- 双密钥槽位:预留两个密钥槽位,当前密钥验证失败时尝试备用密钥,实现无缝切换。
4.4.3 案例拆解:基于 eFuse 的密钥管理方案
某物联网 MCU 产品需要支持远程固件更新,同时防止攻击者回滚到旧版本固件(利用已知漏洞)。设计方案如下:
- 初始烧录:在工厂烧录时,将根公钥哈希(32 字节)写入 eFuse 区域 0,将密钥版本号初始化为 1。
- 固件更新:新固件使用新私钥签名,固件头中包含密钥版本号 2。BootROM 验证签名前,先检查版本号 ≥ eFuse 中的当前版本。
- 版本升级:验证通过后,BootROM 将 eFuse 中的版本号更新为 2。此时旧固件(版本号 1)将无法通过版本检查。
- 密钥轮换:当需要更换密钥时,新公钥的哈希写入 eFuse 区域 1,同时将版本号递增。BootROM 优先使用区域 1 的公钥,若验证失败则回退到区域 0。
该方案的代价是 eFuse 空间占用(2×32 字节 + 版本号),以及每次更新需要烧写 eFuse 的时间(约 10ms)。但换取了防回滚和密钥轮换能力,适用于安全要求较高的产品。
4.4.4 常见误区与总结复盘
在密钥管理实践中,以下误区需要特别注意:
- 私钥存储在 MCU 中:Secure Boot 只需要公钥验证签名,私钥应始终保存在开发服务器或 HSM 中。如果 MCU 中存储了私钥,攻击者可通过调试接口提取。
- 忽略调试接口保护:即使 Secure Boot 验证通过,如果 JTAG/SWD 接口未锁定,攻击者仍可读取 Flash 内容或篡改内存。必须同时启用调试接口保护(如 RDP Level 2)。
- 随机数生成器质量不足:ECDSA 签名需要高质量随机数。如果 MCU 的 TRNG 未正确初始化或熵源不足,可能导致签名密钥泄露。建议使用硬件 TRNG + 软件去偏。
- 忽视侧信道攻击:在验证签名时,如果模幂运算或标量乘法的时间依赖于密钥或消息,攻击者可通过功耗分析提取信息。应使用固定时间算法或硬件加速器。