最近被安排要在产品上新增一个ota升级功能,一开始也没当回事,以为也就是一个从服务器上下载执行程序到本地,成功后弹出提示框并重启的简单功能。奈何自己还是想得太简单,在开发过程中逐渐发现这个过程还涉及到加解密,升级包的解压缩,以及最后对升级文件的校验比对等操作。把这些功能都加上去也颇费了一些时间,这几天把这阵子的收获做一个记录,也算是对这阵子的工作做一个总结。

由于涉及到的内容有点多,因此就分为几篇文章来叙述。今天,就先从文件的加解密开始讲起吧。
一、OTA升级包的加解密在ota的升级过程中,为了保护产品不受外界恶意攻击,被窃取数据,或者被植入恶意代码,在本地上传升级包前的加密以及客户端下载升级包并解密的操作是必不可少的。
如何实现对升级包的加解密操作呢?
当然自己去写算法对文件进行加解密也是可以的,但是安全性可能不太高,因此就需要去找一下是否有开源的加解密算法库能拿来直接用。百度过后,找到了openssl这个开源库里面有我们想要的东西(具体这个库是做什么用的,这里就不再赘述,百度上有很多相关的资料),话不多说,就决定用这个了。
在使用openssl库里面的加解密算法前,我们需要先编译。


进入该目录后依次执行以下两条命令编译出我们代码需要的库文件
./configmakeall
在编译成功后,我们可以看到目录下面多出了一些文件,如下图:

其中和这两个文件就是我们需要的东西。
2.头文件说明在编译出.a库文件后,接下来我们就需要先编写测试代码,在本地环境下先测试对应加解密代码的可用性,后续移植也会方便许多。
我们采用的是aes加密算法来加解密,头文件是./crypt/aes/文件夹下的文件。

