4、安全密钥存储:SHE内部NVM的密钥存储机制与保护策略
好,咱们接着聊SHE规范里最核心的一个话题——密钥到底怎么存?
你想想看,密钥要是被偷了,那整个安全体系就形同虚设。我见过不少项目,算法选得挺强,防侧信道也做得不错,结果密钥存储环节出了纰漏,功亏一篑。所以这一章,咱们把SHE内部NVM的密钥存储机制掰开揉碎了讲清楚。
4.1 SHE的NVM架构:密钥到底放在哪?
SHE规范里定义的NVM,说白了就是芯片内部的一块非易失性存储器。它跟普通的Flash或者EEPROM不一样——SHE的NVM是专用于密钥存储的,普通用户代码根本访问不到。
我个人习惯把SHE的NVM想象成一个“保险柜”。这个保险柜有多个小格子,每个格子对应一个密钥槽(Key Slot)。SHE规范定义了最多16个密钥槽,编号从0到15。
| 密钥槽编号 | 用途 | 是否可被用户读取 |
|---|---|---|
| 0 | 调试密钥(Debug Key) | 否 |
| 1-11 | 通用密钥(Generic Key) | 否 |
| 12-13 | RAM密钥(仅运行时存在) | 否 |
| 14 | 安全启动密钥 | 否 |
| 15 | 主密钥(用于派生其他密钥) | 否 |
嗯,这里要注意:所有密钥槽对用户都是不可读的。你只能通过SHE提供的API去使用密钥,比如加密、解密、MAC计算,但你不能直接问“给我把密钥0x05读出来”。这是SHE安全设计的底线。
核心原则:SHE的NVM密钥存储遵循“可用不可见”原则。密钥在NVM里是密文存储的,即使攻击者物理剖片,拿到的也是一堆乱码。
4.2 密钥存储格式:不仅仅是128位数据
你以为密钥就是往NVM里写128位二进制数?太天真了。
SHE规范对密钥存储格式有严格定义。每个密钥槽在NVM中实际占用144位(18字节)的空间。为什么多出16位?
- 128位:密钥本体
- 4位:密钥版本号(用于密钥更新和回滚保护)
- 4位:密钥标志位(指示密钥类型、是否可导出等属性)
- 8位:CRC校验(用于检测NVM数据完整性)
我在项目中遇到过一个问题:某次OTA升级后,密钥莫名其妙失效了。排查了半天,发现是NVM写入时CRC计算出了偏差。从那以后,我每次做密钥写入都会额外做一次读回校验。
实战技巧:密钥写入后,建议立即执行一次SECURE_BOOT或者LOAD_KEY命令验证密钥是否可用。不要等到系统运行时才发现密钥坏了。
4.3 密钥保护策略:NVM里的密钥是怎么加密的?
直接往NVM里写明文密钥?那是给自己挖坑。
SHE规范要求,NVM中存储的密钥必须经过密钥加密密钥(KEK)加密。这个KEK是怎么来的?
- 芯片唯一密钥(UID Key):基于芯片唯一ID派生,每颗芯片都不一样。
- 用户自定义密钥(User Key):由OEM在产线注入,同一批次可能共享。
- 两者结合:通过KDF(密钥派生函数)生成最终的KEK。
说白了,你写入NVM的密钥,在物理存储层面是经过加密的。攻击者就算把芯片磨到只剩NVM层,用电子显微镜看,看到的也是加密后的密文。没有KEK,他拿这堆数据一点办法都没有。
警告:千万不要尝试绕过SHE的API直接操作NVM地址。我曾经见过一个团队,为了“提高效率”自己写驱动操作NVM,结果把密钥存储区的校验信息搞乱了,整批芯片报废。SHE的NVM操作必须通过SHE模块提供的接口。
4.4 密钥生命周期管理:从生到死
密钥不是写进去就完事了。SHE规范定义了完整的密钥生命周期:
| 阶段 | 操作 | 说明 |
|---|---|---|
| 1. 初始化 | NVM全擦除 | 出厂时所有密钥槽为全0或全1状态 |
| 2. 写入 | LOAD_KEY | 通过安全通道写入加密后的密钥 |
| 3. 使用 | 加密/解密/MAC | 密钥仅在SHE内部使用,不暴露 |
| 4. 更新 | LOAD_KEY(新版本) | 版本号递增,防止回滚攻击 |
| 5. 删除 | NVM擦除 | 物理擦除,不可恢复 |
这里有个关键点——密钥版本号。SHE规范要求,每次更新密钥时,版本号必须递增。如果攻击者试图把旧版本的密钥写回去(回滚攻击),SHE会检测到版本号降低,直接拒绝操作。
我曾经在给一家Tier1做安全审计时发现,他们的密钥更新逻辑里没有检查版本号。结果测试人员用旧固件刷回去,系统居然还能正常工作。这要是被攻击者利用,后果不堪设想。
4.5 密钥导出策略:什么时候可以“拿出来”?
SHE规范里有个很有意思的设计——密钥导出(Key Export)。某些场景下,你需要把密钥从一个SHE模块转移到另一个SHE模块。比如,ECU更换时,需要把旧ECU的密钥迁移到新ECU。
但密钥不能直接明文导出。SHE规范定义了安全导出协议:
- 导出时,密钥会使用目标SHE的公钥进行加密
- 只有目标SHE才能用自己的私钥解密
- 传输过程中,密钥始终处于加密状态
嗯,这里要注意:不是所有密钥都允许导出。密钥槽的标志位里有一个“可导出”位。如果这个位被置0,那这个密钥就永远锁死在当前芯片里了。我个人建议,对于安全启动密钥、主密钥这类关键密钥,一律设置为不可导出。
最佳实践:只有那些需要在产线或者售后环节进行密钥分发的密钥,才设置为可导出。其他密钥,尤其是用于安全启动和固件加密的密钥,务必设置为不可导出。
4.6 实战中的坑与避坑指南
讲了这么多理论,最后分享几个我在实际项目中踩过的坑:
- 坑一:NVM写入时序——SHE的NVM写入需要一定时间(通常是几毫秒到几十毫秒)。如果在写入过程中掉电,密钥可能只写了一半。我现在的做法是:写入前先备份,写入后做CRC校验,校验失败就回滚。
- 坑二:密钥槽冲突——多个安全服务可能使用同一个密钥槽。比如,CAN加密和UDS安全访问都用密钥槽1,结果一改全改。建议每个安全服务使用独立的密钥槽,做好文档记录。
- 坑三:产线密钥注入——产线上批量烧录密钥时,一定要做唯一性校验。我曾经遇到过产线脚本写错了,1000颗芯片烧了同一个密钥。那批产品后来全部召回重做。
好了,关于SHE内部NVM的密钥存储机制,咱们就聊到这里。下一章我会讲密钥派生和会话密钥的生成,那部分更有意思——你想想看,怎么用一颗主密钥派生出成千上万颗会话密钥,还不降低安全性?到时候见。