MM32 MCU加密方法
在MM32系列MCU产品中有多种加密手段保护用户程序,在这里给大家简单介绍几种加密手段。 我们这里程序加密的目的是防止板子中的程序被他人读出使用,现主要介绍的加密方法有: 1、 读保护 2、 唯一UID 3、 SWD 复用功能重映射 4、 时钟来源判断是否自毁 1、 读保护 在上一篇Flash操作的**中有重点介绍Flash读写保护功能,所有MM32的芯片都提供对Flash的保护,防止对Flash的非法访问——写保护和读保护。一旦设置了Flash的读保护,内置的Flash存储区就只能通过程序的正常执行才能读出,而不能通过这两种方式中的任何一种方式读出:通过调试器(JTAG或SWD)和从RAM中启动并执行的程序。所以我们需要对程序进行保护,一种比较简单可靠的方法就是把Flash设置成读保护。 读保护操作方法: FLASH_Unlock();//解锁 FLASH_ReadOutProtection(ENABLE);//读保护使能 FLASH_EnableWriteProtection(FLASH_Pages); //写保护使能 FLASH_Lock();//上锁 解除读保护操作方法: FLASH_Unlock();//解锁 FLASH_ReadOutProtection(DISABLE);//读保护失能 FLASH_Lock();//上锁 2、 UID加密 96 位的产品唯一身份标识所提供的参考号码对任意一个MM32L0系列微控制器,在任何情况下都是唯一的。用户在任何情况下,都不能修改这个身份标识。 产品唯一的身份标识可用做如下功能: 用来作为序列号(例如 USB 字符序列号或者其他的终端应用) 用来作为密码,在编写闪存时,将此唯一标识与软件加解密算法结合使用,提高代码在闪存存储器的安全性 用来激活带安全机制的自举过程 这个 96 位的产品唯一身份标识,按照用户不同的用法,可以以字节(8 位)为单位读取,也可以以半字(16位)或者全字(32 位)读取,基地址: 0x1FFF F7E8。 UID加密原理: if(芯片UID=数组) { 执行正常的程序; } else { 执行伪程序; } 读取UID样例程序: for(i=0;i<12;i++) { Sys_ID=*(u8*)(0x1FFFF7E8+i); printf("%0.2X",Sys_ID); } UID匹配判断: if(Sys_ID[0]==0x37&& Sys_ID[1]==0x20 && Sys_ID[2]==0x00 && Sys_ID[3]==0x11&& Sys_ID[4]==0x55 && Sys_ID[5]==0xAA && Sys_ID[6]==0xFF&& Sys_ID[7]==0xFF && Sys_ID[8]==0x00 && Sys_ID[9]==0x32&& Sys_ID[10]==0x4D && Sys_ID[11]==0x4D) { printf("\r\n成功\r\n"); } else { printf("\r\n失败\r\n"); while(1); } ①为了避免**者利用反汇编,根据芯片UID数据在二进制文件中查找对应相同数据的位置从而**,可以将UID拆散成不同的组合,并且写到不同且不连续的地方。更进一步,可在程序中检测多份这样的分散UID,以增加反汇编的难度。或者将CPU ID进行加密,Flash中存储加密后的结果。 ②将芯片的UID读取之后,经用户自己的复杂的加密算法对程序区的UID号加密运算后生成一个新的数组---用户自加密ID号,写入MM32 Flash中某一个固定地址存储空间。 在用户程序区多处读程序区的UID号和用户自加密UID号比较(经用户自己的复杂的解密算法解密后),如不对应,则200次开机后随机异常。 另外,在程序区的多个地方判断用户自己的程序是否被修改,如被修改,则200次开机后随机异常,将不用的用户程序区用所谓的有效程序全部填满。 操作方法: #defineMM32_ID_D 65535 #defineMM32_ID _ADDR 0x0800 00800 volatile u32MM32_ID_addr[3]={0x1ffff7e8 - MM32_ID_D,0x1ffff7ec + MM32_ID_D,0x1ffff7f0 -MM32_ID_D}; /******************************************************************** 函数功能:读取芯片UID 入口参数:p 返 回:无 备 注: ********************************************************************/ volatilevoid MM32_Read_ID(volatile u32 *p) { volatile u32Addr; Addr =MM32_ID_addr[0] + MM32_ID_D; p[0] =*(vu32*)(Addr); Addr =MM32_ID_addr[1] - MM32_ID_D; p[1] =*(vu32*)(Addr); Addr =MM32_ID_addr[2] + MM32_ID_D; p[2] =*(vu32*)(Addr); } /******************************************************************** 函数功能:加密并保存UID 入口参数:无 返 回:无 备 注: ********************************************************************/ voidMM32_Encrypted_ID(void) { u32MM32ID[4],dat; MM32_Read_ID(MM32ID); MM32ID[3] =MM32_ID_D; dat =MM32ID[0] + MM32ID[1] - (MM32ID[2]/MM32ID[3]); FLASH_Unlock(); FLASH_ErasePage(MM32_ID _ADDR); FLASH_ProgramWord(MM32_ID_ADDR,dat); FLASH_Lock(); } /******************************************************************** 函数功能:比较加密ID,正确返回0 入口参数: 返 回:1:不正确,0:正确 备 注: ********************************************************************/ u32MM32_CMP_Encrypted_ID(void) { u32MM32ID[4],dat,dat2; MM32_Read_ID(MM32ID); MM32ID[3] =MM32_ID_D; dat =MM32ID[0] + MM32ID[1] - (MM32ID[2]/MM32ID[3]); dat2 =*(u32*)( MM32_ID _ADDR); if(dat ==dat2) { return 0;//相同 } else { return 1;//不同 } } 用户可以自定义UID加密算法及存储加密后的UID的地址,防止其他人获取到该信息,用户可以在多个区域根据比较加密函数返回值做出相对应的操作,如:程序全擦除或者开机多长时间后进入异常状态。 3、SWD 复用功能重映射
MCU的程序下载方式有多种:SWD和ISP等方式,为了增加程序被读出的难度,所以在程序中可以将SWD下载口PA13\PA14复用成其他的功能,这样就可以防止其他人通过SWD方式读取MCU的程序。 操作方法: RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);//开启复用时钟 GPIO_PinAFConfig(GPIOA,GPIO_PinSource13, GPIO_AF_7); //PA13复用其他功能 GPIO_PinAFConfig(GPIOA,GPIO_PinSource14, GPIO_AF_7); //PA14复用其他功能 4、时钟来源判断是否自毁 如果用户在硬件电路上有使用外部晶振,在程序一启动在配置时钟源时就判断外部高速时钟就绪标注,如果外部高速时钟就绪标志为1,就默认执行正常的应用程序,如果为0,跳转HSI,就执行伪程序或者实现自毁功能,并且在应用程序中也可以多次判断该位是否为1,该加密方案的前提是确保外部晶振工作正常,防止有其他人取下芯片做其他的操作。
|
感谢分享