硬件信任根:HSM与TPM的区别
说到硬件信任根,很多刚接触安全启动的朋友都会问:HSM和TPM到底有啥区别?我当年也困惑过。说白了,它们都是硬件安全模块,但定位完全不同。
HSM是什么?
HSM,全称是硬件安全模块。你可以把它想象成一个保险箱。这个保险箱专门用来存放密钥,执行加密运算。它有自己的处理器,自己的内存,甚至有自己的操作系统。
我在项目中遇到过一种情况:客户要求密钥必须物理隔离,不能给CPU任何接触的机会。这时候HSM就是唯一的选择。它独立于主系统运行,就算主芯片被攻破了,密钥依然安全。
HSM的核心特点:
- 物理隔离:独立芯片,独立总线
- 高性能:专用硬件加速加密运算
- 高安全性:通过FIPS 140-2 Level 3以上认证
- 价格昂贵:一个工业级HSM可能要几千美元
TPM又是什么?
TPM是可信平台模块。它更像一个安全协处理器,集成在主板上。TPM的定位是「够用就好」——提供基本的密钥存储、平台完整性度量、远程证明等功能。
你想想看,一台笔记本电脑需要HSM吗?没必要。TPM就足够了。它成本低,体积小,功耗低。我建议做消费级产品时优先考虑TPM。
| 对比项 | HSM | TPM |
|---|---|---|
| 成本 | 高(几百到几万美元) | 低(几美元到几十美元) |
| 性能 | 高(专用硬件加速) | 中等(通用协处理器) |
| 密钥存储量 | 大(可扩展) | 有限(通常几十个密钥槽) |
| 典型应用 | 服务器、金融、工业控制 | PC、物联网设备、嵌入式系统 |
| 认证标准 | FIPS 140-2/3, Common Criteria | TCG TPM 2.0 规范 |
我的经验之谈:如果产品量产后需要远程更新固件,TPM是性价比最高的选择。但如果产品涉及金融交易或关键基础设施,别省那点钱,上HSM。
Zephyr支持的硬件安全模块
Zephyr RTOS对硬件安全模块的支持相当全面。我整理了一下,主要分三类:
内置安全单元
很多MCU厂商在芯片内部集成了安全硬件。比如NXP的LPC系列有安全子系统的,ST的STM32系列有CRYP和HASH外设。Zephyr通过驱动层直接调用这些硬件。
// Zephyr中配置硬件加密的示例
// prj.conf
CONFIG_CRYPTO=y
CONFIG_CRYPTO_STM32=y
CONFIG_CRYPTO_INIT_PRIORITY=50
// 代码中调用
#include <crypto/crypto.h>
struct crypto_dtls_ctx ctx;
crypto_dtls_init(&ctx, DEVICE_DT_GET(DT_NODELABEL(crypto)));
外部安全芯片
这类芯片通过SPI或I2C与主MCU通信。常见的包括:
- ATECC608A:Microchip的加密协处理器,支持ECDH、SHA-256
- SLB9670:Infineon的TPM 2.0芯片
- OPTIGA Trust M:英飞凌的安全芯片系列
我记得有一次调试ATECC608A,发现SPI时钟频率太高会导致通信不稳定。后来把时钟降到1MHz以下就正常了。嗯,这里要注意:安全芯片对时序要求比较严格。
软件模拟的安全模块
Zephyr也支持纯软件实现的安全功能。比如mbedTLS库,可以在没有硬件加速的情况下完成加密运算。当然,性能会差一些。
警告:软件实现的密钥存储是不安全的。密钥会暴露在内存中,容易被调试工具读取。生产环境中务必使用硬件安全模块。
MCUboot的硬件抽象层
MCUboot是Zephyr默认的启动加载器。它设计了一个精巧的硬件抽象层,让开发者可以轻松对接不同的安全硬件。
HAL的结构
MCUboot的HAL位于 boot/bootutil/src/hw_abstract.c。它定义了一组标准接口:
// MCUboot硬件抽象层核心接口
int boot_hal_init(void);
int boot_hal_verify_signature(const uint8_t *hash,
uint32_t hash_len,
const uint8_t *signature,
uint32_t sig_len,
const uint8_t *pub_key);
int boot_hal_generate_random(uint8_t *buf, uint32_t len);
int boot_hal_secure_store(uint32_t key_id,
const uint8_t *data,
uint32_t len);
int boot_hal_secure_load(uint32_t key_id,
uint8_t *data,
uint32_t len);
说白了,你只需要实现这几个函数,MCUboot就能用你的安全硬件了。我建议先实现 boot_hal_verify_signature,这是最核心的——固件签名验证全靠它。
实际对接案例
以对接ATECC608A为例,看看具体怎么做:
// 自定义硬件抽象实现
#include "bootutil/hw_abstract.h"
#include "atecc608a.h"
int boot_hal_init(void) {
// 初始化ATECC608A
return atecc608a_init();
}
int boot_hal_verify_signature(const uint8_t *hash,
uint32_t hash_len,
const uint8_t *signature,
uint32_t sig_len,
const uint8_t *pub_key) {
// 使用ATECC608A验证ECDSA签名
// 注意:ATECC608A内部存储公钥,不需要传入
return atecc608a_verify(hash, hash_len, signature, sig_len);
}
避坑指南:我曾经在对接TPM时犯过一个错误——没有处理TPM的NV索引冲突。TPM的NV存储空间有限,如果多个应用共用同一个索引,会导致数据覆盖。建议为每个密钥分配独立的NV索引,并在文档中记录清楚。
性能考量
不同硬件模块的签名验证速度差异很大。我测试过几款:
- ATECC608A:ECDSA验证约50ms
- SLB9670 TPM:RSA 2048验证约200ms
- 软件mbedTLS:ECDSA验证约500ms(Cortex-M4 @ 168MHz)
你想想看,如果每次启动都要等500ms,用户体验会很差。所以我建议优先使用硬件加速的方案。特别是对于需要快速启动的场景,比如汽车电子、工业控制器。
最后说一句:MCUboot的HAL设计得很灵活。你可以根据产品需求,在编译时选择不同的后端。比如开发阶段用软件模拟,量产时切换到硬件安全模块。这种设计思路值得学习。