设备身份存储:安全存储方案对比与密钥派生机制
设备身份一旦生成,接下来最要命的问题就是——放哪儿?
你想想看,私钥这种东西,如果明文躺在文件系统里,那跟把家门钥匙挂在门外有什么区别?我见过太多项目,前期忙着搞算法、搞协议,最后身份存储随便塞个 Flash 分区,结果一上渗透测试就翻车。
这一章,咱们就聊聊设备身份到底该怎么存。我会把 HSM、TEE、SE 这几个主流方案掰开揉碎讲清楚,再聊聊存储加密和密钥派生。这些都是我这些年踩坑踩出来的经验,希望能帮你少走弯路。
3.1 安全存储方案对比:HSM vs TEE vs SE
先给个全景图。目前工业界主流的设备身份安全存储方案,说白了就三种:HSM(硬件安全模块)、TEE(可信执行环境)、SE(安全元件)。它们各有各的适用场景,没有绝对的谁好谁坏。
| 维度 | HSM | TEE | SE |
|---|---|---|---|
| 物理形态 | 独立硬件板卡或外设 | CPU 内的安全隔离区(如 TrustZone) | 独立芯片(如 SIM 卡、eSE) |
| 安全等级 | 最高(FIPS 140-2 Level 3/4) | 中等(防软件攻击,物理攻击较弱) | 高(防物理和侧信道攻击) |
| 成本 | 极高(千元到万元级) | 中等(集成在 SoC 中) | 较低(几元到几十元) |
| 性能 | 高(专用密码芯片) | 中等(与 Rich OS 共享 CPU) | 低(资源受限) |
| 典型场景 | 云端 CA、网关、服务器 | 手机、平板、高端 IoT 设备 | 智能卡、支付终端、低功耗传感器 |
核心观点:没有完美的方案,只有合适的方案。选型时,我建议你从三个角度权衡:安全等级需求、成本预算、设备算力资源。
3.1.1 HSM:银行级的安全堡垒
HSM 是什么?你可以把它理解成一个专门干密码学活儿的黑盒子。私钥一旦进去,就再也出不来了——所有密码运算都在盒子内部完成。
我记得有一次帮一家金融机构做 IoT 网关安全方案,他们要求私钥必须达到 FIPS 140-2 Level 3 标准。当时我们选了一款支持 PKCS#11 接口的 HSM,密钥生成、签名、验签全在 HSM 内部完成。应用层只拿到一个密钥句柄,真正的私钥材料连操作系统都看不到。
但 HSM 也有缺点——贵。而且体积大,功耗高,不适合嵌入到小型设备里。它更适合做基础设施级的安全锚点,比如云端 CA 的根密钥存储。
3.1.2 TEE:CPU 里的安全飞地
TEE 是这几年 IoT 领域的热门方案。以 ARM TrustZone 为例,它在 CPU 内部划分出两个世界:安全世界(Secure World)和非安全世界(Normal World)。设备身份私钥放在安全世界里,普通操作系统(Linux/RTOS)根本访问不到。
我做过一个智能门锁项目,用的就是 TEE 方案。我们在安全世界里跑了一个轻量级的 TA(Trusted Application),专门负责签名操作。门锁每次开锁时,APP 下发挑战值,TA 在安全世界里用私钥签名,然后把签名结果返回给非安全世界。整个过程私钥从未离开 TEE。
不过 TEE 有个硬伤——它防不了物理攻击。如果攻击者能拿到芯片,用探针或者激光注入,TEE 的安全边界就可能被突破。所以,TEE 更适合防软件攻击的场景。
3.1.3 SE:独立芯片的硬核防护
SE 是安全等级最高的方案之一。它是一颗独立的芯片,有自己的 CPU、存储和密码加速器。私钥存在 SE 内部,外部只能通过 APDU 指令跟它交互。
SIM 卡就是最典型的 SE。你手机里的 5G 鉴权密钥(Ki)就存在 SIM 卡的 SE 里,运营商都读不出来。IoT 领域,eSE(嵌入式 SE)越来越流行,比如 NXP 的 SE050 系列。
我曾经在一个智能电表项目里用过 SE。电表需要跟电网后台做双向身份认证,私钥存在 SE 里,每次认证时电表 MCU 发一条 APDU 指令给 SE,SE 完成签名后返回结果。虽然 SE 的运算速度比 TEE 慢一些,但胜在安全——就算攻击者把电表拆了,用电子显微镜也看不到私钥。
我的建议:如果设备成本敏感,选 TEE;如果安全等级要求极高(比如金融支付),选 SE;如果是网关或服务器端,选 HSM。混合使用也很常见——比如用 HSM 做根密钥保护,用 TEE 或 SE 做设备端身份存储。
3.2 存储加密策略:密钥不能裸奔
不管用哪种方案,存储加密都是底线。哪怕你用了 SE,私钥在 SE 内部也是加密存储的。这里我重点聊聊在普通 Flash 上存储设备身份时的加密策略。
3.2.1 加密密钥的层级结构
直接拿一个密钥加密私钥?不,这样太脆弱了。工业界通用的做法是多层密钥体系:
- 主密钥(MK):由设备唯一信息(如芯片 UID)派生,或者烧录在 eFuse 中。它不落 Flash。
- 存储密钥(SK):由主密钥派生,用于加密设备身份私钥。
- 设备身份私钥:用 SK 加密后存储在 Flash 中。
这样做的好处是:即使攻击者读出了 Flash 里的加密私钥,没有主密钥也解不开。而主密钥要么在 eFuse 里(一次性编程,不可读),要么由硬件唯一信息实时派生。
注意:千万不要把主密钥硬编码在代码里。我见过有人把 AES 密钥写在一个 const 数组里,结果反编译一下就全暴露了。主密钥必须依赖硬件根信任。
3.2.2 加密算法与模式选择
存储加密一般用对称算法,因为非对称太慢。我个人习惯用 AES-256-GCM。为什么选 GCM?因为它同时提供加密和完整性校验,能防止攻击者篡改密文。
// 伪代码:使用 AES-256-GCM 加密设备私钥
uint8_t key[32]; // 存储密钥(由主密钥派生)
uint8_t iv[12]; // 随机初始化向量
uint8_t plaintext[]; // 设备私钥明文
uint8_t ciphertext[];
uint8_t tag[16]; // GCM 认证标签
aes_gcm_encrypt(key, iv, plaintext, ciphertext, tag);
// 存储时:iv || ciphertext || tag 一起写入 Flash
解密时,先读 iv、ciphertext 和 tag,然后调用 aes_gcm_decrypt。如果 tag 校验失败,说明数据被篡改过,直接拒绝使用。
3.3 密钥派生机制:一钥变多钥
实际项目中,一个设备往往需要多个密钥——身份私钥、会话密钥、固件签名密钥……如果每个密钥都单独存储,Flash 开销大,管理也麻烦。这时候就需要密钥派生。
3.3.1 基于 HKDF 的派生方案
HKDF(HMAC-based Key Derivation Function)是 RFC 5869 标准,也是我最常用的派生方案。它分两步:提取(Extract)和扩展(Expand)。
// 伪代码:使用 HKDF 派生多个密钥
// 输入:主密钥 ikm(Initial Keying Material),盐值 salt,上下文信息 info
// 输出:派生密钥 okm
// Step 1: Extract
prk = HMAC-SHA256(salt, ikm)
// Step 2: Expand
okm_1 = HKDF-Expand(prk, "device-id-key", 32) // 派生设备身份密钥
okm_2 = HKDF-Expand(prk, "session-key", 16) // 派生会话密钥
okm_3 = HKDF-Expand(prk, "firmware-sign-key", 32) // 派生固件签名密钥
你看,只要一个主密钥,就能派生出任意多个用途不同的子密钥。而且每个子密钥的推导都绑定了上下文信息(info),即使一个子密钥泄露,也不会影响其他密钥。
避坑指南:我曾经在一个项目里直接用 SHA256(ikm || counter) 做派生,结果被安全审计打回来了。原因是这种简单拼接容易受到长度扩展攻击。后来全部改成 HKDF,审计一次过。所以,派生一定要用标准 KDF,别自己造轮子。
3.3.2 基于硬件唯一信息的派生
很多芯片都有唯一的 ID,比如 MCU 的 UID、eFuse 中的密钥。我们可以利用这些硬件信息来派生存储密钥。
// 伪代码:基于芯片 UID 派生存储密钥
uint8_t chip_uid[16]; // 从芯片寄存器读取
uint8_t salt[16]; // 固定盐值(可公开)
uint8_t storage_key[32];
// 使用 HKDF 派生
hkdf_extract(salt, chip_uid, prk);
hkdf_expand(prk, "storage-key", 32, storage_key);
这样做的好处是:每颗芯片的存储密钥都不同。即使攻击者破解了一台设备,也无法用同样的方法破解另一台。
3.4 知识体系总览
下面这张图总结了本章的核心逻辑,从安全存储方案到密钥派生,一目了然。
3.5 本章小结
设备身份存储,说白了就是解决一个问题:私钥放在哪里才安全?
- HSM 适合基础设施,安全等级最高,但成本也最高。
- TEE 适合消费级 IoT,防软件攻击够用,但防不了物理攻击。
- SE 适合高安全场景,独立芯片,物理防护强。
- 存储加密 要用多层密钥体系,算法推荐 AES-256-GCM。
- 密钥派生 用 HKDF 标准,别自己造轮子。