XMOS 的 OTP 加密:原理与完整烧录流程
用 xflash 烧进 SPI Flash 的镜像,默认是明文的:谁把 Flash 拆下来读一遍,就能拿到完整固件;改几个字节再烧回去,设备照样能跑。OTP 加密要解决的就是这三件事——防读取、防篡改、防克隆。
一句话结论:XMOS 不是「给 Flash 加个密」,而是把一段解密程序(xAES Module)和两把 128bit 密钥焊进片内 4KB OTP,再用三个安全位把芯片锁成 secure island。此后每次上电,Boot ROM 先把控制权交给 OTP 里的这段代码,由它认证并解密外部镜像;密钥永不出芯片,JTAG 被关掉,外部只能看到密文。这条路一旦 lock,不可回退。
一、明文镜像的三条攻击路径
先把威胁列清楚,才知道后面每个设计在防谁:
① 整片读取。SPI Flash 是标准器件,夹子一夹就能读出全部内容。拿到 .bin 就等于拿到固件,反汇编后可提取调音参数、算法结构。
② 重烧克隆。把镜像写进另一块板子,设备就变成一台「同款」——这是最常见的山寨路径。
③ 在线调试。只要 JTAG 还开着,就能挂上去读内存、改寄存器、单步绕过校验。
OTP 加密的三件套正好一一对应:密钥加密镜像堵住①,CMAC 认证堵住②,禁用 JTAG 堵住③。
二、硬件底座:4KB OTP 与 xAES
两块东西撑起了整个方案,理解它们的性质,后面的流程才讲得通。
OTP:一次性可编程存储
每个 tile 有独立的 4KB OTP,按 word 写入,写入即固化——一位从 0 变成 1 之后,没有任何办法变回去。它不是 Flash,不能擦除,没有第二次机会。应用代码可以通过 libotp 读它,但写只能由 xburn 完成;正常业务逻辑不应该去碰这块空间。
xAES Module:不是外设,是烧进 OTP 的代码
这是最容易误解的一点。xAES 不是某个加密外设的开关,它是一段由 XMOS 提供、随密钥一起烧进 OTP 的模块。上电时 Boot ROM 从 OTP 直接把它读出来执行,不经过 SPI——所以外部无法替换它。它掌握密钥寄存器,负责两件事:用 CMAC-AES-128 校验镜像真伪,用 AES-128 解密镜像正文。
换个角度理解:「能解开密钥的那段代码」本身被放在了不可修改的地方。密钥是数据,xAES 是读数据的程序,两者同住 OTP,缺一不可。所以加密镜像不是「加密了就能跑」,还必须在 OTP 里有配套的 xAES 模块。
三、两把钥匙,各管一件事
xburn --genkey keyfile 一次生成两把 128bit 密钥,写入同一个 keyfile。它们职责分明:
| 密钥 | 算法 | 负责什么 | 缺失后果 |
|---|---|---|---|
| CMAC 密钥 | CMAC-AES-128 | 认证镜像未被篡改 | 认证失败,Boot 停止 |
| AES 密钥 | AES-128 | 解密镜像正文 | 解不出明文,无法执行 |
为什么认证和解密要分开?因为顺序不能反:先认证,后解密。只有 CMAC 校验通过,说明这段密文确实出自持有密钥的人,才值得投入算力去解密;否则等于对一个不可信输入做解密运算,白白给攻击者提供侧信道。
两把钥匙合计只有 32 字节,但它们是整条链路上最值钱的东西。keyfile 是明文保存的,一旦泄露,别人就能生成一台「认证完全合法」的克隆机——芯片锁得再死也没用。所以 keyfile 的保管级别应当高于任何一份固件源码。
四、三个安全位,把芯片变成 secure island
密钥进了 OTP 还不算完。真正让芯片「不可旁路」的是三个一次性的安全位,它们组合起来才是 secure island:
| 安全位 | 效果 | 堵住了什么 |
|---|---|---|
| secure boot enable | 强制从 OTP 启动 | 改用 SPI / Link 启动绕过加密 |
| JTAG disable | 调试口永久关闭 | 挂调试器读内存、取密钥 |
| OTP write lock | 整个 4KB 不可再写 | 替换密钥或引导代码 |
三者齐备后,片内的所有计算、内存访问、I/O 与通信都在这颗 tile 的独占控制之下。同一批芯片,没有 keyfile 的人拿到手,只能烧出一个永远停在 Boot 阶段的砖。
五、上电之后到底发生了什么
把上面的零件串起来,就是一条固定的启动链。注意第 ③ 步的特殊性:它是唯一一次不经过 SPI 的代码加载。

