4. 唯一设备密钥(UDK)生成:基于物理不可克隆函数(PUF)的密钥生成、基于芯片ID的密钥派生、UDK的安全存储

好,咱们进入第四章。这一章讲的是UDK怎么来的,以及怎么把它安全地存住。

你想想看,量产几百万片芯片,每片都要有一个独一无二的密钥。这个密钥不能写死在Flash里——太容易被读走了。也不能靠服务器下发——网络不通怎么办?

所以,业界主流做法就三条路:PUF、芯片ID派生、以及安全存储。我一个个拆开讲。

4.1 基于物理不可克隆函数(PUF)的密钥生成

PUF这词听起来玄乎,说白了就是利用芯片制造时产生的微观差异。同一片晶圆上,相邻两个晶体管的阈值电压都有微小差别。这种差别没法复制,也没法预测。

我当年第一次接触PUF是在一款安全MCU项目上。客户要求密钥不能以明文形式存在于任何非易失介质中。我们试了OTP、eFuse,都不够理想。最后选了SRAM PUF——上电瞬间SRAM单元的初始值就是天然的指纹。

PUF的核心优势:

  • 不可克隆:即使拿到同一套光罩,不同芯片的PUF响应也不同
  • 物理绑定:密钥与芯片本体绑定,拆片即失效
  • 无存储:密钥不在Flash/EEPROM中,抗物理攻击

常见的PUF类型有几种,我列个表对比一下:

PUF类型 原理 面积开销 稳定性 量产成熟度
SRAM PUF SRAM上电初始值随机性 低(复用已有SRAM) 中等(需纠错) 高(广泛使用)
环形振荡器PUF 振荡频率差异 中 高 中
仲裁器PUF 路径延迟差异 低 低(易受环境干扰) 低
DRAM PUF DRAM retention时间差异 低(复用DRAM) 低 实验阶段

实际量产中,SRAM PUF是主流。为什么?因为它不需要额外模拟电路,直接用芯片上已有的SRAM就行。成本几乎为零。

注意:PUF原始响应不是直接可用的密钥。它受温度、电压、老化影响,会有位翻转。必须配合模糊提取器(Fuzzy Extractor)和纠错码(ECC)才能稳定输出128位或256位密钥。

我曾经踩过一个坑:某批次芯片在低温下PUF响应错误率飙升到15%,导致密钥恢复失败。后来我们在纠错码里加了BCH(15,7,5)编码,把错误率压到了0.1%以下。嗯,这里要注意,辅助数据(Helper Data)必须存在片上非易失区,但辅助数据本身不泄露密钥信息。

4.2 基于芯片ID的密钥派生

不是所有芯片都适合PUF。有些低端MCU没有SRAM可用,或者客户对成本极度敏感。这时候可以用芯片ID派生密钥。

芯片ID通常是厂家在晶圆测试阶段写入的一次性编程(OTP)区,比如64位唯一标识符。但直接用芯片ID当密钥?不行。ID是明文可读的,攻击者拿到ID就能算出密钥。

正确的做法是:芯片ID + 密钥派生函数(KDF)。

// 伪代码示例:基于芯片ID的密钥派生
uint8_t chip_id[8];          // 从OTP读取芯片ID
uint8_t master_key[16];      // 主密钥(烧录在安全区)
uint8_t udk[16];             // 唯一设备密钥

// 使用HMAC-SHA256作为KDF
hmac_sha256(master_key, chip_id, sizeof(chip_id), udk, sizeof(udk));

这里有个关键点:主密钥(Master Key)必须安全存储。它可以是工厂在安全环境中注入的,也可以是PUF生成的。我习惯的做法是:用PUF生成主密钥,再用主密钥对芯片ID做HMAC派生UDK。这样既利用了PUF的物理绑定特性,又通过KDF实现了密钥隔离。

个人经验:派生时一定要加盐值(Salt)和上下文(Context)。比如加入产品型号、批次号。防止不同产品线之间密钥碰撞。我曾经见过一个案例,两个不同项目用了相同的芯片ID范围,结果派生出的UDK有30%重复——就是因为没加盐。

芯片ID派生的优点是确定性——只要芯片ID不变,每次派生出的UDK都一样。不需要纠错码,不需要辅助数据。缺点是安全性依赖主密钥——主密钥泄露,所有UDK都能被算出来。

4.3 UDK的安全存储

密钥生成了,放哪儿?

最蠢的做法:放Flash明文区。稍微好点:放Flash加密区。但真正安全的做法是:不让密钥以明文形式出现在任何非易失介质中。

我列一下常见的存储方案,从最弱到最强:

  1. Flash明文存储——攻击者用JTAG或SPI探针直接读走。不推荐。
  2. Flash加密存储——用另一个密钥加密后存Flash。但加密密钥本身也要存,问题没解决。
  3. OTP/eFuse——一次性编程,不可改写。适合存根密钥或主密钥。但面积大,成本高。
  4. PUF实时重建——每次上电从PUF重建密钥,用完即擦。密钥从不落盘。
  5. 硬件安全模块(HSM)内部寄存器——密钥只在HSM内部使用,CPU只能通过硬件接口调用加解密,无法直接读取密钥值。

量产设备中,我推荐方案4+5的组合:PUF生成密钥,密钥直接送入HSM寄存器,CPU只能通过硬件API使用密钥,不能读密钥本身。

安全存储的核心原则:

  • 最小暴露原则:密钥只在需要时出现在计算单元中
  • 物理隔离:密钥存储区与主CPU总线隔离
  • 零化机制:检测到攻击(如电压毛刺、温度异常)立即擦除密钥

我曾经处理过一个返修案例:某设备被攻击者用激光切割芯片表面,直接读取了内部总线上的密钥。后来我们在芯片顶层加了主动屏蔽层(Active Shield)——一层蛇形走线的金属层,一旦被切断或短路,立即触发密钥擦除。嗯,这招挺管用,从那以后没再出过类似问题。

4.4 本章知识体系

我把三种UDK生成方式的关系画了张图,方便你理解整体架构:

UDK生成与存储架构图 UDK生成与存储架构 SRAM PUF 原始响应 模糊提取器 + ECC 稳定密钥 (128/256位) 芯片ID (OTP) KDF (HMAC-SHA256) 派生密钥 (UDK) HSM 安全寄存器 CPU 通过硬件API调用 PUF路径特点 • 物理绑定芯片 • 需纠错码辅助 • 抗物理攻击强 芯片ID路径特点 • 确定性输出 • 依赖主密钥安全 • 无需纠错码

从图上你能看到,两条路径最终都汇聚到HSM安全寄存器。这是关键——不管密钥怎么来的,最终它必须在一个硬件隔离的环境里被使用。

我的建议:如果芯片面积允许,优先用PUF。如果成本敏感,用芯片ID+KDF。但无论哪种,HSM是必须的——没有硬件隔离,密钥生成得再安全也白搭。