STM32 的加密实现

文章正文
发布时间:2024-09-08 12:06

目的:对运行于STM32的嵌入式代码程序进行加密

编译环境:IAR Embedded System for ARM5.5

一.STM32Flash组织

STM32的Flash包括主存储器(HD版本,512KB)+信息块。信息块包括2KB的系统存储器(用于系统自举启动代码)和16字节的选项字节(8个字节数据+8个字节数据的反码)。

二、STM32读保护

STM32读保护是通过设置RDP选项字节,然后在系统重新复位加载了新的RDP选项字节后启动的。当保护字节被写入相应的值以后:

●通过从内置SRAM或FSMC执行代码访问主闪存存储器的操作,通过DMA1、DMA2、JTAG、SWV(串行线观察器)、SWD(串行线调试)、ETM和边界扫描方式对闪存的访问都将被禁止。

●只允许从用户代码中对主闪存存储器的读操作(以非调试方式从主闪存存储器启动)。

●第0~3页(小容量和中容量产品),或第0~1页(大容量和互联型产品)被自动加上了写保护,其它部分的存储器可以通过在主闪存存储器中执行的代码进行编程(实现IAP或数据存储等功能),但不允许在调试模式下或在从内部SRAM启动后执行写或擦除操作(整片擦除除外)。

●所有通过JTAG/SWD向内置SRAM装载代码并执行代码的功能依然有效,亦可以通过JTAG/SWD从内置SRAM启动,这个功能可以用来解除读保护。当读保护的选项字节转变为存储器未保护的数值时,将会执行整片擦除过程。

●可以使用系统启动程序解除读保护(此时只需执行系统复位即可重新加载选项字节),芯片自动擦除Flash所有内容。

三.STM32的加密

1.使用系统启动程序STM32 Flash Loader demonstrator将Flash设置为读保护。

所有以调试工具、内置SRAM或FSMC执行代码等方式对主存储器访问的操作将被禁止,只允许用户代码对主Flash存储器的读操作和编程操作(除了Flash开始的4KB区域不能编程)。用户代码允许自主编程可以实现IAP或者数据存储等功能。

这样破解者将不能用调试工具、内置SRAM或者FSMC执行代码等方式读出Flash中的代码。破解者也不能使用系统启动程序读取代码,因为要解除读保护,将执行整个芯片的擦除操作。

2.主程序中使用设备ID保护

即使将Flash设置为读保护,破解者也可以通过IAP下载自己的一段小程序,从而读出Flash中的内容。因此,还需要利用设备的唯一ID进行加密保护。在主程序中,加入对设备唯一ID的检测,这样即使破解者读出了芯片中的二进制码,也不能用这个二进制码去复制新的器件。具体实现方法:

(1)在应用程序中定义1个(32位甚至更多)const变量,变量值全为0xFF。每次启动程序时,检查const变量值如果全为0xFF,就读器件的唯一ID,通过Flash编程写入该const变量中(因为全是0xFF,所以可以编程写入)。

(2)在程序中多个地方检查const变量,如果变量值不为0xFF并且与设备ID不一致,就执行与功能无关代码(比如自擦除)。

这样,即使破解者读出了芯片中的二进制码,因为这份二进制码包含了设备唯一ID,具有唯一性,所以不能复制到其他芯片中。

为了避免破解者利用反汇编,根据芯片ID数据在二进制文件中查找对应相同数据的位置从而破解,可以将ID拆散成不同的组合,并且写到不同且不连续的地方。更进一步,可在程序中检测多份这样的分散ID,以增加反汇编的难度。或者将CPUID进行加密,Flash中存储加密后的结果。

四.程序加密的实现

//加密后的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]);  

1、将写入加密数据和判断加密两个功能分开。写入加密在PrsCtrlTask开始的地方;而判断加密分布到程序的各个角落。

2、非常重要的是CPUID加密值的定义一定要加“volatile”类型:

volatile const static uint32 CPUIDEncrypt = 0xFFFFFFFF;

否则按速度优化编译,在判断加密值,不会重新读取加密值,导致判断出错。

3、在工程选项Options->Debugger->Download中选择: use flash loader

否则主程序中对Flash编程将不成功。


关键字:STM32  加密 引用地址:STM32 的加密实现

上一篇:STM32F4时钟系统初探(二)
下一篇:基于STM32F103的ID号对应用程序的保护方法

推荐阅读最新更新时间:2024-03-16 15:32

GD的抗干扰能力为何不如STM32

GD32是国内开发的一款单片机,据说开发的人员是来自ST公司的,GD32也是以STM32作为模板做出来的。所以GD32和STM32有很多地方都是一样的。 不过GD32毕竟是不同的产品,不可能所有东西都沿用STM32,有些自主开发的东西还是有区别的。 相同的地方我们就不说了,下面列一下不同的地方。 内核 GD32采用二代的M3内核,STM32主要采用一代M3内核,下图是ARM公司的M3内核勘误表,GD使用的内核只有752419这一个BUG。 主频 使用HSE(高速外部时钟):GD32的主频最大108M,STM32的主频最大72M 使用HSI(高速内部时钟):GD32的主频最大108M,STM32的主频最大64M 主频

