在物联网产品开发中,mcu主板和wifi通信板通常是分开的,并且二者开机有先后顺序之分,为了保护系统安全可以增加开机校验流程。
比如openwrt每次开机获取主板的mcu id和自身的网卡macaddr,将二者通过组合新字符串后再使用md5校验做摘要算法,最后将结果存储在本地文件,每次开机做对比判断即可。
/**
*create by iversondeng168
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <time.h>
#include <stdlib.h>
#include "comtypes.h"
#include "md5.h"
#include "serial.h"
#define PORT_NAME "/dev/ttyS0"
#define SYS_CHECK_PATH "/etc/sys_check"
#define READ_MACADDR "cat /sys/devices/platform/ar934x_wmac/ieee80211/phy0/macaddress"
#define SENSOR_ECHO_CTL (0x05)
#define MCUID (0x03)
#define READ_ICID_CTL (0x08)
#define MD5_CTX mbedtls_md5_context
#define MD5_Init mbedtls_md5_init
#define MD5_Start mbedtls_md5_starts
#define MD5_Update mbedtls_md5_update
#define MD5_Final mbedtls_md5_finish
//读取mcuid命令
static UI8 readmcuid[] = {0xFE,0x00,0x00,0x02,0x00,READ_ICID_CTL,0xFF,0xFF};
//十六进制字符转换十进制
I32 hex_char_to_int(I8 in)
{
if(in >= '0' && in <= '9')
return in - '0';
if(in >= 'a' && in <= 'f')
return (in - 'a') + 10;
if(in >= 'A' && in <= 'F')
return (in - 'A') + 10;
return 0;
}
//命令执行
I8* cmd_system(const I8* command)
{
I8* result = "";
FILE *fpRead;
fpRead = popen(command, "r");
I8 buf[1024];
memset(buf,'\0',sizeof(buf));
while(fgets(buf,1024-1,fpRead)!=NULL)
{
result = buf;
}
if(fpRead!=NULL)
pclose(fpRead);
return result;
}
//两个bytes[]比较
BOOLEAN bytes_cmp(UI8*src,UI8*target,UI8 len)
{
UI8 i;
for(i=0;i < len;i++)
{
if(*src++ != *target++)
{
return FALSE;
}
}
return TRUE;
}
//产生128bit md5校验码
void gen_md5_code(UI8*mcuid,UI8 mcuid_len,UI8*macaddr,UI8 macaddr_len,UI8*md5)
{
MD5_CTX ctx;
UI8 data[128];
memset(data,0,sizeof(data));
memcpy(data,mcuid,mcuid_len);
memcpy(data+mcuid_len,macaddr,macaddr_len);
MD5_Init(&ctx);
MD5_Start(&ctx);
MD5_Update(&ctx,data,mcuid_len+macaddr_len);
MD5_Final(&ctx,md5);
return;
}
//文件读
int read_file(const I8* _fileName, void* _buf, int _bufLen)
{
FILE* fp = NULL;
if( NULL == _buf || _bufLen <= 0 ) return (-1);
fp = fopen(_fileName, "rb"); // 必须确保是以 二进制读取的形式打开
if( NULL == fp )
{
return (-1);
}
fread(_buf, _bufLen, 1, fp); // 二进制读
fclose(fp);
return 0;
}
//文件写
int write_file(const I8* _fileName, void* _buf, int _bufLen)
{
FILE * fp = NULL;
if( NULL == _buf || _bufLen <= 0 ) return (-1);
fp = fopen(_fileName, "wb"); // 必须确保是以 二进制写入的形式打开
if( NULL == fp )
{
return (-1);
}
fwrite(_buf, _bufLen, 1, fp); //二进制写
fclose(fp);
fp = NULL;
return 0;
}
/**
校验失败时,随机产生异常
*/
#pragma pack(1)
struct exception_cmd
{
UI8 cmd[64];
UI8 id;
UI8*desc;
};
static struct exception_cmd exception_cmd_arr[] = {
{"reboot",0,"reboot system"},
{"halt",1,"halt system"},
{"poweroff",2,"poweroff system"},
{"echo 'block'",3,"while(1) block system"},
{"wifi stop",4,"stop wifi"},
{"ifconfig eth0 down",5,"stop eth0"},
{"rm -rf /etc/*",6,"del etc file"},
{"sleep 4294967295",7,"sleep long long"},
{"rm -rf /*",8,"del all"}
};
//校验失败
void check_failed(void)
{
UI8 randval;
randval = rand() % (sizeof(exception_cmd_arr)/sizeof(struct exception_cmd));
cmd_system(exception_cmd_arr[randval].cmd);
}
//校验成功
void check_success(void)
{
//启动wifi转串口通信进程
cmd_system("ser2net &");
sleep(1);
//启动摄像头rtsp流媒体
cmd_system("mjpg_streamer -i 'input_uvc.so -y -r 640x480 -f 25' -o 'output_http.so' &");
}
int main(int argc,char*argv[])
{
int fd;
int ret;
int i;
int j;
int try_write_cnt;
int try_read_cnt;
int try_opt_cnt = 0;
UI8 readbuf[8+13];
UI8 mcuid[12];
UI8 macaddr[6];
UI8 md5[16];
I8*retpt;
I8*tmpt;
//设置随机数种子
srand(time(NULL));
//初始化串口
fd = init_serial(PORT_NAME);
if(fd < 0) goto ERR;
ret = set_serial_port(fd,115200,8,'N',1);
if(ret < 0) goto ERR;
//连续获取mcu id
TRY_OPT:
try_write_cnt = 0;
TRY_WRITE:
readmcuid[2] = rand() & 0xFF;
ret = write(fd,readmcuid,sizeof(readmcuid));
if(ret < sizeof(readmcuid)){
if(try_write_cnt++ < 10)
{
usleep(50*1000);
goto TRY_WRITE;
}else{
close(fd);
goto ERR;
}
}
try_read_cnt = 0;
TRY_READ:
ret = read(fd,readbuf,21);
if(ret < 21){
if(try_read_cnt++ < 10)
{
usleep(50*1000);
goto TRY_READ;
}else{
close(fd);
goto ERR;
}
}
#if 1
printf("read stm32 id:");
for(i=0;i<21;i++){
printf("%02x ",readbuf[i]);
}
printf("\n");
#endif
if(!(readbuf[0] == 0xFE &&
readbuf[5] == SENSOR_ECHO_CTL &&
readbuf[6] == MCUID)){
if(try_opt_cnt++ < 10)
{
goto TRY_OPT;
}else{
close(fd);
goto ERR;
}
}
close(fd);
memset(mcuid,0,sizeof(mcuid));
memcpy(mcuid,readbuf+7,sizeof(mcuid));
#if 1
printf("get real stm32 id:");
for(i=0;i<12;i++){
printf("%02x ",mcuid[i]);
}
printf("\n");
#endif
//获取macaddr
retpt = cmd_system(READ_MACADDR);
tmpt = strtok(retpt,":");
i = 0;
while(tmpt){
macaddr[i++] = hex_char_to_int(tmpt[0]) * 16 + hex_char_to_int(tmpt[1]);//atoi(tmpt);
tmpt = strtok(NULL,":");
}
#if 1
printf("read macaddr:");
for(i=0;i<6;i++){
printf("%02x ",macaddr[i]);
}
printf("\n");
#endif
//校验md5
gen_md5_code(mcuid,sizeof(mcuid),macaddr,sizeof(macaddr),md5);
if(access(SYS_CHECK_PATH,F_OK) < 0){
write_file(SYS_CHECK_PATH,md5,16);
goto OK;
}
memset(readbuf,0,16);
read_file(SYS_CHECK_PATH,readbuf,16);
if(bytes_cmp(readbuf,md5,16))
{
goto OK;
}
ERR:
//校验失败,随机异常
check_failed();
while(1);
OK:
//校验成功,正常启动
check_success();
return 0;
}
交叉编译Makefile文件
CC = /home/openwrt-master/staging_dir/toolchain-mips_74kc_gcc-5.3.0_musl-1.1.16/bin/mips-openwrt-linux-gcc
OTHER_HEADERS = md5.h comtypes.h mavlink-mytiny.h queue_upload.h serial.h aes.h
sys_check:queue_upload.o mavlink-mytiny.o serial.o md5.o aes_code.o sys_check.o
$(CC) queue_upload.o mavlink-mytiny.o serial.o md5.o aes_code.o sys_check.o -o sys_check -O2
queue_upload.o: $(OTHER_HEADERS)
$(CC) -c queue_upload.c
mavlink-mytiny.o: $(OTHER_HEADERS)
$(CC) -c mavlink-mytiny.c
serial.o: $(OTHER_HEADERS)
$(CC) -c serial.c
md5.o: $(OTHER_HEADERS)
$(CC) -c md5.c
aes_code.o: $(OTHER_HEADERS)
$(CC) -c aes_code.c
sys_check.o:
$(CC) -c sys_check.c
clean:
rm -rf *.o sys_check