在物联网产品开发过程中,尤其在量产环节,为了防止固件泄露,抄板等发生,
需要在硬件电路的协助下,让单片机程序做一层安全校验系统。
比如第一次开机可以将mcu的唯一ID保存到空白eeprom中,当再次启动时
会读取eeprom固定地址的ID信息与自身ID进行匹配,匹配不上则让单片机
处于死机状态。更进一步,当单片机校验正常启动以后,再与无线通信模组进行ID信息的交换,
或者不同的应答逻辑,双方达到匹配之后才可正常工作。
enc.c简单的异或加解密
#ifndef __ENC_H__
#define __ENC_H__
#include <stdlib.h>
#include "stm32f2xx_hal.h"
void Robot_Code_Init(void);
uint8_t* Robot_Encode_Protocol(uint8_t*datas,uint8_t len,uint8_t pni);
uint8_t* Robot_Decode_Protocol(uint8_t*datas,uint8_t len,uint8_t pni);
#endif
#include "enc.h"
static RNG_HandleTypeDef RngHandle;
//单片机硬件随机数发生器初始化
void Robot_Code_Init(void)
{
__HAL_RCC_RNG_CLK_ENABLE();
/*##-1- Configure the RNG peripheral #######################################*/
RngHandle.Instance = RNG;
if(HAL_RNG_Init(&RngHandle) != HAL_OK)
{
/* Initialization Error */
return;
}
srand(HAL_RNG_GetRandomNumber(&RngHandle));
}
/**
简单的异或加密,pni为随机密钥字节存放索引,
返回加密后的内容.
*/
uint8_t* Robot_Encode_Protocol(uint8_t*datas,uint8_t len,uint8_t pni)
{
uint8_t nr;
uint8_t mask = 0;
uint8_t i;
uint8_t nr_index = pni;
nr = rand() & 0xFF;
datas[nr_index] = nr;
for(i=0;i < len; i++)
{
if((i & 0x01) == 1)
mask = (uint8_t)(nr + i + 1);
else
mask = (uint8_t)(nr * (i + 5));
if(i != nr_index)
datas ^= mask;
}
return datas;
}
/**
简单的异或解密,pni为随机密钥字节存放索引,
返回解密后的内容.
*/
uint8_t* Robot_Decode_Protocol(uint8_t*datas,uint8_t len,uint8_t pni)
{
uint8_t nr_index = pni;
uint8_t mask = 0;
uint8_t i;
uint8_t nr = datas[nr_index];
datas[nr_index] = 0x00;
for(i=0; i < len; i++)
{
if((i & 0x01) == 1)
mask = (uint8_t)(nr + i + 1);
else
mask = (uint8_t)(nr * (i + 5));
if(i != nr_index)
datas ^= mask;
}
return datas;
}
system_verify.c单片机开机执行校验流程
#ifndef __SYSTEM_VERIFY_H__
#define __SYSTEM_VERIFY_H__
#include <string.h>
#include <core_cm3.h>
#include "stm32f2xx_hal.h"
#include "comtypes.h"
#include "boot_act.h"
#include "unique.h"
#include "enc.h"
#include "util.h"
#include "base_data.h"
void System_Verify(void);
#endif
#include "system_verify.h"
#define CPU_PKG_LEN (13)
#define SV_NR_INDEX (12)
#define POWERON_FLAG_LEN (2)
#define CPU_ID_SAM_LEN (4)
#define POWERON_FLAG (0x8899)
//字符串比较
static BOOLEAN Bytes_Cmp(uint8_t*src,uint8_t*target,uint16_t len)
{
uint8_t i;
for(i=0;i < len;i++)
{
if(*src++ != *target++) return FALSE;
}
return TRUE;
}
//关闭中断进入无限循环
static void SV_Failed_OPTS(void)
{
__disable_irq();
while(TRUE);
}
/**
全为0x00或者0xFF都表示eeprom为空
*/
static BOOLEAN Is_Correct(uint8_t*buf,uint16_t len,BOOLEAN ignore0)
{
uint8_t i;
if(!ignore0 && buf[0] == 0x00)
{
for(i=0;i < len;i++)
{
if(buf != 0x00) return TRUE;
}
return FALSE;
}
for(i=0;i < len;i++)
{
if(buf != 0xFF) return TRUE;
}
return FALSE;
}
/**校验系统*/
void System_Verify(void)
{
uint8_t readpkgbuf[CPU_PKG_LEN];
uint8_t readidsam[CPU_ID_SAM_LEN];
uint8_t curidbuf[CPU_PKG_LEN];
uint8_t curidsam[CPU_ID_SAM_LEN];
uint8_t poweronflag[POWERON_FLAG_LEN];
uint8_t alldata[POWERON_FLAG_LEN + CPU_ID_SAM_LEN + CPU_PKG_LEN];
uint8_t*encpkgbuf;
uint8_t*decpkgbuf;
uint32_t tmp = 0;
//先清空,防止垃圾数据
memset(readpkgbuf,0,sizeof(readpkgbuf));
//读取存储的芯片MCU ID
Read_Boot(readpkgbuf,IAP_START_ADDRESSS_ID,CPU_PKG_LEN);
//如果没有保存ID信息
if(!Is_Correct(readpkgbuf,CPU_ID_LEN,FALSE))
{
//判断是否为第一次上电
memset(poweronflag,0,sizeof(poweronflag));
Read_Boot(poweronflag,IAP_START_ADDRESS_POWERON_FLAG,POWERON_FLAG_LEN);
if(((poweronflag[0] << 8) | poweronflag[1]) == POWERON_FLAG)
{
//开始做崩溃的事情
goto SYSTEM_VERIFY_FAILED;
}
//将当前芯片ID及校验信息保存起来,并置第一次上电完成.
Get_ID(curidbuf);
tmp = Crc32_Calc(curidbuf,CPU_ID_LEN);
curidsam[0] = (tmp >> 24) & 0xFF;
curidsam[1] = (tmp >> 16) & 0xFF;
curidsam[2] = (tmp >> 8) & 0xFF;
curidsam[3] = tmp & 0xFF;
poweronflag[0] = (POWERON_FLAG >> 8) & 0xFF;
poweronflag[1] = POWERON_FLAG & 0xFF;
encpkgbuf = Robot_Encode_Protocol(curidbuf,CPU_PKG_LEN,SV_NR_INDEX);
memcpy(alldata,poweronflag,POWERON_FLAG_LEN);
memcpy(alldata+POWERON_FLAG_LEN,curidsam,CPU_ID_SAM_LEN);
memcpy(alldata+POWERON_FLAG_LEN+CPU_ID_SAM_LEN,encpkgbuf,CPU_PKG_LEN);
Write_Boot_ACT(TYPE_ADDR_BOOT,IAP_START_ADDRESS,alldata,sizeof(alldata));
goto SYSTEM_VERIFY_SUCCESS;
}
//解密芯片MCU ID
decpkgbuf = Robot_Decode_Protocol(readpkgbuf,CPU_PKG_LEN,SV_NR_INDEX);
//验证存储的芯片ID校验信息是否正确
Read_Boot(readidsam,IAP_START_ADDRESS_IDSAM,CPU_ID_SAM_LEN);
if(((readidsam[0] << 24) | (readidsam[1] << 16) | (readidsam[2] << 8) | readidsam[3]) != Crc32_Calc(decpkgbuf,CPU_ID_LEN))
{
//开始做崩溃的事情
goto SYSTEM_VERIFY_FAILED;
}
//与当前芯片ID比较
Get_ID(curidbuf);
if(!Bytes_Cmp(decpkgbuf,curidbuf,CPU_ID_LEN))
{
开始做崩溃的事情
goto SYSTEM_VERIFY_FAILED;
}
SYSTEM_VERIFY_SUCCESS:
return;
SYSTEM_VERIFY_FAILED:
SV_Failed_OPTS();
}
————————————————
版权声明:本文为CSDN博主「麦德泽特」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44470384/article/details/131262245
|
|