[图 1 从复位到执行用户程序的七个阶段,以及认证失败时的分支]
① 复位。Boot ROM 开始执行,它是一段固化在芯片里的只读代码,不可修改。
② 读 OTP。检查 secure boot 位是否置起。没置位就走普通启动,加密方案完全不生效。
③ 执行 xAES Module。从 OTP 加载并跳入这段模块——不经过外部总线,因此无法被中间人替换。
④ 载入并认证 Flash Loader。xAES 通过 SPI 把 flash loader 读进片内,先用 CMAC-AES-128 验证它。loader 是后续读整个镜像的「钥匙串」,它本身必须是可信的。
⑤ 密钥入寄存器。认证通过后,两把密钥被放进 xAES 的密钥寄存器,应用代码无法读取;随后跳转到 flash loader。
⑥ 选镜像。loader 按优先级挑选:升级镜像从高版本往低版本逐个尝试,全部失败则回退到 factory 镜像。
⑦ 完整认证 + 解密 + 执行。对选中镜像做整镜 CMAC 认证与 AES 解密,按段表把各段载入 SRAM,跳到入口地址。
注意区分两种「失败」:④ / ⑦ 任一步认证不通过 → 直接停止,不降级、不继续,这是防篡改的核心;而⑥中某个镜像不存在或无法解析 → 属于正常回退,用 factory 镜像继续启动。认证失败绝不回退,否则攻击者只要破坏升级镜像就能把设备拉回一个旧版本。
六、开发期与量产,是两条不同的路
最常见的翻车都出在这里:拿量产的命令在开发阶段试,第一次烧就锁死了样片。两条路的根本区别只有一句话——开发期 OTP 不 lock,量产才 lock。

[图 2 同一条工具链,两种用法:上半程可反悔,下半程不可逆]
开发期:只验证加密链路通不通
用 xflash --key 烧一个加密镜像上板,跑一遍启动、音频、DAC 初始化。此时 OTP 尚未 lock,JTAG 仍可连接,改代码、换密钥、重烧都可以。这一步的目的是确认「密钥 → 镜像 → 启动」这条链没有断,而不是追求安全。
量产:一次性烧断
样机全部验证通过、keyfile 归档之后,才进入量产。顺序不能颠倒:先把密钥与 xAES 写进 OTP 并锁定,再关调试口、加主锁,最后用同一个 keyfile 离机生成加密镜像文件交给产线烧录器。
| 阶段 | 命令 | 作用 |
|---|---|---|
| 生成密钥 | xburn --genkey keyfile | 产出 CMAC + AES 两把 128bit |
| 查看 OTP | xburn -l | 确认当前是否已写入 / 已锁 |
| 试烧镜像 | xflash --id a.xe --key keyfile | 开发期验证,OTP 保持可改 |
| 写入并锁定 | xburn --id --lock keyfile --target-file target.xn | 不可逆:密钥固化、OTP 锁死 |
| 关闭调试 | xburn --id --target-file target.xn --disable-jtag --enable-master-lock | 不可逆:JTAG 关闭、主锁生效 |
| 出镜像 | xflash a.xe -key keyfile -o image-file | 离机生成,交产线批量烧录 |
顺序警告:如果先执行 --disable-jtag 再发现镜像烧错,就既改不了 OTP 里的密钥,也连不上调试器——整批芯片只能报废。稳妥做法:首片只做 --lock 不关 JTAG,整机跑通后再对同批次执行锁定并留档记录。
七、4KB 里到底装了什么
很多人以为 OTP 里只存了两把密钥,其实密钥只占 32 字节,真正占地方的是那段能解开密钥的代码:

[图 3 OTP 内部的功能分区(地址为示意,实际偏移由工具版本决定)]
密钥只进不出。两把 128bit 密钥在 OTP 内供 xAES 使用,无法通过任何接口读出。JTAG 关闭之后,连片内调试通路也断了;想换密钥,只能换芯片。
xAES Module 是固件,不是配置。它随 --lock 一起写入,由 XMOS 提供,版本必须与工具链匹配。
写错就是报废。OTP 没有第二份 4KB,地址写偏一个 word 或 keyfile 拿错一个版本,都没有回退手段。
八、排错清单:六个典型现象
| 现象 | 根因 | 处理 |
|---|---|---|
| 烧完不启动,JTAG 也连不上 | secure boot 已置位,但镜像未加密或密钥不符 | 换片,无软件手段 |
| 能启动,音频无输出 | 镜像段表未完整打包,某段被裁掉 | 用 xflash -o 重新生成完整镜像 |
| xflash 报认证失败 | keyfile 与 OTP 内的密钥不是同一份 | 核对归档件,别用新生成的 |
| 同批部分机器不启动 | 产线烧录器未做写后校验 | 烧录器开启 verify + 记录序列号 |
| xburn -l 读不到内容 | 已 enable-master-lock | 属正常现象,回读被禁止 |
| 想改一行代码重烧 | OTP 已锁,只能换镜像不能换密钥 | 沿用原 keyfile 重新出镜像 |
九、该用,还是先别用
适合上:进入量产的整机产品、声学参数与算法构成核心资产、市场上有同款被克隆的风险。先别上:算法还在频繁试错、需要现场抓内存定位问题、尚无能力管理 keyfile 的团队——此时锁定 OTP 只会把调试成本放大十倍。
最后一句提醒:加密保护的是「固件不被拿走」,不是「设备不被破解」。如果攻击者能物理接触设备并读出模拟信号、录音回放、重刷 SPI Flash 的合法旧镜像,OTP 加密都拦不住——它只解决固件保密与完整性这一层。安全方案要按威胁模型逐层设计,而不是买一个开关就以为万事大吉。