软件层面对单片机程序进行加密

软件层面对单片机程序进行加密

前言:再项目中按照要求需要对程序进行加密,可以使用硬件加密和软件加密。

硬件加密

就是使用外部芯片,首次上电的时候读取id后通过加密算法将密钥存储在外部介质中,每次运行的时候都从外部芯片读取的密钥进行匹配。这个是比较牢靠的,而且可以使用更加复杂的加密算法,但是这样需要外挂芯片导致了一个最根本的问题,成本增加,并且也不适合量产。

硬件加密芯片介绍 及 加密芯片选择(加密IC) 加密芯片原理-CSDN博客

硬件加密芯片的使用及适配(CC020加密芯片)_海思如何与加密芯片通信-CSDN博客

https://www.gd32mcu.com/data/documents/applicationNote/AN073_Proper_use_of_UID_for_firmware_protection_Rev1.0_CN.pdf

软件加密(固件加密)

  1. 固件加密:最节约成本的方式就是使用软件进行加密。流程: ①定义全局变量const uint32 UID = 0xFFFFFFFF;

    • 定义uint32 uid_save = 0xFFFFFFFF;

    • 定义const uint32 uid_save = 0xFFFFFFFF;

    ②第一次上电后判断UID是0xFFFFFFFF时,读取单片机的ID后经过加密算法将密钥存储在UID中,以后每次运行都需要判断密钥才可以正常运行。

     /**************************************************************************
     * 函数名称: getEncryptID
     * 功能描述: 获取并加密ID
     **************************************************************************/
     u32 getEncryptID(u32 *p_id)
     {
         p_id[0] = *(vu32*)(UID_BASE);
         p_id[1] = *(vu32*)(UID_BASE + 4);
         p_id[2] = *(vu32*)(UID_BASE + 8);
      
         return ((p_id[0] >> 3) + (p_id[1] >> 1) + (p_id[2] >> 2));  //加密算法
     }
     /**************************************************************************
     * 函数名称: judgeEncryptID
     * 功能描述: 判断加密ID
     **************************************************************************/
     u8 judgeEncryptID(void)
     {
         u32 t_encid;
         u32 t_cpuid[3];
         u32 t_addr = 0;
         u32 t_flashid;
         u32 p[3];
         t_encid = getEncryptID(t_cpuid);    //读本机UID
         
         p[0] = *(vu32*)(UID_BASE);
         p[1] = *(vu32*)(UID_BASE + 4);
         p[2] = *(vu32*)(UID_BASE + 8);
         
         t_addr = (u32)&uid_save;
         if(*(vu32 *)t_addr == 0xFFFFFFFF)   //第一次烧写将加密后的UID写入FLASH
         {
             FLASH_Unlock();
             FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP);
             FLASH_ProgramWord(t_addr, t_encid);//写UID
             FLASH_Lock();
         }
         t_flashid = *(vu32 *)t_addr;        //第一次上电存完了之后需要再读一遍
         
         return (t_flashid == t_encid);
     }

    这样哪怕有人读取了固件,但是固件中错误的起始密钥也会导致程序无法正常运行。(stm32中UID是一个唯一的96bit数据,存在特定的地址,可以直接读取。

    8051的ID可以通过编程软件自己更改修改位置和ID,并且使用xdata声明变量在code区。需注意ID地址不可以覆盖程序段,另外在stm32中读取特定地址的时候,代码中不可以显性的出现这个地址,被读取后容易被发现使用了UID,需要将经过一些运算(加减任意一个偏移量、与或非运算)后得到)。相关博客:【嵌入式】使用嵌入式芯片唯一ID进行程序加密实现_嵌入式设备生成唯一序列号-CSDN博客

    • 此外,ztm32在下载代码的时候还支持上锁的操作,可以对flash进行读保护,此时无法下载代码也无法读取代码。如果想读取固件,必须解锁,解锁的同时也会擦除flash。

    • 关于跳过加密部分:在功能设置多条不同的判断,起到防护的作用,为破解起到阻碍作用。

    (这里涉及到一个知识,const修饰的变量是存在ROM也就是flash中的(仅限于全局变量,定义在函数内部,哪怕是main函数内部,这个时候变量是局部变量,在RAM中),不可以被显性修改,但是可以通过写flash修改)。
  2. 代码加密:对关键的一些重要文件制作静态链接库,也就是制作.a文件,屏蔽实现过程,只保留.h文件对外提供接口。

  3. 物理加密:建议厂家将关键芯片的丝印打磨掉或者进行涂漆。

基于STM32F407单片机测试代码

 #include "sys.h"
 #include "delay.h"
 #include "usart.h"
 #include "led.h"
 #include "stmflash.h"  
 //ALIENTEK 探索者STM32F407开发板 实验34
 //FLASH模拟EEPROM 实验 -库函数版本
 //技术支持:www.openedv.com
 //淘宝店铺:http://eboard.taobao.com  
 //广州市星翼电子科技有限公司  
 //作者:正点原子 @ALIENTEK
 //要写入到STM32 FLASH的字符串数组
 ​
 #define UID_BASE (0x1FFFF7E8)
 const u32 uid_save = 0xFFFFFFFF;    //CPUID保存
 /**************************************************************************
 * 函数名称: getEncryptID
 * 功能描述: 获取并加密ID
 **************************************************************************/
 u32 getEncryptID(u32 *p_id)
 {
     p_id[0] = *(vu32*)(UID_BASE);
     p_id[1] = *(vu32*)(UID_BASE + 4);
     p_id[2] = *(vu32*)(UID_BASE + 8);
  
     return ((p_id[0] >> 3) + (p_id[1] >> 1) + (p_id[2] >> 2));  //加密算法
 }
 ​
 /**************************************************************************
 * 函数名称: judgeEncryptID
 * 功能描述: 判断加密ID
 **************************************************************************/
 u8 judgeEncryptID(void)
 {
     u32 t_encid;
     u32 t_cpuid[3];
     u32 t_addr = 0;
     u32 t_flashid;
     t_encid = getEncryptID(t_cpuid);    //读本机UID
 ​
     t_addr = (u32)&uid_save;            //读取机密ID
     if(*(vu32 *)t_addr == 0xFFFFFFFF)   //第一次上电将加密后的UID写入FLASH
     {
         FLASH_Unlock();
         FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP);
         FLASH_ProgramWord(t_addr, t_encid);//写UID
         FLASH_Lock();
     }
     t_flashid = *(vu32 *)t_addr;        //第一次上电存完了之后需要再读一遍
     
     return (t_flashid == t_encid);
 }
 int main(void)
 { 
     delay_init(168);              //初始化延时函数
     LED_Init();                   //初始化LED端口
     while(1)
     {
         if(judgeEncryptID() == 1){
             GPIO_SetBits(GPIOB,GPIO_Pin_2);      //LED0对应引脚GPIOF.9拉低,亮  等同              LED0=0;
             delay_ms(50);                        //延时300ms
             GPIO_ResetBits(GPIOB,GPIO_Pin_2);    //LED0对应引脚GPIOF.9拉低,亮  等同              LED0=0;
             delay_ms(50);
         }           
     }    
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值