第3章 TEE中的密钥生成:硬件安全密钥派生、平台身份密钥与密封密钥

好,咱们进入第三章。前两章我们把TEE的基本概念和签名验签的宏观流程聊清楚了。这一章,我带你钻到TEE的肚子里,看看那些用来签名的密钥到底是怎么生出来的。

说实话,密钥生成这事儿,在普通操作系统里可能就是个随机数加个算法。但在TEE里,规矩多得很。为什么?因为TEE的核心理念就是——密钥必须出生在硬件里,死在硬件里。密钥一旦被软件拿到明文,那TEE的信任根基就塌了。

我个人习惯把TEE的密钥体系分成三个层次:根密钥、平台身份密钥、应用密封密钥。咱们一个一个来拆。

3.1 硬件安全密钥派生:从芯片熔丝到派生密钥

所有TEE密钥的源头,是一组在芯片制造时烧录的硬件根密钥。这玩意儿通常存在eFuse(电子熔丝)或OTP(一次性可编程)存储器里。芯片一出厂,这组值就焊死了,谁也改不了。

但问题来了——我们不能直接用这个根密钥去签名每一个消息。为什么?

  • 安全隔离:根密钥一旦泄露,整个芯片的信任体系全完蛋。
  • 功能单一:根密钥通常只有128位或256位,没法满足不同场景的密钥需求。
  • 合规要求:很多安全标准(比如FIPS 140-3)要求密钥必须定期更换或派生,不能直接用硬件固定密钥。

所以,TEE的做法是:用根密钥作为种子,通过硬件支持的密钥派生函数(KDF),派生出各种用途的密钥。

这里我放一张图,帮你理解这个派生链条:

TEE密钥派生层级结构图 硬件根密钥 (eFuse/OTP) 硬件KDF (AES-CMAC / HMAC) 平台身份密钥 (AIK) 用于远程证明签名 密封密钥 (Sealing Key) 用于数据加密保护 应用签名密钥 应用加密密钥 派生过程在TEE内部完成,根密钥永不离开硬件安全边界

你看,整个派生链条是单向的。从根密钥到AIK,从AIK到应用密钥,每一步都经过硬件KDF。我在项目里见过有人试图在REE侧自己算派生密钥,结果被安全审计打了个大大的X——派生过程必须在TEE内部完成,这是铁律。

核心原则:TEE密钥派生遵循"最小权限"原则——每个密钥只做一件事,只在一个上下文中可用。根密钥只做派生,不直接用于签名或加密。

3.2 平台身份密钥(AIK):TEE的身份证

平台身份密钥,英文叫Attestation Identity Key,简称AIK。这玩意儿是TEE在远程证明中的身份证。

你想想看,当你的TEE向远程服务器证明"我是合法的TEE"时,总得有个东西来签名吧?这个签名者就是AIK。

AIK有几个关键特性:

  • 唯一性:每个TEE实例的AIK都是唯一的,由芯片根密钥派生而来。
  • 不可导出性:AIK的私钥永远不能离开TEE。你只能用它签名,不能把它读出来。
  • 可验证性:AIK的公钥会通过证书链发布,远程方可以验证。

AIK的生成流程,我拆成几步:

  1. 读取平台配置:TEE启动时,硬件测量其代码、配置、数据,生成一组度量值(Measurement)。
  2. 调用硬件KDF:以根密钥为种子,以平台度量值为输入,调用硬件KDF。
  3. 生成AIK密钥对:KDF的输出作为种子,生成非对称密钥对(通常是RSA-2048或ECDSA-P256)。
  4. 签发AIK证书:由平台制造商或隐私CA(Certificate Authority)对AIK公钥签名,形成证书链。

这里有个坑,我踩过。有一次,我在调试远程证明时,发现AIK签名总是验证失败。查了两天,最后发现是平台度量值在两次启动之间发生了变化——因为固件升级了。AIK的生成依赖度量值,度量值变了,AIK就变了。所以,AIK不是永久不变的,它跟平台状态绑定。

