软件层面对单片机程序进行加密
前言:再项目中按照要求需要对程序进行加密,可以使用硬件加密和软件加密。
硬件加密
就是使用外部芯片,首次上电的时候读取id后通过加密算法将密钥存储在外部介质中,每次运行的时候都从外部芯片读取的密钥进行匹配。这个是比较牢靠的,而且可以使用更加复杂的加密算法,但是这样需要外挂芯片导致了一个最根本的问题,成本增加,并且也不适合量产。
硬件加密芯片介绍 及 加密芯片选择(加密IC) 加密芯片原理-CSDN博客
硬件加密芯片的使用及适配(CC020加密芯片)_海思如何与加密芯片通信-CSDN博客
软件加密(固件加密)
-
固件加密:最节约成本的方式就是使用软件进行加密。流程: ①定义全局变量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。
-
关于跳过加密部分:在功能设置多条不同的判断,起到防护的作用,为破解起到阻碍作用。
-
-
代码加密:对关键的一些重要文件制作静态链接库,也就是制作.a文件,屏蔽实现过程,只保留.h文件对外提供接口。
-
物理加密:建议厂家将关键芯片的丝印打磨掉或者进行涂漆。
基于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);
}
}
}
3982

被折叠的 条评论
为什么被折叠?