[单片机]

GD的抗干扰能力为何不如STM32

STM32 CAN模块使用

简介:STM32 CAN模块使用详解.重点介绍以STM32F103E系列芯片为基础介绍CAN 总线的使用方法。CAN 总线在控制领域使用的非常广泛,如今大多数CPU芯片外围都扩展CAN接口。 1. 硬件基础 CAN总线工作需要两根数据线,RX和TX,即为输入总线和输出总线。一般CPU与外界通信需要接一个驱动芯片(这点很像UART接口),常用的CAN芯片主要有:SN65VHD230、PCA82C250T等,本系统使用SN65VHD230作为CAN接口芯片。而CPU提供的CAN接口为CAN_L和CAN_H。 2. 软件设计 在进行软件设计时,我们首先来看这样的一个结构体: typedef struct { uint32_t S

[单片机]

stm32 mpu6050 模拟i2c实例实现

最近准备一个比赛,所以正在加紧学习stm32,这篇文章就结合mpu6050分析一下利用i2c实现芯片之间的通信。 首先可以在原有的LED文件或显示屏(OLED)的文件基础上,新建一个HANDWARE,在其中加入mpu6050.c和mpu6050.h(名字自定)。 首先是在C文件中加入基本的I2C通信函数 1.I2C的GPIO端口初始化SDA、SCL设置为推挽输出。 2.然后是i2c_start();i2c_stop();函数,根据时序图设置SCL、SDA的高低电平变化。 3.之后加入主机ack的响应函数和ack的等待响应函数i2c_wait_ack();i2c_ack();i2c_wai

[单片机]

stm32 mpu6050 模拟i2c实例实现

使用STM32的USB模块中后对USB缓冲区的认识

最近在使用STM32的USB模块开发个项目,还以为挺简单,结果搞了快两天才把USB的包缓冲区的访问搞定,在此做个小总结吧。 STM32的USB模块包缓冲区有512B,但是在STM32的参考手册中的存储器映像中却表明0x40006000-0x400063ff,整整多了512B,怎么会这样呢,同时在尝试着编程时也遇到了一个问题: 在usb_core.c文件的Setup0_Process(void)这个函数中,有这么一段: uint16_t offset = 1; if (pInformation- ControlState != PAUSE) { pInformation- USBbmRequestType = *pBuf.b

[单片机]

Stm32的ADC功能介绍及相关代码

特性 此图来自中文参考手册,作为下面的整体概述。 ADC正常工作时的电路连接: ADC的内部结构图: 从上面的内部结构图可以看出stm32与其他低端的单片机不同的地方是:可以通过定时器事件触发ADC的转换,但只支持注入通道。那么注入通道和规则通道又是什么? 注入通道与规则通道: 上面的图形象的说明了注入通道与规则通道的区别:规则通道相当于正常的程序运行一通道完成后接着另一通道(当然这要开启连续或者扫描模式才行),而注入通道相当于程序的中断,也就是说它可以打断规则通道的ADC转换去优先转换另一条同的ADC转换;比如说在连续转换中现在转换到了2通道,此时因为定时器事件发生触发ADC去转换配置为注入通道的通道4,转

[单片机]

Stm32的ADC功能介绍及相关代码

STM32进入睡眠模式下的GPIO配置参考

1. GPIO内部电路图 1.根据设备原理图查看IO外部引脚连接电路,闲置状态为低电平时,设置为下拉输入;闲置状态为高电平时,设置为上拉输入;闲置状态为悬空时设置为模拟输入;输出引脚根据功能需要设置就行 原因:当IO通过外围电路电阻接地被拉低时,如果设置为上拉输入,则在芯片内部的上拉电阻和外围的下拉电阻构成回路,电流损耗取决于这两个电阻;当IO通过外围电路电阻接电源被拉高时,则在芯片内部的下拉电阻和外围的上拉电阻构成回路,电流损耗也取决于这两个电阻;当悬空时,斯密特触发器是打开的,要判断输入的是高电平还是低电平,需要一点电流损耗,但是设备模拟输入,这个触发器是关闭的 --------------------- 假设你的这个GP

[单片机]

STM32进入睡眠模式下的GPIO配置参考

【STM32 Cotex-M3处理器系列编程】按键灯亮

//分别按下S1~S4,D1~D4分别点亮 #include stm32f10x.h void Delay(unsigned int x); int main(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE,ENABLE);//IO口使能设置 GPIO_InitTypeDef GPIO_InitStructure; //定义结构体 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //LED管脚

[单片机]

STM32 通用定时器的一些概念解析

STM32一共有8个定时器,其中定TIM1和TIM8为高级控制定时器,除了具有通用定时器的功能外,还兼具控制功能,不仅能够输出PWM还可以采集编码器,驱动各种电机的功能。而基本定时器TIM6和TIM7一般不用作普通定时器,一般会给别的定时器提供基准时钟信号。 对于通用定时器TIM2~TIM5,基本的功能就不描述了,主要是看这些通用定时器如何使用: TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_DeInit(TIM2); //重新将Timer设置为缺省值 TIM_InternalClockCo

[单片机]