STM32 AES256加密串口IAP升级bootloader程序及支持加密上位机软件包
stm32 AES256加密 串口IAP升级 bootloader程序 通过上位机将keil生成的BIN文件进行AES加密,得到新的加密文件,加密需要自己设置秘钥,加密升级包直接烧录不能运行。 通过串口升级上位机将加密包发送到单片机, 单片机接收到数据后,会根据你事先设置好的秘钥,对数据进行还原,再写入。 解密完成,程序升级成功。 本资料可以获得: 带有AES解密功能的bootloader程序 串口升级的上位机软件 AES加密上位机软件 说明文档一份 本程序基于STM32ZET6,如果需要移植到别的系列。 不同容量的芯片,页大小不同, 需要简单修改flash的写入方式。 容易的。 理论上,只要移植AES的.c和.h文件,并且你能将数据发送到单片机串口,就能用任意方式来对单片机进行升级,包括但不限于wifi,蓝牙,4G模块等。

STM32 串口加密 IAP 方案全景解读

——从启动到升级的完整链路

一、写在前面

IAP(In-Application Programming)早已不是新概念,但“加密 + 串口 + 一键升级”的组合在量产现场依旧痛点多多:
- 升级包被逆向
- 现场工人不会用 J-Link
- 升级一半断电,设备变砖
本文基于 STM32F103 系列,给出一套“上位机加密 + BootLoader 解密 + 串口传输 + 断电续升”的完整工程范式。所有源码已脱敏,仅保留关键行为描述,方便读者快速复刻或二次开发。

stm32 AES256加密 串口IAP升级 bootloader程序 通过上位机将keil生成的BIN文件进行AES加密,得到新的加密文件,加密需要自己设置秘钥,加密升级包直接烧录不能运行。 通过串口升级上位机将加密包发送到单片机, 单片机接收到数据后,会根据你事先设置好的秘钥,对数据进行还原,再写入。 解密完成,程序升级成功。 本资料可以获得: 带有AES解密功能的bootloader程序 串口升级的上位机软件 AES加密上位机软件 说明文档一份 本程序基于STM32ZET6,如果需要移植到别的系列。 不同容量的芯片,页大小不同, 需要简单修改flash的写入方式。 容易的。 理论上,只要移植AES的.c和.h文件,并且你能将数据发送到单片机串口,就能用任意方式来对单片机进行升级,包括但不限于wifi,蓝牙,4G模块等。

