3、安全启动与密钥管理:基于TrustZone的硬件信任根、安全启动链、密钥派生与存储策略

安全启动和密钥管理,说白了就是给设备办一张「出生证明」和「身份证」。没有这两样东西,你的国密算法再强,也架不住别人从根上把你替换掉。我在做金融终端安全方案时,见过太多「算法很强、密钥裸奔」的案例——SM4加密做得滴水不漏,结果根密钥直接明文躺在Flash里。嗯,这就像给保险柜装了顶级锁,却把钥匙挂在门上。

TrustZone的价值就在这里:它能把信任根和密钥管理锁进安全世界,让普通世界连碰都碰不到。今天我们就来拆解这套机制。

3.1 硬件信任根:一切信任的起点

信任根(Root of Trust, RoT)是安全启动的基石。它必须是一个不可篡改、物理隔离的实体。在TrustZone架构中,这个角色通常由以下几部分承担:

  • BootROM:芯片出厂时固化在只读存储器中的代码,是信任链的第一环。它不可更改,物理上无法被覆盖。
  • OTP(一次性可编程存储器):用于存储芯片唯一身份、根密钥哈希、安全配置等。写入后永久锁定。
  • 安全世界的中断向量表:确保安全世界代码入口不被普通世界劫持。

核心原则:信任根必须满足「三不」——不可读、不可写、不可绕过。BootROM是硬件固化的,OTP是一次性写入的,安全世界入口是Monitor模式强制路由的。这三者缺一不可。

我个人习惯把信任根比作「芯片的DNA」。它从出厂那一刻就决定了这个设备是否可信。我在一个IoT门锁项目里遇到过这样的坑:某厂商为了省成本,把根密钥存在外部SPI Flash里,结果被物理攻击直接读出。后来我们改用OTP存储根密钥哈希,配合TrustZone的隔离,才彻底堵住这个漏洞。

3.2 安全启动链:逐级验证,层层递进

安全启动不是一步到位的,而是一个链式验证过程。每一级在加载下一级之前,都要先验证它的签名或哈希。一旦某级验证失败,启动立即终止。

典型的TrustZone安全启动链如下:

  1. BootROM:上电后最先执行。它读取OTP中的根公钥哈希,验证下一级Bootloader(通常是BL1)的签名。
  2. BL1(一级Bootloader):运行在安全世界SRAM中。它负责初始化DRAM,验证BL2的镜像。
  3. BL2(二级Bootloader):运行在安全世界DRAM中。它加载并验证安全世界固件(如OP-TEE)和普通世界Bootloader(如U-Boot)。
  4. 安全世界固件(OP-TEE/Trusted Firmware):提供安全服务,管理安全存储,执行国密运算。
  5. 普通世界Bootloader & OS:启动Linux或其它富操作系统。

为什么会这样设计?你想想看,如果BootROM直接加载整个OS,那BootROM的代码量会非常庞大,漏洞面也大。逐级验证的好处是:每一级只做最少的事,代码量小,容易审计,也容易做形式化验证。

避坑指南:我曾经在一个项目中,BL1和BL2共用同一套签名密钥。后来做安全审计时发现,如果BL1被逆向,攻击者就能用同一密钥签名恶意BL2。正确的做法是:每一级使用独立的密钥对,并且密钥的用途在OTP中明确限定。

下面这张图展示了完整的信任链传递过程:

基于TrustZone的安全启动信任链 BootROM(硬件固化) 验证BL1签名(使用OTP根公钥哈希) BL1(安全SRAM) 验证BL2签名(使用BL1密钥) BL2(安全DRAM) 验证安全固件 + 普通世界Bootloader 安全世界固件(OP-TEE) 普通世界OS(Linux) 每一级验证失败即停止启动,进入安全错误处理

3.3 密钥派生:从根密钥到业务密钥

有了信任根和安全启动,接下来就是密钥管理了。直接使用根密钥加密业务数据是极其危险的做法——一旦根密钥泄露,整个设备的安全体系就崩塌了。正确的做法是:通过密钥派生,生成不同用途的次级密钥。

在TrustZone安全世界中,我常用的密钥派生策略如下:

密钥层级 存储位置 派生方式 用途
根密钥(RK) OTP / eFuse 芯片出厂随机生成,不可导出 信任根,仅用于派生
设备密钥(DK) 安全存储(RPMB/安全文件) HKDF-SM3(RK, 设备ID, 上下文) 设备身份认证
加密密钥(EK) 安全存储(会话级) HKDF-SM3(DK, 应用ID, 随机数) 业务数据加密(SM4)
签名密钥(SK) 安全存储(持久化) HKDF-SM3(RK, 用途标签, 计数器) 固件签名、消息认证(SM2)

重要提醒:密钥派生必须使用国密标准的KDF算法。我推荐使用HKDF-SM3,它基于HMAC-SM3构建,符合GM/T 0005-2021标准。千万不要自己拼接哈希值,那很容易引入侧信道攻击。

