从SHA204A思考关于嵌入式固件加密的问题
前段时间在家整理东西时,发现一枚未使用的 SOP-8 封装芯片 —— 没有包装,也无其他信息,仅用一块泡沫加透明胶带包裹着。通过查看芯片丝印我才想起,这是几年前购入的加密芯片 ATSHA204A。
当时因项目需求买入这款芯片,本打算用于相关功能测试,却因某些原因最终未能用上,便被我遗忘了。本着不浪费的原则,也为了学习这款芯片的用法及固件加密的工作原理,我决定花些时间测试其功能。
此前我在一块开发板上找到了合适的测试位置,上面恰好预留了一个 SOP-8 封装的焊盘,且已连接至 STM32H7 的硬件 IIC 接口。因此,我无需花费过多时间搭建硬件测试环境。
在 GitHub 上很容易找到该芯片的相关驱动代码,我没有选用官方代码库 —— 其体积过于庞大。我采用了网友移植的驱动,核心文件仅两三个,移植起来十分便捷。不过在具体移植过程中仍遇到了一些问题,主要是 MCU 主频不一致导致的通讯超时问题,做些适配调整即可解决。
SHA204A 芯片实际提供的是一种校验机制,用于判定硬件是否为克隆版本,其本身并不具备固件加密功能。使用时,需先向 SHA204A 芯片写入不可读取的密钥,之后主机 MCU 通过校验该密钥,判断 SHA204A 是否为克隆版。即便攻击者能克隆整个电路板(包括 MCU 内的固件),但由于 SHA204A 内未写入正确密钥,MCU 仍能检测出异常。
SHA204A 芯片会通过 SHA256 算法计算内部密钥的哈希值,MCU 端则用相同的 SHA256 算法对同一密钥计算哈希值,若两者一致则判定校验通过。由于 MCU 与 SHA204A 芯片的通讯过程可能被捕获,为避免通讯层面的重放攻击,主机 MCU 可向 SHA204A 芯片提供一个随机数(challenge),实际计算的哈希值为 SHA256(key + challenge)。这样一来,即便密钥固定不变,每次计算的哈希值也会不同。
更进一步,若主机 MCU 没有安全的随机数发生器,搭配 NONCE 指令同样能避免重放攻击。具体流程为:主机先写入一个随机数(challenge,即便安全性不足也可),此时芯片内部会生成一个安全性极高的随机数(random)并返回给主机 MCU;芯片内部同时计算 token = SHA256(challenge + random),该 token 主机无法访问;随后 SHA204A 芯片进一步计算哈希值 = SHA256(key + token);MCU 端则用相同算法计算哈希值。这种方式虽流程更复杂,但能进一步提升安全性。
写到这里,我已基本理解该芯片的工作机制(滚动密钥等其他功能未进一步探索)。但该芯片能否成为硬件防克隆的可靠保障呢?这需要一个关键前提:MCU 内的固件需确保不被读取。若 MCU 固件被提取,意味着 MCU 侧存储的密钥存在泄露风险;一旦密钥泄露,SHA204A 的校验机制便会完全失效。
为何会存在这种风险?本质上是对称加密导致的问题:SHA204A 芯片与 MCU 内运行相同的加密算法、使用相同的密钥。这意味着,只要 MCU 内的信息泄露,整个系统就会被破解。因此,我们需要一种非对称加密机制来保障系统安全性 —— 加密芯片与 MCU 分别存储私钥和公钥,即便公钥泄露,也能确保系统安全。
SHA204A 的后续同类产品中,已有支持非对称加密的型号。以 ATECC608B 为例,它在兼容 ATSHA204A 的基础上,新增了密钥生成、密钥交换算法、签名与验签算法等非对称加密指令。但将其用于设备防克隆时,我认为仍存在应用缺陷:它无法写入自定义私钥,只能在芯片内部随机生成新私钥,再读取公钥。而我的设备需要批量生产,为保证设备固件的统一性,加密芯片内部的私钥最好能统一且由用户自行写入。
这类验证机制有哪些应用场景呢?目前多数 MCU 的 Flash 都具备读写保护机制,在这类场景下,可能无需额外使用独立加密芯片;但对于 Flash 外置的 MCU,加密芯片仍有其用武之地。以 RP2040 为例,该芯片本身不具备安全启动功能,用 RP2040 量产的设备,其固件存在被破解的风险。
最新的 RP2350 芯片新增了安全启动功能:通过 ECC 验签机制确保固件不被篡改,同时通过自定义 Bootloader 实现固件的 AES 加密。但该方案需将固件解密后加载到 SRAM 中运行,由于 SRAM 空间有限,对于固件体积较大的软件而言,此方案仍不适用。此时,搭配使用外置加密芯片或许是更优选择。
不过,外置加密芯片并非防止固件克隆的绝对安全方案:一旦固件被破解,攻击者可通过逆向固件、篡改关键代码执行流程,直接绕过外置加密芯片。尽管逆向固件的难度极高,但面对高价值设备,逆向其固件仍有利可图,因此风险依然存在。
行业内是否存在较好且通用的嵌入式固件防克隆解决方案呢?
由于我在这一领域接触有限,但我认为,在嵌入式场景下,几乎不存在完全通用的解决方案。防止固件克隆需要从软件、硬件多个层面综合实施防御策略:
物理不可克隆,避免固件被恶意提取。例如开启 Flash 读写保护、关闭调试接口等;
若无法避免固件被提取,则需确保固件全流程加密 —— 包括固件的部署、更新、执行环节,均需保护原始固件信息不被泄露;
安全启动与可信执行。固件全流程加密的前提是具备安全启动环境,在不可信环境中解密并执行固件,会存在信息泄露风险;
良好的软件设计。部分设计缺陷可能导致攻击者通过任意代码执行,进而 dump 出全部固件内容。