避坑指南:AIK的生成时机很关键。我建议在TEE初始化阶段就生成AIK,并缓存其公钥证书。不要在每次远程证明时都重新生成AIK,那样性能太差。但要注意,如果平台度量值发生变化(比如固件升级),必须重新生成AIK。

3.3 密封密钥(Sealing Key):数据保险箱的锁

密封密钥,Sealing Key,这名字起得好——就像把数据封在一个信封里,只有特定条件下才能打开。

密封密钥的用途很直接:加密数据,让数据只能在指定的TEE状态下解密。

举个例子:你的TEE应用有一个私密配置文件,你希望只有在你当前这个TEE版本下才能读取。怎么办?用密封密钥加密它。

密封密钥的生成机制和AIK类似,但有一个关键区别:

特性 AIK Sealing Key
用途 远程证明签名 数据加密保护
派生输入 平台度量值 + 根密钥 平台度量值 + 应用标识 + 根密钥
密钥类型 非对称密钥对 对称密钥(AES-256)
可导出性 私钥不可导出,公钥可导出 完全不可导出
生命周期 随平台状态变化 随应用和平台状态变化

你看,Sealing Key的派生输入多了一个应用标识。这意味着,不同应用拿到的密封密钥是不同的。即使同一个TEE,应用A的密封密钥也解不开应用B加密的数据。

密封密钥的使用流程是这样的:

  1. 密封(Seal):应用调用TEE的密封接口,传入明文数据和期望的平台状态。TEE内部生成Sealing Key,加密数据,输出密文。
  2. 解封(Unseal):应用调用解封接口,传入密文。TEE检查当前平台状态是否匹配,如果匹配则重新生成Sealing Key并解密,否则拒绝。

经验之谈:我在做金融支付方案时,经常用密封密钥来保护交易密钥。具体做法是:在TEE初始化时,生成一个交易主密钥,然后用密封密钥加密后存储到REE的文件系统中。每次需要使用时,再解封出来。这样既保证了密钥的持久化,又确保了安全性——因为解封条件可以设置得非常严格,比如要求TEE版本号、应用哈希值完全匹配。

3.4 密钥生命周期管理

密钥生出来了,不是就完事了。你得管好它的整个生命周期。

我总结了一个密钥生命周期管理的清单:

  • 生成:在TEE内部,使用硬件KDF,确保随机性足够。
  • 使用:限制使用次数和上下文,比如AIK只能用于签名,不能用于加密。
  • 存储:私钥永远留在TEE内,公钥可以导出但需要证书保护。
  • 轮换:定期更换密钥,尤其是应用密钥。我建议最长不超过一年。
  • 销毁:当TEE被重置或应用被卸载时,必须安全擦除密钥。

这里要特别强调密钥轮换。我记得有一次做安全审计,客户问:"你们的AIK多久换一次?"我说:"AIK跟平台状态绑定,平台不变就不换。"审计员直接打了个问号。后来我才明白,即使平台状态不变,也应该定期重新生成AIK,以防止长期使用同一密钥带来的泄露风险。

最佳实践:对于AIK,建议在每次远程证明会话开始时重新生成一次。对于Sealing Key,建议在应用每次启动时重新密封数据,这样Sealing Key实际上每次都在变化。虽然密钥本身变了,但只要解封条件不变,数据就能正常解密。

3.5 小结

好,这一章的内容就这些。总结一下:

  • TEE的密钥体系从硬件根密钥开始,通过KDF派生。
  • AIK是TEE的身份证,用于远程证明签名,依赖平台度量值。
  • Sealing Key是数据保险箱的锁,用于加密保护数据,依赖平台状态和应用标识。
  • 密钥生命周期管理要覆盖生成、使用、存储、轮换、销毁五个环节。

嗯,这些概念听起来可能有点抽象。但等你真正动手做TEE开发时,你会发现——密钥生成是所有安全功能的基石。根密钥稳了,派生密钥对了,后面的签名验签才能站得住脚。