3. 身份存储与安全:安全存储介质、密钥派生与防篡改
设备身份的核心,说白了就是那把私钥。私钥一旦泄露,整个信任体系就崩塌了。我见过太多项目,算法选得再强,协议设计得再精巧,最后私钥被从文件系统里直接读出来——那前面所有工作都白费了。
所以这一章,我们重点聊聊私钥到底该放在哪、怎么存、怎么用。我会结合自己踩过的坑,把 TPM、SE、密钥派生和防篡改这些话题讲透。
3.1 安全存储介质:TPM 与 SE 的选择
先问个问题:私钥能不能放在 Flash 里?能,但不安全。普通 Flash 没有防读保护,攻击者用 JTAG 或者直接拆芯片读存储,私钥就没了。我早期一个项目就吃过这个亏——产品量产了才发现,用逻辑分析仪就能把密钥抓出来。
所以工业级方案必须用独立的安全元件。目前主流就两种:TPM 和 SE。
| 特性 | TPM(可信平台模块) | SE(安全元件) |
|---|---|---|
| 核心用途 | 平台完整性度量 + 密钥存储 | 金融级密钥保护 + 应用隔离 |
| 接口 | LPC / SPI / I2C | ISO 7816 / SWP / I2C |
| 防物理攻击 | 中(有主动屏蔽层) | 高(有电压/温度/激光检测) |
| 典型成本 | $1-3 | $0.5-2(但认证费高) |
| 适用场景 | PC、服务器、网关 | 手机、支付终端、车钥匙 |
我个人习惯这样选:如果设备需要做远程证明(Remote Attestation),比如网关要证明自己没被篡改,那就上 TPM。如果设备处理的是金融交易或者数字车钥匙这种高价值资产,SE 更靠谱。
3.2 密钥派生:从根密钥到会话密钥
设备身份密钥通常只有一个——我们叫它设备私钥(Device Private Key)。但实际运行时,不可能每次都拿它去签名。为什么?因为私钥操作慢,而且暴露次数越多风险越大。
正确的做法是:用根密钥派生出一堆临时密钥。这就是密钥派生(Key Derivation)。
我常用的派生结构是这样的:
// 根密钥存储在 TPM/SE 中,永不出芯片
RootKey = TPM_Seal(随机数, 设备唯一ID)
// 每次启动时派生会话密钥
SessionKey = KDF(RootKey, 启动计数器 || 设备时间)
// 每次通信时派生临时密钥
EphemeralKey = KDF(SessionKey, 随机Nonce || 对端公钥Hash)
这里 KDF 我推荐用 HKDF(RFC 5869),它基于 HMAC,安全性经过充分验证。别自己写派生算法——我见过有人用简单的 SHA256 拼接,结果被长度扩展攻击打穿。
3.3 加密存储:密钥在休息时也要安全
密钥在芯片内部是安全的,但有时候我们不得不把密钥存到外部 Flash 里——比如设备休眠时需要保存状态。这时候就必须加密存储。
加密存储的典型流程:
- 生成存储密钥: 用 TPM/SE 内部的硬件真随机数生成一个 AES-256 密钥。
- 加密密钥块: 用存储密钥加密设备私钥,输出密文。
- 绑定设备: 把密文和设备的唯一 ID、芯片序列号绑定,防止密钥块被移植到另一台设备。
- 存储: 把密文写到外部 Flash 或文件系统。
解密时反过来:从 TPM/SE 取出存储密钥,解密密钥块,然后加载到安全内存中使用。
3.4 防篡改机制:让攻击者无处下手
防篡改不是单一技术,而是一套组合拳。我把它分成三个层次:
3.4.1 物理防篡改
- 主动屏蔽层: TPM/SE 芯片内部有金属网格,一旦被钻孔或切割,网格断裂,芯片自动擦除密钥。
- 电压/温度检测: 攻击者常用电压毛刺或液氮降温来干扰芯片。安全芯片会监控这些参数,异常时触发自毁。
- 光传感器: 开盖检测——芯片一旦暴露在光线下,立即擦除敏感数据。
我记得有一次做车钥匙的渗透测试,我们用激光照射芯片表面想读取 ROM,结果芯片直接自毁了。嗯,那款 SE 的防篡改做得确实到位。
3.4.2 逻辑防篡改
- 访问控制: 只有经过授权的固件才能调用密钥操作接口。TPM 有 PCR(平台配置寄存器)机制,只有 PCR 值匹配时才能解锁密钥。
- 防回滚: 密钥版本号存储在 OTP 中,每次更新只能递增。攻击者无法把密钥恢复到旧版本。
- 速率限制: 密钥操作接口加入延迟和失败计数。连续失败 5 次就锁定,防止暴力破解。
3.4.3 环境防篡改
- 灌胶封装: 把安全芯片用环氧树脂灌封,让攻击者无法直接接触引脚。
- PCB 层叠设计: 敏感信号走内层,外层铺地,防止探针接触。
- 防拆螺丝: 使用特殊螺丝,一旦拆卸就留下物理痕迹。
3.5 整体架构图:身份存储与安全的关系
下面这张图把整个身份存储与安全的体系串起来了。你可以看到从根密钥到会话密钥的派生路径,以及防篡改机制在各个层级的分布。
你看,整个架构是分层的。每一层都依赖下一层提供的基础安全能力。最底层是防篡改,它保护了安全介质;安全介质保护了根密钥;根密钥通过派生保护了会话密钥;会话密钥通过加密保护了存储数据。
这个设计思路我一直在用。说白了,就是「不要把鸡蛋放在一个篮子里」——即使某一层被攻破,其他层还能兜底。
3.6 实战建议:选型与部署清单
最后,我整理了一份选型清单,方便你在实际项目中对照检查:
| 检查项 | 推荐方案 | 避坑点 |
|---|---|---|
| 安全介质选型 | 高安全场景用 SE,平台证明场景用 TPM | 别用通用 MCU 内置 Flash 存私钥 |
| 密钥派生算法 | HKDF-SHA256 | 别用简单哈希拼接 |
| 加密存储算法 | AES-256-GCM + 关联数据绑定 | 别用 ECB 模式,别忽略认证标签 |
| 防篡改等级 | 至少做逻辑防篡改 + 灌胶 | 别只依赖软件校验 |
| 密钥生命周期 | 根密钥永久,会话密钥按需刷新 | 别让会话密钥长期有效 |