MCU(微控制器单元)的加密方法可以从硬件、软件和通信协议三个层面来理解。以下是常见的MCU加密手段,按类型分类说明:
针对目前 STM32 系列微控制器在程序加密保护方面手段单一、保护效果有限的问题,本文介绍并分析了四种常用的程序保护方法:
-
闪存读写保护
-
芯片唯一 ID 验证
-
外接加密芯片
-
引导程序加密(Bootloader 加密)
实际在 STM32 开发板上的测试表明,合理组合多种保护机制,能显著增强芯片程序与数据的安全性,有效防止闪存程序被读取、拷贝或篡改,为嵌入式系统提供更可靠的安全保障。
1 闪存读写保护法
STM32 微控制器提供了闪存读写保护的功能,
用来防止对闪存的非法访问。 闪存读写保护功能概述:
读保护(RDP)
-
通过修改 Option Bytes 中的 RDP位来启用。
-
启用后,Flash 只能被内部正常执行的程序读取,无法通过 JTAG/SWD 调试接口或从 RAM 启动的程序读取。
-
解除读保护会触发整片 Flash 擦除,防止逆向工程与调试工具破解。
-
以 STM32L1 系列为例,RDP 分为 3 个等级,不同等级对应不同的安全强度。
等级 | 描述 |
---|---|
0 | 无保护(默认)。可以通过 JTAG/SWD 或从 RAM 启动的程序任意读取 Flash。 |
1 | Flash 受保护,防止由调试器(JTAG/SWD)直接读取,也不能通过在 RAM 中加载执行程序来读取。 解除 Level 1 保护将触发全片擦除。 |
2 | 最严格保护------禁用所有调试功能。 一旦设为 Level 2,不可复原,需谨慎使用。 |
写保护(WRP)
-
通过在 Option Bytes 中设置 WRP位来启用。
-
启用后,对被保护页的任何写或擦除操作都会被硬件阻止,并在状态寄存器中产生错误标志。
-
可以防止恶意修改中断向量表或关键代码区域。
优缺点对比:
优点:
由硬件层面直接提供,成本为零,易于配置。
能有效防止通过调试接口的非法读写。
缺点:
单一的读/写保护难以抵抗高级物理攻击或侧信道分析。
需要与软件层面的校验(如 CRC、HASH)或更高级的加密方法(如外部加密芯片、Bootloader 加密)组合,才能构建更完善的防护体系。
实施的方法如下,下面以 STM32G4 系列为例,分别介绍如何通过 ST-Link/CubeProgrammer 工具以及 运行时(HAL)编程 两种方式来启用 Flash 的读写保护(RDP 和 WRP)。
方法一:通过 STM32CubeProgrammer 界面设置
打开 CubeProgrammer
启动 STM32CubeProgrammer,选择 "ST-Link" 连接。
读取当前 Option Bytes
在左侧菜单选择 "Option Bytes"。
点击 "Read",查看当前 RDP(Read Protection)和 WRP(Write Protection) 配置。
配置读保护(RDP)
在 "Read protection" 下拉框中选择:
Level 0:无保护
Level 1:Flash 只允许内部执行读取
Level 2:全部调试接口禁用(不可逆)
推荐一般项目选 Level 1。

配置写保护(WRP)
在 "Write protection" 区域,勾选你要保护的 Flash 扇区(Page)。
比如要保护第 0~3 扇区,就勾选对应页号。

写入并重启
点击 "Apply",CubeProgrammer 会提示需要复位芯片以生效。
确认后,设备重启,Option Bytes 即更新完毕。
方法二:在用户代码中动态配置(HAL 库示例)
如果希望在程序首次运行时,或通过 Bootloader 进行保护设置,可以在固件内部调用 HAL API 来修改 Option Bytes。

cpp
/**
* @brief 启用 RDP Level1 并对指定扇区启用写保护
* @note 必须在系统启动早期执行,且芯片复位后才生效
*/
void Protect_Flash(void)
{
HAL_FLASH_Unlock();
HAL_FLASH_OB_Unlock();
/* 1) 读保护 → Level1 */
FLASH_OBProgramInitTypeDef OBInit = {0};
OBInit.OptionType = OPTIONBYTE_RDP;
OBInit.RDPLevel = OB_RDP_LEVEL_1;
if (HAL_FLASHEx_OBProgram(&OBInit) != HAL_OK) {
/* 错误处理 */
}
/* 2) 写保护 → 保护第 0~15 KB(页 0~15) */
memset(&OBInit, 0, sizeof(OBInit));
OBInit.OptionType = OPTIONBYTE_WRP;
OBInit.WRPState = OB_WRPSTATE_ENABLE;
OBInit.WRPPage = OB_WRP_PAGES0TO3
| OB_WRP_PAGES4TO7
| OB_WRP_PAGES8TO11
| OB_WRP_PAGES12TO15;
if (HAL_FLASHEx_OBProgram(&OBInit) != HAL_OK) {
/* 错误处理 */
}
HAL_FLASH_OB_Lock();
HAL_FLASH_Lock();
// /* 复位生效 */
// NVIC_SystemReset();
}

其次你会发现程序也烧写不进去。此时目标也达成。
我们说了加密,**那如何解密呢?**问题在于每次切换RDPLevel 1到0的过程中的时候,会将flash的内容全部擦除。因此这是解密的难点之一。

我们引入思考点一,针对闪存读写保护法这类内容也就是寄存器置位,如果你要切换RDP1到RDP0 的过程伴随着一个问题,STM32 上的 Read-Out Protection(RDP)并不是真正的"加密",而是一种硬件级的"只读保护"机制------它保证 任何 试图"解开"这层保护的操作(也就是把 RDP 从 Level 1 降回 Level 0),都会触发一次整片 Flash 的 不可逆擦除,从而根本不可能在芯片上恢复出原来的固件!!!
一旦启用 RDP Level 1,就不可能在器件内"解密"或"读取" Flash 内容;任何试图取消保护的行为都会把所有数据抹掉。
为什么不能"解密"现有固件???
STM32 的 RDP 设计上就是「不可逆保护」:降级就擦除。
Flash 中的代码以明文形式存储,Option Bytes 保护只是阻止「直接」访问,但并不做真实的加密。
一旦需要「访问明文」,只能通过内部执行(CPU 跳转),而不是通过调试器或外部读口。
因此问题点来了!!!我们要做的是,在启用了 RDP Level 1 以后,所有基于 JTAG/SWD 或 外部调试器 的直接读 Flash 操作都会被阻止------硬件层面上不可能再通过外部工具把 Flash 整片"拷"出来 。不过,RDP Level 1 并不影响 MCU 自身程序对 Flash 的正常读取;换句话说,你只要在芯片内跑一段用户代码,通过 UART/CAN/USB 等总线把 Flash 内容"转发"出去,就能获得完整的二进制镜像。
20250513 23:38待补全。。。