以下是这个头文件里面的内容
/*crypto/aes/*-mode:C;c-file-style:"eay"-*-*//*====================================================================*Copyright(c)1998-2002**Redistributionanduseinsourceandbinaryforms,withorwithout*modification,arepermittedprovidedthatthefollowingconditions*aremet:**1.Redistributionsofsourcecodemustretaintheabovecopyright*notice,thislistofconditionsandthefollowingdisclaimer.**2.Redistributionsinbinaryformmustreproducetheabovecopyright*notice,thislistofconditionsandthefollowingdisclaimerin*thedocumentationand/orothermaterialsprovidedwiththe*distribution.**3.Alladvertisingmaterialsmentioningfeaturesoruseofthis*softwaremustdisplaythefollowingacknowledgment:*"ThisproductincludessoftwaredevelopedbytheOpenSSLProject*foruseintheOpenSSLToolkit.()"**4.Thenames"OpenSSLToolkit"and"OpenSSLProject"mustnotbeusedto*orseorpromoteproductsderivedfromthissoftwarewithout*,pleasecontact*openssl-core@**5.Productsderivedfromthissoftwaremaynotbecalled"OpenSSL"*normay"OpenSSL"appearintheirnameswithoutpriorwritten*permissionoftheOpenSSLProject.**6.Redistributionsofanyformwhatsoevermustretainthefollowing*acknowledgment:*"ThisproductincludessoftwaredevelopedbytheOpenSSLProject*foruseintheOpenSSLToolkit()"**THISSOFTWAREISPROVIDEDBYTHEOpenSSLPROJECT``ASIS''ANDANY*EXPRESSEDORIMPLIEDWARRANTIES,INCLUDING,BUTNOTLIMITEDTO,THE*IMPLIEDWARRANTIESOFMERCHANTABILITYANDFITNESSFORAPARTICULAR**ITSCONTRIBUTORSBELIABLEFORANYDIRECT,INDIRECT,INCIDENTAL,*SPECIAL,EXEMPLARY,ORCONSEQUENTIALDAMAGES(INCLUDING,BUT*NOTLIMITEDTO,PROCUREMENTOFSUBSTITUTEGOODSORSERVICES;*LOSSOFUSE,DATA,ORPROFITS;ORBUSINESSINTERRUPTION)*HOWEVERCAUSEDANDONANYTHEORYOFLIABILITY,WHETHERINCONTRACT,*STRICTLIABILITY,ORTORT(INCLUDINGNEGLIGENCEOROTHERWISE)*ARISINGINANYWAYOUTOFTHEUSEOFTHISSOFTWARE,EVENIFADVISED*OFTHEPOSSIBILITYOFSUCHDAMAGE.*====================================================================**/defineHEADER_AES_HifdefOPENSSL_NO_AESifdefineAES_ENCRYPT1defineAES_MAXNR14ifdef__cplusplusextern"C"{ifdefAES_LONGunsignedlongrd_key[4*(AES_MAXNR+1)];ifintrounds;};typedefstructaes_key_stAES_KEY;constchar*AES_options(void);intAES_set_encrypt_key(constunsignedchar*userKey,constintbits,AES_KEY*key);intAES_set_decrypt_key(constunsignedchar*userKey,constintbits,AES_KEY*key);intprivate_AES_set_encrypt_key(constunsignedchar*userKey,constintbits,AES_KEY*key);intprivate_AES_set_decrypt_key(constunsignedchar*userKey,constintbits,AES_KEY*key);voidAES_encrypt(constunsignedchar*in,unsignedchar*out,constAES_KEY*key);voidAES_decrypt(constunsignedchar*in,unsignedchar*out,constAES_KEY*key);voidAES_ecb_encrypt(constunsignedchar*in,unsignedchar*out,constAES_KEY*key,constintenc);voidAES_cbc_encrypt(constunsignedchar*in,unsignedchar*out,size_tlength,constAES_KEY*key,unsignedchar*ivec,constintenc);voidAES_cfb128_encrypt(constunsignedchar*in,unsignedchar*out,size_tlength,constAES_KEY*key,unsignedchar*ivec,int*num,constintenc);voidAES_cfb1_encrypt(constunsignedchar*in,unsignedchar*out,size_tlength,constAES_KEY*key,unsignedchar*ivec,int*num,constintenc);voidAES_cfb8_encrypt(constunsignedchar*in,unsignedchar*out,size_tlength,constAES_KEY*key,unsignedchar*ivec,int*num,constintenc);voidAES_ofb128_encrypt(constunsignedchar*in,unsignedchar*out,size_tlength,constAES_KEY*key,unsignedchar*ivec,int*num);voidAES_ctr128_encrypt(constunsignedchar*in,unsignedchar*out,size_tlength,constAES_KEY*key,unsignedcharivec[AES_BLOCK_SIZE],unsignedcharecount_buf[AES_BLOCK_SIZE],unsignedint*num);/*NB:theIVis_two_blockslong*/voidAES_ige_encrypt(constunsignedchar*in,unsignedchar*out,size_tlength,constAES_KEY*key,unsignedchar*ivec,constintenc);/*NB:theIVis_four_blockslong*/voidAES_bi_ige_encrypt(constunsignedchar*in,unsignedchar*out,size_tlength,constAES_KEY*key,constAES_KEY*key2,constunsignedchar*ivec,constintenc);intAES_wrap_key(AES_KEY*key,constunsignedchar*iv,unsignedchar*out,constunsignedchar*in,unsignedintinlen);intAES_unwrap_key(AES_KEY*key,constunsignedchar*iv,unsignedchar*out,constunsignedchar*in,unsignedintinlen);#[AES_BLOCK_SIZE];unsignedcharoutdate[AES_BLOCK_SIZE];unsignedchardecryptdate[AES_BLOCK_SIZE];staticvoid_encrypt_file(char*file_in,char*file_out,char*passwd);staticvoid_decrypt_file(char*file_in,char*file_out,char*passwd);intmain(intargc,char*argv[]){if(argc5){printf("enterparametererror!!!\r\n");exit(-1);}charfile_in[64];charfile_out[64];intmode=-1;charpasswd[16+1];if(*(argv[1]+0)=='-')//加密{if(*(argv[1]+1)=='d')mode=AES_DECRYPT;elseif(*(argv[1]+1)=='e')mode=AES_ENCRYPT;}strcpy(file_in,argv[2]);strcpy(file_out,argv[3]);strcpy(passwd,argv[4]);printf("mode:%d.\r\n",mode);printf("file_in:%s.\r\n",file_in);printf("file_out:%s.\r\n",file_out);printf("passwd:%s.\r\n",passwd);if(mode==AES_DECRYPT){_decrypt_file(file_in,file_out,passwd);}elseif(mode==AES_ENCRYPT){_encrypt_file(file_in,file_out,passwd);}return0;}文件加密函数
staticvoid_encrypt_file(char*file_in,char*file_out,char*passwd){FILE*fp_in=fopen(file_in,"r+");FILE*fp_out=fopen(file_out,"w+");unsignedchariv[AES_BLOCK_SIZE];intpostion=0;intbytes_read,bytes_write;AES_KEYaes_key;AES_set_encrypt_key(passwd,128,aes_key);while(1){memset(iv,0,AES_BLOCK_SIZE);bytes_read=fread(indate,1,AES_BLOCK_SIZE,fp_in);AES_cfb128_encrypt(indate,outdate,bytes_read,aes_key,iv,postion,AES_ENCRYPT);bytes_write=fwrite(outdate,1,bytes_read,fp_out);if(bytes_readAES_BLOCK_SIZE)break;}fclose(fp_in);fclose(fp_out);}文件解密函数
staticvoid_decrypt_file(char*file_in,char*file_out,char*passwd){FILE*fp_in=fopen(file_in,"r+");FILE*fp_out=fopen(file_out,"w+");unsignedchariv[AES_BLOCK_SIZE];intpostion=0;intbytes_read,bytes_write;AES_KEYaes_key;AES_set_encrypt_key(passwd,128,aes_key);while(1){memset(iv,0,AES_BLOCK_SIZE);bytes_read=fread(outdate,1,AES_BLOCK_SIZE,fp_in);AES_cfb128_encrypt(outdate,decryptdate,bytes_read,aes_key,iv,postion,AES_DECRYPT);bytes_write=fwrite(decryptdate,1,bytes_read,fp_out);if(bytes_readAES_BLOCK_SIZE)break;}fclose(fp_in);fclose(fp_out);}测试代码编写完了,最后我们需要对代码进行测试,看看是否可能正常对文件进行加解密。
我们先在otaPack下make,编译出可执行程序。
makeall
编译正常,接下来就是测试环节。
加密
./
解密
./
到这里,测试后发现经过我们的代码加解密后,最后的压缩包是无法正常解压缩的。那么问题出在哪里呢?这里我查了很多资料,最后查到说是这里passwd是需要16个字符才能正常加解密的,如果没有满16个字符,内部会做填充。我们项目对密码长度没有要求,因此这一块先不花时间去深究。重新设置16个字符长度的密码进行加密测试
.//
最后是可以对加解密后的压缩包进行正常的解压缩操作的,因此可能说明我们的代码是没有什么大问题的。最后就是需要将相应的解密代码移植到开发板平台上,这里也不再赘述。
好了,今天就先讲到这里吧。有时间在讲其他部分的内容