这里有一个我在实际项目中用过的派生函数示例:

// 基于SM3的密钥派生函数(HKDF-SM3)
// 输入:根密钥root_key, 盐值salt, 上下文信息info, 输出长度len
// 输出:派生密钥derived_key
int derive_key_sm3(const uint8_t *root_key, size_t root_len,
                   const uint8_t *salt, size_t salt_len,
                   const uint8_t *info, size_t info_len,
                   uint8_t *derived_key, size_t len) {
    // 第1步:提取阶段(Extract)
    // 使用HMAC-SM3生成伪随机密钥PRK
    uint8_t prk[32]; // SM3输出32字节
    hmac_sm3(salt, salt_len, root_key, root_len, prk);
    
    // 第2步:扩展阶段(Expand)
    // 基于PRK生成所需长度的密钥
    uint8_t t[32];
    uint8_t counter = 1;
    size_t offset = 0;
    
    while (offset < len) {
        // T(i) = HMAC-SM3(PRK, T(i-1) || info || counter)
        hmac_sm3_update(prk, 32, t, offset);
        hmac_sm3_update(prk, 32, info, info_len);
        hmac_sm3_update(prk, 32, &counter, 1);
        hmac_sm3_final(prk, 32, t);
        
        size_t copy_len = (len - offset) > 32 ? 32 : (len - offset);
        memcpy(derived_key + offset, t, copy_len);
        offset += copy_len;
        counter++;
    }
    
    return 0;
}

3.4 密钥存储策略:安全世界的「保险柜」

密钥派生出来了,存在哪里?普通世界的文件系统肯定不行。TrustZone提供了几种安全存储方案:

  • RPMB(Replay Protected Memory Block):eMMC/UFS中的安全分区,具备重放保护。适合存储设备密钥和证书。
  • 安全文件系统(如OP-TEE的Secure Storage):基于RPMB或安全Flash分区,提供文件级加密存储。密钥在存储前会用设备密钥加密。
  • 安全SRAM:掉电易失,适合存放会话密钥。攻击者即使物理拆机,断电后数据即消失。

我的经验:对于高安全场景(如金融支付),我建议采用「三级存储」策略:

  1. 根密钥放在OTP,物理不可读。
  2. 设备密钥放在RPMB,由安全世界固件管理。
  3. 会话密钥放在安全SRAM,用完即焚。

这样即使攻击者拿到Flash镜像,也得不到任何有效密钥。

另外,密钥的生命周期管理也很重要。我见过不少设备,密钥从出厂到报废从不更换。正确的做法是:

  • 生产阶段:在安全环境中注入根密钥,锁定OTP。
  • 运行阶段:定期派生新会话密钥,旧密钥安全擦除。
  • 退役阶段:触发安全擦除流程,清除所有安全存储区。

嗯,这里要注意:安全擦除不是简单地删除文件。对于Flash存储,要执行全块擦除并写入随机数,防止数据残留被恢复。

3.5 国密算法在安全启动中的具体应用

讲完了框架,我们来看看国密算法具体怎么嵌入到安全启动链中。

在标准的TrustZone安全启动中,签名验证通常使用RSA或ECDSA。替换为国密SM2后,流程如下:

  1. 镜像签名:在编译阶段,使用SM2私钥对镜像文件计算签名(SM2签名算法)。
  2. 镜像哈希:同时计算镜像的SM3哈希值,用于完整性校验。
  3. 启动验证:BootROM读取OTP中的SM2公钥,验证BL1镜像的SM2签名。验证通过后,计算BL1的SM3哈希,与签名中的哈希比对。
  4. 逐级传递:每一级都重复上述过程,直到整个系统启动完成。

关键点:SM2签名验证的计算量比RSA-2048大约30%,但安全性更高(等效于RSA-3072)。在嵌入式设备上,我建议使用硬件SM2加速器,否则启动时间可能增加数百毫秒。

我曾经在一个项目中,因为没启用硬件SM2加速,导致安全启动耗时从200ms飙升到1.2s。后来在TrustZone安全世界中配置了SM2协处理器,才把时间压回300ms以内。所以,硬件加速不是可选项,而是必选项。

最后,总结一下本章的核心要点:

  • 信任根必须硬件固化,不可篡改。
  • 安全启动是链式验证,每一级独立签名。
  • 密钥派生使用HKDF-SM3,分层管理。
  • 密钥存储利用TrustZone安全存储机制,分级保护。
  • 国密SM2/SM3可无缝替换国际算法,但需注意硬件加速。

这些内容,说白了就是一句话:从芯片上电的第一条指令开始,到业务密钥的每一次使用,都要确保「可信」和「可控」。TrustZone给了我们隔离的土壤,国密算法给了我们自主的武器,剩下的就是如何把它们组合成一套坚固的防御体系。