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 更靠谱。

一个小技巧: 很多 MCU 现在内置了「伪 TPM」——其实就是芯片内部的一块 OTP 加一个真随机数发生器。这种方案成本低,但防物理攻击能力有限。我建议只用在生命周期短、价值低的设备上。

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 里——比如设备休眠时需要保存状态。这时候就必须加密存储。

加密存储的典型流程:

  1. 生成存储密钥: 用 TPM/SE 内部的硬件真随机数生成一个 AES-256 密钥。
  2. 加密密钥块: 用存储密钥加密设备私钥,输出密文。
  3. 绑定设备: 把密文和设备的唯一 ID、芯片序列号绑定,防止密钥块被移植到另一台设备。
  4. 存储: 把密文写到外部 Flash 或文件系统。

解密时反过来:从 TPM/SE 取出存储密钥,解密密钥块,然后加载到安全内存中使用。

注意: 加密存储不是万能的。如果攻击者能物理访问设备,他可以直接读 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 整体架构图:身份存储与安全的关系

下面这张图把整个身份存储与安全的体系串起来了。你可以看到从根密钥到会话密钥的派生路径,以及防篡改机制在各个层级的分布。

设备身份存储与安全架构 设备身份存储与安全架构 安全存储介质层 TPM(可信平台模块) | SE(安全元件) | 内置 OTP 密钥派生层 根密钥 → KDF(HKDF) → 会话密钥 → KDF → 临时密钥 派生因子:设备唯一ID | 启动计数器 | 随机Nonce 加密存储层 AES-256-GCM 加密 | 设备绑定 | 外部 Flash 密文存储 防篡改机制层 物理防护(屏蔽层/传感器) | 逻辑防护(PCR/防回滚) | 环境防护(灌胶/PCB设计) 密钥永不出芯片 操作在内部完成 派生密钥用完即毁 根密钥不暴露 密文可公开 解密需安全芯片

你看,整个架构是分层的。每一层都依赖下一层提供的基础安全能力。最底层是防篡改,它保护了安全介质;安全介质保护了根密钥;根密钥通过派生保护了会话密钥;会话密钥通过加密保护了存储数据。

这个设计思路我一直在用。说白了,就是「不要把鸡蛋放在一个篮子里」——即使某一层被攻破,其他层还能兜底。

3.6 实战建议:选型与部署清单

最后,我整理了一份选型清单,方便你在实际项目中对照检查:

检查项 推荐方案 避坑点
安全介质选型 高安全场景用 SE,平台证明场景用 TPM 别用通用 MCU 内置 Flash 存私钥
密钥派生算法 HKDF-SHA256 别用简单哈希拼接
加密存储算法 AES-256-GCM + 关联数据绑定 别用 ECB 模式,别忽略认证标签
防篡改等级 至少做逻辑防篡改 + 灌胶 别只依赖软件校验
密钥生命周期 根密钥永久,会话密钥按需刷新 别让会话密钥长期有效
最后提醒一句: 安全存储没有银弹。TPM 和 SE 只是工具,关键还是设计思路。我曾经见过一个项目,用了最贵的 SE,但固件更新接口没做签名校验——攻击者直接刷了个恶意固件,把 SE 的密钥调用接口暴露出来了。嗯,工具再好,用不对也是白搭。