STM32对flash中程序的加密保护

2024.7.14

今天学习了很多关于STM32对于程序的保护措施,原先一直不理解为什么DF CAR需要做加密,他的加密流程我也不是很知道,后面发现他是在控制任务初始化的时候,加了一个判断flash中某个区域的数值的程序,如果判断失败就while(1)不断地判断,这个值如何被修改呢,就是上位机下发一个STM32的chip id,这个Id位于0x1FFF7A10的位置,每个芯片有自己专属的UID,我的STM32板子接收到了之后,和自身的UID进行比对,如果正确就烧写flash中那个位置的值,完成激活。

这存在一个缺点,就是别人可以抓取我们激活的数据流,很容易伪造一个DF LINK,来激活他们仿造的板子,并且我们的板子也没有加读保护,别人可以随意读取我们的hex程序。

首先我们来解决读保护的问题。读保护寄存器在flash的选项字节的位置存储,可以通过软件或者ST uinity进行打开和关闭,如果打开了读保护,那么就会禁用SWD等调试接口,但是可以通过串口来更新程序,因此一般会有bootloader程序,开启读保护之后,通过bootloader程序进行串口下载程序。

STlink utility设置如下:将读保护等级设置为1就好,等级0是无读保护,等级2是设置了之后无法取消读保护,这个是永久性的,慎用!,开启读保护之后,就不可以用ST link读取芯片的hex了。

如果想解除读保护,只需要将原先的等级1变成等级0就好,但是这会进行全片擦除,芯片内的所有代码都被擦除掉。

下面是RDP(读保护)不同等级的一览表。

软件读保护的代码如下,自行理解

c 复制代码
#include "stm32f4xx_hal_flash.h"
#include "stm32f4xx_hal_flash_ex.h"
#define __READ_PROCETION  0  //使能Flash读保护
typedef enum
{
        LEVEL0 =0xAA, //无保护
        LEVEL2 =0x55, //读保护
   //   LEVEL2 =0xCC, //最高的等级,设置后无法返回LEVEL0和LEVEL1
}Flash_Procetion_LEVEL;

void Flash_ReadOutProtection(uint8_t level)
{
	uint8_t RDP_Level = 0;

	RDP_Level = FLASH_OB_GetRDP();

	FLASH_OB_RDP_LevelConfig(level);

	RDP_Level = FLASH_OB_GetRDP();
}

int main(void)
{
	.....
	//加入flash只读写保护
	#if __READ_PROCETION
		HAL_FLASH_Unlock();
		HAL_FLASH_OB_Unlock();				//解锁Flash控制寄存器访问权限
		Flash_ReadOutProtection(LEVEL1);  	//设置Flash读保护等级为1
		HAL_FLASH_OB_Launch();			  	//启动加载
		HAL_FLASH_Lock();
		HAL_FLASH_OB_Lock();				//上锁Flash控制寄存器访问权限
	#endif
	.......
}

然后就是解决别人抓取到我们的数据流,激活的问题

整体思路就是单片机读取自身的UID,然后将这三个ID进行运算,将计算结果保留到一个volatile const static uint32的数据中,注意这个是const数据,如果要修改,就需要使用FLASH编程函数,也要注意这个数据初始化的时候要是FFFF,因为FLASH只能从1擦0。这个加密算法很重要,需要着重考虑,然后上位机这边从服务器抓取到相应的UID之后,也进行同样的计算,发送DF LINK的时候,就发送加密数据~!

c 复制代码
//加密后的CPUID  
volatile const static uint32 CPUIDEncrypt = 0xFFFFFFFF;  
//写入加密数据 
void WriteEncrypt(void)  
{   
    //第一次烧写:将UID写入到Flash中  
    if(CPUIDEncrypt==0xFFFFFFFF)  
   {  
        uint32_t CpuID[3];         
        //获取CPU唯一的ID  
        CpuID[0]=*(vu32*)(UID_BASE);  
        CpuID[1]=*(vu32*)(UID_BASE+4);  
        CpuID[2]=*(vu32*)(UID_BASE+8);         

        //加密算法,很简单的加密算法  
        uint32_t EncryptCode=(CpuID[0]>>3)+(CpuID[1]>>1)+(CpuID[2]>>2);    
        FLASH_Unlock();  
        FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);  
        FLASH_ProgramWord((uint32_t)&CPUIDEncrypt, EncryptCode);  
        FLASH_Lock(); 
    }  
} 
//判断加密  
bool JudgeEncrypt(void)  
{       
    uint32_t CpuID[4];        
    //获取CPU唯一的ID   
    CpuID[0]=*(vu32*)(UID_BASE);  
    CpuID[1]=*(vu32*)(UID_BASE+4);  
    CpuID[2]=*(vu32*)(UID_BASE+8);      
    //加密算法,很简单的加密算法  
    CpuID[3]=(CpuID[0]>>3)+(CpuID[1]>>1)+(CpuID[2]>>2);     
    //检查Flash中的UID是否合法   
    return (CPUIDEncrypt == CpuID[3]);  
}
相关推荐
qq_459730032 小时前
4-3 MCU中ARM存储器的作用
arm开发·单片机·嵌入式硬件
嵌入式科普5 小时前
嵌入式科普(24)从SPI和CAN通信重新理解“全双工”
c语言·stm32·can·spi·全双工·ra6m5
重生之我是数学王子5 小时前
点亮核心板小灯 STM32U575
stm32·单片机·嵌入式硬件
end_SJ5 小时前
初学stm32 --- 定时器中断
stm32·单片机·嵌入式硬件
南城花随雪。5 小时前
单片机:实现数码管动态显示(0~99999999)74hc138驱动(附带源码)
单片机·嵌入式硬件
南城花随雪。8 小时前
单片机:实现信号发生器(附带源码)
单片机·嵌入式硬件
灵槐梦9 小时前
【速成51单片机】2.点亮LED
c语言·开发语言·经验分享·笔记·单片机·51单片机
三月七(爱看动漫的程序员)10 小时前
HiQA: A Hierarchical Contextual Augmentation RAG for Multi-Documents QA---附录
人工智能·单片机·嵌入式硬件·物联网·机器学习·语言模型·自然语言处理
新晨单片机设计11 小时前
【087】基于51单片机智能宠物喂食器【Proteus仿真+Keil程序+报告+原理图】
嵌入式硬件·51单片机·proteus·宠物·ad原理图
大风起兮1211 小时前
STM32HAL库中RTC闹钟设置时分秒,年月日
stm32·嵌入式硬件