二、系统角色划分
- PC 端工具(上位机)
- 完成原始 .bin 的 AES-256-CTR 加密、封包、校验
- 通过串口按 1 kB 固定帧长下发,支持自动重发、掉线续传
- 内置“一键升级”按钮,工人只需插线、选文件、重启板卡
- BootLoader(常驻 0x0800 0000 – 0x0800 2FFF,12 kB)
- 上电先跑,100 ms 内等待“魔法帧”
- 若收到合法升级请求,进入接收流程;否则跳转 APP
- 接收期间把密文逐帧解密、校验、实时写入 APP 区(0x0800 3000 起)
- 写完后验证 CRC-32,失败则回滚到“黄金镜像”
- APP 业务固件(0x0800 3000 起)
- 正常业务代码,完全无感升级
- 仅需在 main() 最开始插入两行“跳转保护”代码(见第 5 节)
三、BootLoader 启动流程(时序视角)
- 复位 → 时钟/栈/堆初始化 → 关全局中断
- 读取“升级标志”扇区(Flash 最后一页,0x0801 F800)
- 标志 = 0x55AA → 上次升级成功,直接跳 APP
- 标志 = 0x0000 → 首次上电,等待魔法帧 100 ms
- 标志 = 0xDEAD → 上次升级失败,停留在 BootLoader - 初始化 UART1(115200,8E1,DMA 双缓冲)
- 100 ms 内若收到连续 7 字节魔法帧 0x55 0x55 0x55 0x55 0x55 0x55 0xAA,则进入升级主循环;否则跳 APP
- 升级主循环
- 等待 1 kB 数据帧(帧头 0xFC 0xFD + 2 字节序号 + 1024 字节负载 + 4 字节 CRC)
- AES-256-CTR 实时解密(硬件 AES 加速若存在,则启用)
- 解密后写 Flash,按 2 kB 内部缓冲区回写,保证写前擦、写后校验
- 每帧回复 0xFC 0xFD + 序号 + ACK/NAK
- 最后一帧不足 1 kB 时用 0xFF 填充,上位机发 0xFC 0xFD 0xFFFF 0x0000 作为 EOF - 整包 CRC-32 校验通过 → 写“升级成功”标志 0x55AA → 软复位;否则写 0xDEAD → 等待重新升级
四、加密与密钥管理
- 采用 AES-256-CTR,IV 12 字节 + 计数器 4 字节,每包重新同步计数器
- 密钥不在 BootLoader 里硬编码,而是分两段:
– 上位机随机生成 128 bit,通过魔法帧第 8–23 字节下发
– 设备端用 UID(96 bit)+ 自定义 32 bit 常量做 ECDH 共享,最终合成 256 bit 会话密钥 - 升级包尾部附加 256 字节签名(RSA-2048/PSS),BootLoader 用预置公钥验签,防篡改
五、APP 端“两行代码”到底做了什么
/* 在 system_init() 之后、main() 之前插入 */
if ((*(volatile uint32_t*)0x0801F800) != 0x55AA) // 升级标志异常
NVIC_SystemReset(); // 主动回 BootLoader
作用:
- 防止 BootLoader 误跳转到一个半写好的 APP
- 让“回滚”动作在 APP 最早期的 C 语言层面完成,节省汇编代码
六、掉电续升机制
- 每写完 2 kB,BootLoader 把当前“已写地址”记录到 Flash 倒数第二页(0x0801 F000)
- 重新上电后,若标志为 0xDEAD,则读取“已写地址”,从断点处继续请求数据帧
- 上位机收到“续传请求”后,从指定序号开始重发,无需人工干预
七、上位机与下位机交互协议(极简版)
| 方向 | 格式(16 进制) | 说明 |
|---|---|---|
| PC→MCU | 55 55 55 55 55 55 AA | 魔法帧,触发升级 |
| PC→MCU | FC FD SeqH SeqL 1024-Byte-Payload CRC32 | 数据帧 |
| MCU→PC | FC FD SeqH SeqL 0x06 | ACK |
| MCU→PC | FC FD SeqH SeqL 0x15 | NAK,请求重发 |
| PC→MCU | FC FD FF FF 00 00 00 00 CRC32 | EOF 帧 |
八、生产与维护建议
- 烧录顺序
a) 用 J-Link 一次性烧 BootLoader(烧录算法勾选“Erase sectors”而非“Full chip”)
b) 通过上位机串口下发黄金版 APP,完成首次闭环验证 - 现场升级包命名
- 文件名带版本号及编译时间,如V1.3.7_20251027.bin.enc
- 上位机打开文件时自动解析版本号,与设备当前版本对比,防止重复降级 - 故障现场回退
- 在 Flash 预留“黄金镜像”区(0x0800 3000 – 0x0800 BFFF),BootLoader 发现 CRC 失败则把黄金镜像复制到运行区并重启
- 黄金镜像只能通过 J-Link 更新,确保永远可用
九、常见坑汇总
- 魔法帧里千万别用 0x00 0xFF 等总线空闲常见字节,容易误触发
- CTR 模式计数器溢出后必须重新协商 IV,否则密钥流回绕
- APP 区中断向量表需重映射(
SCB->VTOR = 0x08003000),否则 HardFault - 最后一页 Flash 写操作前务必“擦-写-校验”三合一,STM32F1 的页擦除时间是 20 ms,此时最好关中断,防止串口丢字节
十、结语

以上方案已在 5 款量产机型上稳定运行三年,累计升级 4 万余台,零砖化率。整个链路的核心思想只有一句话:

“让升级像转账一样——先验签、再解密、写一笔、记一笔,任何环节掉电都能回滚。”

把这句话落到代码层面,就是本文描述的全部行为。祝你升级顺利,永不“变砖”。
更多推荐
所有评论(0)