关于参数保存至FLASH区存储机制

本文讨论了物联网(IoT)产品中参数存储的安全性问题,包括头尾标志验证的不足以及结构体变化可能导致的问题。提出了通过添加CRC校验字段和单字节对齐方式来增强参数完整性的解决方案,并详细展示了读取和保存参数的实现过程。同时,提醒开发者注意即使有CRC校验,结构体成员顺序改变也可能导致参数错位,建议进行参数范围检测以确保安全性。
摘要由CSDN通过智能技术生成

    描述:   

         通常在做IOT产品或者项目需要参数保存时,通常我们的逻辑是首先判断flash中是否有参数的痕迹,有则读出直接使用,否则认为参数不合法,或者没有参数则要进行参数的初始化。

typedef struct

{

        uint16 Start_Init_Flag;

        uint8 iFlashHardwareUniqueID[4];     //DEVICE ID

        uint8 iFlashFactoryAESKey[16];  //出厂加密KEY

        uint8 iFlashHardwareUniqueIDCipher[8]; //Cipher ID

        uint16 End_Init_Flag;

}T_FLASH_FACTORY,*PT_FLASH_FACTORY;


如图在结构体中,有Start_Init_Flag、 End_Init_Flag两个参数,在参数保存时赋值一个值如,0X5A5A,则在读取参数时则判断此值是否为人为赋的正常值0X5A5A来判定参数区域是否合法。

此通过头尾变量的方式来做,是可以达到效果,但是不完善存在BUG,问题如下:

  1. 单个值不保险,如头尾变量标志在flash内存里,有一次异常操作没有修改到头尾,只改变了中间位置的参数,这样我们依旧是认为合法的。(这样是不对的)
  2. 若旧版本软件结构体参数为2个,然后后续发布了新版程序,参数增加了至3个,但是有可能因为结构体对齐原因导致整个结构体大小没有变化。这样读出的参数,头尾就还是正确的。所以认为合法参数,但是实际值并不合法,(因为把原本对齐的空间,现在给了新增参数,虽然里面的值是0X00,但是这样是不合法的,值不是人为合法给的)。

解决方法:

typedef struct
{
	uint16 Start_Init_Flag;  //参数存在标志
    uint8 Allocation_Net_SSID[MAX_NET_SSID_LEN];  //连接网	络名称
	uint8 Allocation_Net_PWD[MAX_NET_PWD_LEN];	//连接网络密码
    uint8 iFlashNewIPAddress[MAX_SERVECE_IPADDRESS];  	//新的入网IP
    uint8 iFlashNewIPPort[MAX_SERVECE_IPPORT];			//新的入网端口号
    uint8 iFlashGatewayUseIp;		//使用域名或者IP标志
    uint8 iFlashNewDomainName[MAX_SERVECE_DOMAINNAME];  //域名
    uint16 iFlashMaxMessageID;		//message ID最大值
	T_SLEEP_MODE_PARAMETER Sleep_Parameter;
	uint8 iFlashWifi_APMAC[20];	//WIFI MAC地址
	uint16 Cat_Out_Scab_Time;  //猫砂结痂时间
	uint8 Device_WorkPattern; //设备工作模式
	uint16 End_Init_Flag;  //参数存在标志
	uint8 Parameter_Crc;
}__attribute__ ((packed))T_FLASH_PROGRAM,*PT_FLASH_PROGRAM;  //保存flash参数

如次结构:在结构体中除了头尾标志,增加   uint8 Parameter_Crc字段,在保存时加入crc。并且结构体采用单字节对齐方式,保证增加减少参数一定会改变结构长度,不会出现增加参数导致长度不变,导致对齐问题出现异常赋值问题。

如下为读取参数,保存机制:

void Device_FlashConfig_Parameter_Save(void)
{
	uint8 Parameter_Crc;
	Device_flashParam.Start_Init_Flag = FLASH_PARAMETER_INTACT_FLAG;  //标志置位
	Device_flashParam.End_Init_Flag = FLASH_PARAMETER_INTACT_FLAG;  //标志置位
	Parameter_Crc = Check_CRC((uint8 *)&Device_flashParam,sizeof(Device_flashParam)-sizeof(Device_flashParam.Parameter_Crc));
	Device_flashParam.Parameter_Crc = Parameter_Crc;
	STM32_Flash_ErasePage(DEVICE_CONFIG_PARAMETER_ADDR);
	STM32_Flash_Write_NBytes(DEVICE_CONFIG_PARAMETER_ADDR,(uint8 *)&Device_flashParam,sizeof(Device_flashParam));
}

uint8 Device_FlashConfig_ParameterCheck(void)
{
	uint8 Parameter_Crc;
 	STM32_Flash_Read_NBytes(DEVICE_CONFIG_PARAMETER_ADDR, (uint8 *)&Device_flashParam, sizeof(Device_flashParam)); //读出falsh参数
 	Parameter_Crc = Check_CRC((uint8 *)&Device_flashParam,sizeof(Device_flashParam)-sizeof(Device_flashParam.Parameter_Crc));
 	if((Device_flashParam.Start_Init_Flag != FLASH_PARAMETER_INTACT_FLAG) || (Device_flashParam.End_Init_Flag != FLASH_PARAMETER_INTACT_FLAG) ||\
 		(Parameter_Crc != Device_flashParam.Parameter_Crc))
	{
		#if Debug_Parameter
			printf("*\r\n======FlashConfig_ParameterCheckInit=======*Parameter_Crc=0X%X,Device_flashParam.Parameter_Crc =0X%X\r\n",Parameter_Crc,Device_flashParam.Parameter_Crc);
		#endif
		Device_FlashConfig_ParameterInit();  
		Device_FlashConfig_Parameter_Save();
        return 1;
	}
	#if Debug_Parameter
		PCTxString("*======FlashConfig_Parameter Read successd=======*\r\n");
	#endif
    return 0;
}

注意:

尽管结构中增加头尾标志变量、crc校验、单字节对齐。但也应对不了一种情况,那就是结构体空间未出现大小变化,仅是将结构体成员进行位置调换,在这种情况下,读取数据后,crc校验正常,但是参数会错位,所以需要极其注意,最好是对每个参数都进行范围检测,判断是否非法!保证程序不会出现较大的隐患。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值