智能家居中的物联网网关的可信计算平台模块(TPM)设计
摘要:
随着智能家居的普及,安全性问题的研究已成当务之急。针对物联网网关自身的易受攻击性和网络传输过程中的信息窃听,我们分别采用SHA-1和AES算法对网关中的操作系统和节点采集的信息进行验证和加密,在一定程度上实现可信。我们创造性地将可信模块与网关平台进行解耦,利于可信模块的升级和维护。
简介:
智能家居通过物联网技术将家中的各种设备(如照明系统、空调控制、安防系统)连接到一起。智能家居最初的发展主要以灯光遥控、电器远程控制和电动窗帘控制为主,后来延伸到家庭安防报警、背景音乐、可视对讲、门禁指纹控制等领域。可见智能家居中的中央控制系统已经担当起大管家的职责,然而随之而来的安全性问题日益突出,需要我们对大管家进行特殊的防护。
物联网网关,作为一个新的名词,在未来的物联网时代将会扮演非常重要的角色,它将成为连接感知网络与传统通信网络的纽带。作为网关设备,物联网网关可以实现感知网络与通信网络,以及不同类型感知网络之间的协议转换。既可以实现广域互联.也可以实现局域互联。物联网网关在智能家居中处于核心地位,在我们的设计中网关便担当了大管家的职责,因此我们将重点针对物联网网关进行防护。
可信计算是在计算和通信系统中广泛使用基于硬件安全模块支持下的计算平台,以提高系统整体的安全性与可靠性。可信计算包括5个完整的可信系统所必须的关键技术概念:签注密钥、安全输入输出、储存器屏蔽、密封储存、以及远程认证。因此将可信计算用于物联网网关,实现一套完成的物联网网关可信平台模块。而目前国内还暂无技术较成熟的基于可信计算的物联网网关平台,项目较为新颖。
系统设计:
将可信平台模块(TPM)用于对嵌入式物联网网关设备的安全管理,实现网关的安全信息处理及通信。我们设计并在Devkit8500平台上实现了TPM模块的主要基本功能,并搭配基于ARM9的TQ2440平台的嵌入式物联网网关以及基于Zigbee通信协议的无线传感器网络。通过TPM模块对网关启动时(包括Boot Loader以及OS Kernel)的完整性验证,可以在启动前保证网关的核心系统程序的安全性。同时,网关应用程序(传感器数据收集、Web Service等)对数据的处理以及同外部设备通信也将通过TPM模块进行加解密处理,以保证数据的安全性。
功能模块设计:
1、TPM模块:
1)通过RS232与网关进行通信。
2)上面运行SHA-1验证算法,当网关启动时,网关会先后将其操作系统的bootloader和kernel通过RS232串口传送到TPM,届时SHA-1算法利用传来的信息生成信息摘要并与正确摘要匹配达到开机可信验证的目的,这是针对对物联网网关系统级的攻击的防护,一旦系统发生改动,SHA-1验证算法便会检测到异常,提醒用户。
3)AES加密算法。主要针对传感网节点传来的信息,若以明文存在网关数据库中,同样面临被窃取的风险。我们借鉴https的加密策略,在TPM上集成AES加密算法,节点传来的信息经由TPM进行加密,以密文的信息存在网关上的sqlite数据库中。
2、网关模块:
1)搭载GoAhead webserver,并编写CGI程序作为逻辑与界面控制。
2)通过RS232与TPM通信,并与温湿度传感器节点组成的Zigbee网络中协调器 进行RS232通讯。
3)自定义通信协议,实现网关与TPM通信的有序性。当两路或多路节点信息同时经由TPM进行加密处理时,它们是在争用一条串口线,这时就需要定义规则,对多路信息进行惟一标识和排队等候。
3、用户端:
通过访问网关上的CGI页面,用户先进行身份验证,然后可选择是否将请求信息进行AES加密处理,防止用户指令遭窃听。大规模用户访问对可信模块的计算能力提出了严峻的挑战,而实现的TPM和网关的解耦,却不利于大规模用户访问,也造成了性能瓶颈。
4、传感节点:
温湿度传感器配备Zigbee通信模块,组建传感网。协调器节点负责发起并维护一个无线网络,识别网络中的设备加入网络;路由器节点支撑网络链路结构,完成数据包的转发;终端节点是网络的感知者和执行者,负责数据采集和可执行的网络动作。
总结:
针对智能家居,我们搭建了一个模拟环境,建立起TPM负责可信验证,实现节点信息的安全存储、用户访问信息的加密传输以及系统级的可信验证,并对大规模访问有所探究,同时涉及Zigbee网络的组建,而解耦设计可以对TPM进行单独维护和升级。我们所构建的原始模型,不仅可以用于开发智能家居,而且我们曾将这一模型用于火车站自动检票机的设计。这也是我们大胆的将可信计算平台应用于物联网网关设计的一次尝试。
附:
AESListen.c
/********************************************************* *TPM AES jiemi * **********************************************************/ #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<string.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<termios.h> #include<errno.h> #include<sys/time.h> #include <time.h> #include "aes.h" #define FALSE -1 #define TRUE 1 int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300, }; int name_arr[] = {115200,38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300, }; void set_speed(int fd, int speed); int set_Parity(int fd,int databits,int stopbits,int parity); void Print(BYTE a[]) { int i; for(i=0; i<4*Nb; i++) { printf("%02X ", a[i]); } printf("\n\n"); } int main(void) { char *serialport="/dev/ttyUSB0"; int fd; int nread; int count; char buffer[16]={'\0'}; char buffer_all[16]={'\0'}; fd=open(serialport,O_RDWR|O_NOCTTY|O_NDELAY); if(fd==-1) { printf("%s open error!\n",serialport); return -1; } printf("open %s successfully !",serialport); fflush(stdout); set_speed(fd,115200); if (set_Parity(fd,8,1,'N')==FALSE) { printf("Set Parity Error\n"); exit(1); } DWORD e_key[Nb*(MaxNr+1)]; BYTE key[4*MaxNk]={ //miyao 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17}; BYTE decrypted_msg[4*Nb]; int filelen; int times=0; SetKey(192); KeyExpansion(key, e_key); tcflush(fd,TCIOFLUSH); count=0; while(1) { nread=read(fd,buffer,16); if(nread>0) { memcpy(buffer_all+count,buffer,nread); count +=nread; } if(count==16) { printf("total_size : %d\n",count); break; } sleep(1); printf("loop one second\n"); } printf("encrypted message:\n"); Print(buffer_all); AesDecrypt(buffer_all, decrypted_msg, e_key); //jiemi printf("decrypted message:\n"); Print(decrypted_msg); write(fd,decrypted_msg,16); return 0; } void set_speed(int fd, int speed) { int i; int status; struct termios Opt; tcgetattr(fd, &Opt); for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) { if (speed == name_arr[i]) { tcflush(fd, TCIOFLUSH); cfsetispeed(&Opt, speed_arr[i]); /* */ cfsetospeed(&Opt, speed_arr[i]); status = tcsetattr(fd, TCSANOW, &Opt); /* */ if (status != 0) { perror("tcsetattr fd1"); return; } } tcflush(fd,TCIOFLUSH); /* */ } } int set_Parity(int fd,int databits,int stopbits,int parity) { struct termios options; if (tcgetattr( fd,&options) != 0) { printf("SetupSerial 1"); return(FALSE); } options.c_cflag &= ~CSIZE; /* */ switch (databits) /**/ { case 7: options.c_cflag |= CS7; break; case 8: options.c_cflag |= CS8; break; default: fprintf(stderr,"Unsupported data size\n"); return (FALSE); } switch (parity) { case 'n': case 'N': options.c_cflag &= ~PARENB; /* Clear parity enable */ options.c_iflag &= ~INPCK; /* Enable parity checking */ break; case 'o': case 'O': options.c_cflag |= (PARODD | PARENB); /* */ options.c_iflag |= INPCK; /* Disnable parity checking */ break; case 'e': case 'E': options.c_cflag |= PARENB; /* Enable parity */ options.c_cflag &= ~PARODD; /* */ options.c_iflag |= INPCK; /* Disnable parity checking */ break; case 'S': case 's': /*as no parity*/ options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; break; default: fprintf(stderr,"Unsupported parity\n"); return (FALSE); } /**/ switch (stopbits) { case 1: options.c_cflag &= ~CSTOPB; break; case 2: options.c_cflag |= CSTOPB; break; default: fprintf(stderr,"Unsupported stop bits\n"); return (FALSE); } /* Set input parity option */ if (parity != 'n') options.c_iflag |= INPCK; options.c_cc[VTIME] = 150; // 15 seconds options.c_cc[VMIN] = 0; options.c_lflag &= ~(ICANON |ISIG); options.c_iflag &= ~(ICRNL|IGNCR); tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */ if (tcsetattr(fd,TCSANOW,&options) != 0) { printf("SetupSerial 3"); return (FALSE); } return (TRUE); }
Listenarm.c
#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <errno.h> #include <sys/time.h> #include <time.h> #include "sha1.h" #include "stdint.h" #define MAX 1024 #define FALSE -1 #define TRUE 1 #define BUFFER_SIZE 1024 typedef unsigned char TPM_TAG ; typedef unsigned int UINT32; typedef unsigned char TPM_COMMAND_CODE; int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300, }; int name_arr[] = {115200,38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300, }; void set_speed(int fd, int speed); int set_Parity(int fd,int databits,int stopbits,int parity); void itoa ( unsigned int val, char *buf, int radix ); unsigned char buffer_all_bootloader[1024*1024]; int buffer_len_bootloader; unsigned char buffer_all_kernel[1024*1024]; int buffer_len_kernel; unsigned char Message_Digest_bootloader[SHA1HashSize]; unsigned char Message_Digest_kernel[SHA1HashSize]; typedef struct { TPM_TAG tag; UINT32 paramSize; TPM_COMMAND_CODE ordinal; }TPM_COMMAND; //unsigned char bootloader_sha1_checksum[20]={31,79,191,25,22,207,68,233,254,242,171,148,233,85,122,172,52,150,227,121}; unsigned char bootloader_sha1_checksum[20]={0x77,0xCA,0x04,0xD2,0x41,0xA7,0xF7,0xCD,0x9F,0x69,0x11,0x06,0x68,0x28,0x95,0xE3,0x71,0x7F,0x24,0xEC}; //unsigned char kernel_sha1_checksum[20]={161,76,7,206,132,245,247,137,244,45,3,48,49,98,232,213,32,219,62,17}; unsigned char kernel_sha1_checksum[20]={0x70,0xD0,0x0C,0x51,0x7C,0x10,0xFB,0xCB,0x93,0x81,0x2C,0x0C,0x5C,0x8C,0xBF,0x35,0x23,0xB8,0xE5,0x99}; int main(void) { char *serialport = "/dev/ttyUSB0"; int fd=open(serialport,O_RDWR,O_NOCTTY); if(fd == -1) { printf("%s Open Error!\n",serialport); return -1; } printf("open %s successfully !\n",serialport); fflush(stdout); set_speed(fd,115200); if (set_Parity(fd,8,1,'N')== FALSE) { printf("Set Parity Error\n"); exit(1); } /*******************************************************************************/ struct timeval tpstart,tpend; float timeuse; gettimeofday(&tpstart,NULL); write(fd,"s",1); /*TPM帧格式*/ TPM_COMMAND request_bootloader={'t',6,'s'}; unsigned char d[5]; itoa(request_bootloader.paramSize,d,10); unsigned char dest[strlen(d)+5]; sprintf(dest,"%c%d%c",request_bootloader.tag,request_bootloader.paramSize,request_bootloader.ordinal); dest[3]='a'; dest[4]='b'; dest[5]='c'; write(fd,dest,strlen(d)+5); /*******************************************************************************/ //监听bootloader int nread = 1,nwrite = 0; int total_size = 0; unsigned char buffer[BUFFER_SIZE] = {'\0'}; int i; buffer_len_bootloader = 0; while(1) { nread=read(fd,buffer,1024); if(nread>0) { total_size+=nread; memcpy(buffer_all_bootloader+buffer_len_bootloader,buffer,nread); buffer_len_bootloader+=nread; #if 0 for(i = 0;i<nread;i++) { if(i%8==0) { printf("\n"); } printf("0x%x,",buffer[i]); } #endif } if(total_size==29700) { printf("total_size:%d\n",total_size); break; } } //生成bootloader摘要值 sha1_test(buffer_all_bootloader,buffer_len_bootloader,Message_Digest_bootloader); /* sha-1 */ sleep(1); int count; for(count=0;count<20;count++) { if(bootloader_sha1_checksum[count]==Message_Digest_bootloader[count]) continue; else goto close; } write(fd,"s",1); write(fd,"abcdef",6); gettimeofday(&tpend,NULL); timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec; timeuse/=1000000; printf("Used Time:%f\n",timeuse); /*******************************************************************************/ //监听kernel0 struct timeval tpstart2,tpend2; float timeuse2; gettimeofday(&tpstart2,NULL); nread = 1,nwrite = 0; total_size = 0; unsigned char buffer2[BUFFER_SIZE] = {'\0'}; buffer_len_kernel = 0; while(1) { nread=read(fd,buffer2,1024); if(nread>0) { total_size+=nread; memcpy(buffer_all_kernel+buffer_len_kernel,buffer2,nread); buffer_len_kernel+=nread; #if 0 for(i = 0;i<nread;i++) { if(i%8==0) { printf("\n"); } //printf("0x%x,",buffer2[i]); } #endif } if(total_size==29386) { printf("total_size:%d\n",total_size); break; } } //生成kernel摘要值 sha1_test(buffer_all_kernel,buffer_len_kernel,Message_Digest_kernel); sleep(1); for(count=0;count<20;count++) { if(kernel_sha1_checksum[count]==Message_Digest_kernel[count]) continue; else goto close; } write(fd,"s",1); write(fd,"abcdef",6); gettimeofday(&tpend2,NULL); timeuse2=1000000*(tpend2.tv_sec-tpstart2.tv_sec)+tpend2.tv_usec-tpstart2.tv_usec; timeuse2/=1000000; printf("Used Time:%f\n",timeuse2); close: close(fd); return 0; } void set_speed(int fd, int speed) { int i; int status; struct termios Opt; tcgetattr(fd, &Opt); for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) { if (speed == name_arr[i]) { tcflush(fd, TCIOFLUSH); cfsetispeed(&Opt, speed_arr[i]); /* 指定输入波特率 */ cfsetospeed(&Opt, speed_arr[i]); status = tcsetattr(fd, TCSANOW, &Opt); /* 将修改后的termios数据设置到串口中 */ if (status != 0) { perror("tcsetattr fd1"); return; } } tcflush(fd,TCIOFLUSH); /* */ } } int set_Parity(int fd,int databits,int stopbits,int parity) { struct termios options; /*if (tcgetattr( fd,&options) != 0) { printf("SetupSerial 1"); return(FALSE); } */ options.c_cflag &= ~CSIZE; /* 设置数据位前必须先使用CSIZE做位屏蔽 */ switch (databits) /*设置数据位数*/ { case 7: options.c_cflag |= CS7; break; case 8: options.c_cflag |= CS8; break; default: fprintf(stderr,"Unsupported data size\n"); return (FALSE); } switch (parity) { case 'n': case 'N': options.c_cflag &= ~PARENB; /* Clear parity enable */ options.c_iflag &= ~INPCK; /* Enable parity checking */ break; case 'o': case 'O': options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/ options.c_iflag |= INPCK; /* Disnable parity checking */ break; case 'e': case 'E': options.c_cflag |= PARENB; /* Enable parity */ options.c_cflag &= ~PARODD; /* 转换为偶效验*/ options.c_iflag |= INPCK; /* Disnable parity checking */ break; case 'S': case 's': /*as no parity*/ options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; break; default: fprintf(stderr,"Unsupported parity\n"); return (FALSE); } /* 设置停止位*/ switch (stopbits) { case 1: options.c_cflag &= ~CSTOPB; break; case 2: options.c_cflag |= CSTOPB; break; default: fprintf(stderr,"Unsupported stop bits\n"); return (FALSE); } /* Set input parity option */ if (parity != 'n') options.c_iflag |= INPCK; options.c_cc[VTIME] = 150; // 15 seconds options.c_cc[VMIN] = 0; options.c_lflag &= ~(ICANON |ISIG); options.c_iflag &= ~(ICRNL|IGNCR); tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */ if (tcsetattr(fd,TCSANOW,&options) != 0) { printf("SetupSerial 3"); return (FALSE); } return (TRUE); } void itoa ( unsigned int val, char *buf, int radix ) { char *p; /* pointer to traverse string */ char *firstdig; /* pointer to first digit */ char temp; /* temp char */ unsigned int digval; /* value of digit */ p = buf; firstdig = p; /* save pointer to first digit */ do { digval = (unsigned int) (val % radix); val /= radix; /* get next digit */ /* convert to ascii and store */ if (digval > 9) *p++ = (char)(digval - 10 + 'a'); /* a letter */ /////////////////////////////// else *p++ = (char ) (digval + '0'); /* a digit */ //////////////////////////////// } while (val > 0); /* We now have the digit of the number in the buffer, but in reverse order. Thus we reverse them now. */ *p-- = '\0'; /* terminate string; p points to last digit */ ///////////////////// do { temp = *p; *p = *firstdig; *firstdig = temp; /* swap *p and *firstdig */ --p; ++firstdig; /* advance to next two digits */ } while (firstdig < p); /* repeat until halfway */ }
CGI.c
/***************** * CGI * * ******************/ #include<stdio.h> #include<stdlib.h> #include<string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <errno.h> #include <sys/time.h> #include <time.h> #define MAX 1024 #define FALSE -1 #define TRUE 1 #define BUFFER_SIZE 1024 typedef unsigned char BYTE; int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300, }; int name_arr[] = {115200,38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300, }; void set_speed(int fd, int speed); int set_Parity(int fd,int databits,int stopbits,int parity); void Print(BYTE a[]) { int i; for(i=0; i<4*4; i++) { printf("%02X ", a[i]); } printf("\n\n"); } int main() { char *method; char *data; int count; int i; int j; char *serialport = "/dev/tq2440_serial1" ; // int fd; int nread; char buffer[16] = {'\0'}; char buffer_all[16]={'\0'}; FILE *fp; time_t rawtime; struct tm *timeinfo; int end=5; printf("Content-type:text/html\n\n"); printf("<p>this is a cgi"); if((method=getenv("REQUEST_METHOD"))==NULL) // return 1; printf("<p>method: %s",method); if((data=getenv("QUERY_STRING"))==NULL) // return 1; printf("<p>%s",data); /*if((i=sscanf(data,"command=%s",command))==0) return 1; printf("%s",command);*/ /************************** * * * **************************/ fd=open(serialport,O_RDWR|O_NOCTTY|O_NDELAY); if(fd == -1) { printf("%s Open Error!\n",serialport); return -1; } printf("<p>open %s successfully !",serialport); set_speed(fd,115200); if (set_Parity(fd,8,1,'N')== FALSE) { printf("Set Parity Error\n"); exit(1); } tcflush(fd,TCIOFLUSH); write(fd,data,16); count=0; while(end) { end--; nread=read(fd,buffer,16); if(nread>0) { memcpy(buffer_all+count,buffer,nread); count += nread; } if(count==16) { printf("<p>receive success !"); break; } sleep(1); printf("<p>loop one time"); } Print(buffer_all); time(&rawtime); timeinfo=localtime(&rawtime); if((fp=fopen("/mnt/usrcommand.txt","ab+"))==NULL) return 1; fprintf(fp,"%4d-%02d-%02d %02d%02d%02d\n",1900+timeinfo->tm_year,1+timeinfo->tm_mon,timeinfo->tm_mday,timeinfo->tm_hour,timeinfo->tm_min,timeinfo->tm_sec); //fwrite(data,sizeof(char),strlen(data),fp); for(j=0; j<4*4; j++) { fprintf(fp,"%02X",buffer_all[j]); } //fwrite(buffer_all,sizeof(char),16,fp); fclose(fp); return 0; } void set_speed(int fd, int speed) { int i; int status; struct termios Opt; tcgetattr(fd, &Opt); for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) { if (speed == name_arr[i]) { tcflush(fd, TCIOFLUSH); cfsetispeed(&Opt, speed_arr[i]); /* */ cfsetospeed(&Opt, speed_arr[i]); status = tcsetattr(fd, TCSANOW, &Opt); /* */ if (status != 0) { perror("tcsetattr fd1"); return; } } tcflush(fd,TCIOFLUSH); /* */ } } int set_Parity(int fd,int databits,int stopbits,int parity) { struct termios options; if (tcgetattr( fd,&options) != 0) { printf("SetupSerial 1"); return(FALSE); } options.c_cflag &= ~CSIZE; /* */ switch (databits) /**/ { case 7: options.c_cflag |= CS7; break; case 8: options.c_cflag |= CS8; break; default: fprintf(stderr,"Unsupported data size\n"); return (FALSE); } switch (parity) { case 'n': case 'N': options.c_cflag &= ~PARENB; /* Clear parity enable */ options.c_iflag &= ~INPCK; /* Enable parity checking */ break; case 'o': case 'O': options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/ options.c_iflag |= INPCK; /* Disnable parity checking */ break; case 'e': case 'E': options.c_cflag |= PARENB; /* Enable parity */ options.c_cflag &= ~PARODD; /* */ options.c_iflag |= INPCK; /* Disnable parity checking */ break; case 'S': case 's': /*as no parity*/ options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; break; default: fprintf(stderr,"Unsupported parity\n"); return (FALSE); } /**/ switch (stopbits) { case 1: options.c_cflag &= ~CSTOPB; break; case 2: options.c_cflag |= CSTOPB; break; default: fprintf(stderr,"Unsupported stop bits\n"); return (FALSE); } /* Set input parity option */ if (parity != 'n') options.c_iflag |= INPCK; options.c_cc[VTIME] = 150; // 15 seconds options.c_cc[VMIN] = 0; options.c_lflag &= ~(ICANON |ISIG); options.c_iflag &= ~(ICRNL|IGNCR); tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */ if (tcsetattr(fd,TCSANOW,&options) != 0) { printf("SetupSerial 3"); return (FALSE); } return (TRUE); }