单片机开机安全校验系统,MCU和EEPROM绑定启动

文章描述了一种在物联网产品开发中确保固件安全的方法,通过在硬件层面实现ID校验系统,防止固件泄露和抄板。单片机在启动时会比较自身的ID与EEPROM中保存的ID,不匹配则进入死机状态。此外,还使用简单的异或加密算法对通信协议进行加密,增强设备间的通信安全性。
摘要由CSDN通过智能技术生成

在物联网产品开发过程中,尤其在量产环节,为了防止固件泄露,抄板等发生,

需要在硬件电路的协助下,让单片机程序做一层安全校验系统。

比如第一次开机可以将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[i] ^= 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[i] ^= 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[i] != 0x00) return TRUE;
		 }
		 
		 return FALSE; 
	 }

	 for(i=0;i < len;i++)
	 {
	     if(buf[i] != 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(); 
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值