MM32 MCU加密方法

[复制链接]
158|1
 楼主 | 2017-12-27 10:30 | 显示全部楼层 |阅读模式
MM32 MCU加密方法

MM32系列MCU产品中有多种加密手段保护用户程序,在这里给大家简单介绍几种加密手段。
我们这里程序加密的目的是防止板子中的程序被他人读出使用,现主要介绍的加密方法有:
1、 读保护                       2、 唯一UID                3、 SWD 复用功能重映射             4、 时钟来源判断是否自毁
1、 读保护
在上一篇Flash操作的文章中有重点介绍Flash读写保护功能,所有MM32的芯片都提供对Flash的保护,防止对Flash的非法访问——写保护和读保护。一旦设置了Flash的读保护,内置的Flash存储区就只能通过程序的正常执行才能读出,而不能通过这两种方式中的任何一种方式读出:通过调试器(JTAGSWD)和从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的地址,防止其他人获取到该信息,用户可以在多个区域根据比较加密函数返回值做出相对应的操作,如:程序全擦除或者开机多长时间后进入异常状态。
3SWD 复用功能重映射

MCU的程序下载方式有多种:SWDISP等方式,为了增加程序被读出的难度,所以在程序中可以将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,该加密方案的前提是确保外部晶振工作正常,防止有其他人取下芯片做其他的操作。

评论

dirtwillfly 2018-4-26 11:38 回复TA
感谢分享 
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式
我要创建版块 申请成为版主

论坛热帖

关闭

热门推荐上一条 /6 下一条

分享 快速回复 返回顶部 返回列表