openwrt对单片机程序加解密存储和传输

在物联网产品开发中,经常需要对单片机或其他嵌入式系统进行在线升级,原始二进制文件

在存储和传输的过程中非常不安全,可以对二进制文件进行高效的加密之后再使用,

并在片内进行解密之后再执行各自的升级任务。

比如对整个二进制文件以16字节为段,每段进行AES编码,不足16字节需要补全后再编码,

在新文件尾部使用额外两字节记录与原始文件的差值大小,方便解密还原使用。

binfilecrypto.c

/**
 *binary文件高效加解密
 *create by iversondeng168
 **/
#include <stdio.h>
#include <string.h>
#include "aes.h"


#define I8            char
#define UI8           unsigned char


#define DEBUG



/**
filename:文件路径
mode:加解密模式
*/
static int bin_file_xcode(const I8*filename,UI8 mode)
{
    #define NAME_MAX_SIZE  (128)
    #define DATA_MAX_SIZE  (16)
    #define MAX_TRYCNT     (10)


    mbedtls_aes_context context;


    FILE * fp          = NULL;
    FILE * newfp       = NULL;
    long filelen       = 0;
    long offset        = 0;
    long newoffset     = 0;
    int tmp            = 0;
    int ret            = 0;

    int trycnt         = 0;

    UI8 databuf[DATA_MAX_SIZE];
    UI8 outbuf[DATA_MAX_SIZE];
    int outbuflen      = 0;

    I8 newfilename[NAME_MAX_SIZE];

    
	/**
     由于AES加解密 16字节对齐问题,
	 故让加密固件最后面多加两个字节代表与原始固件的大小差值.
	*/
    UI8 lendiff[2];
    long fpfilelen     = 0;
    int tmplen         = 0;
 

    //打开原始文件
    fp                 = fopen(filename, "rb");
    if(fp == NULL)     return -1;
     
    memset(newfilename,0,sizeof(newfilename));
   

    //根据加解密模式,决定新生成文件名称
    switch(mode)
    {
       case 0:
            sprintf(newfilename,"%s-encode",filename);
            break;
       case 1:
            sprintf(newfilename,"%s-decode",filename);
            break;
       default:
            return -1;
    }
 

    //打开新生成文件
    newfp              = fopen(newfilename, "wb+");    
    if(newfp == NULL)  return -1;

  
    //获取原始文件长度
    fseek(fp,0,SEEK_END);
    filelen            = ftell(fp);
    fpfilelen          = filelen;

#ifdef DEBUG
    printf("filelen=%ld\n",filelen);
#endif
	
    
	//解密模式
    if(mode == 1)
    {
       //读取固件差值
       fseek(fp,filelen - sizeof(lendiff),SEEK_SET);

       trycnt          = 0;

LENDIFF_R_LOOPS:
       ret             = fread(lendiff, sizeof(lendiff), 1, fp);
       if(ret != 1) {
           if(trycnt++ < MAX_TRYCNT)
              goto LENDIFF_R_LOOPS;
           else
              return -1;
       }
       
	   //获取原始文件在加密之前的大小
       tmplen          = lendiff[0] << 8 | lendiff[1];
       filelen        -= sizeof(lendiff);

#ifdef DEBUG
       printf("tmplen=%d\n",tmplen);
#endif
    }


    fseek(fp,0,SEEK_SET);

    while(filelen > 0)
    {
       tmp             = filelen / DATA_MAX_SIZE ? DATA_MAX_SIZE : filelen;
       filelen        -= tmp;

       trycnt          = 0;

	   //每次读取16字节,不足16字节以剩余为准
FREAD_LOOPS: 

       ret             = fread(databuf, tmp, 1, fp);

       if(ret != 1){
          if(trycnt++ < MAX_TRYCNT){
             #ifdef DEBUG
             printf("fread ret=%d\toffset=%d\n",ret,(int)offset);
             #endif
             goto FREAD_LOOPS;
          }
          else{
             return -1;
          }
       }
 

       switch(mode)
       {
         case 0:
            //将每次读取的字节进行AES加密 
	        aes_encode(&context,databuf,outbuf,tmp,&outbuflen);
	        break;

         case 1:
            //将每次读取的字节进行AES解密
	        aes_decode(&context,databuf,outbuf,tmp);
            if(filelen == 0){
                outbuflen = tmp - tmplen;
            }
            else{
                outbuflen = tmp;
            }

	        break;
       }
       
       
   
       trycnt          = 0;

	   //将每次处理后的字节写入新文件
FWRITE_LOOPS:
       ret             = fwrite(outbuf, outbuflen, 1, newfp);
      
       if(ret != 1){  
          if(trycnt++ < MAX_TRYCNT){
             #ifdef DEBUG
             printf("fwrite ret=%d\tnewoffset=%d\n",ret,(int)newoffset);
             #endif
             goto FWRITE_LOOPS;
          }
          else{
             return -1;
          }
       }

 
       //原始文件和新生成文件同步移动文件指针
       offset         += tmp;
       newoffset      += outbuflen;

       fseek(fp,offset,SEEK_SET);
       fseek(newfp,newoffset,SEEK_SET);
    }


    //加密模式
    if(mode == 0)
    {
	   //16字节整数倍
       tmplen          = fpfilelen % DATA_MAX_SIZE;
	   //16字节求余数
       if(tmplen > 0)  
           tmplen      = DATA_MAX_SIZE - tmplen;
 
       //加密后固件最后两字节代表差数
       lendiff[0]      = tmplen >> 8;
       lendiff[1]      = tmplen & 0xFF;

       trycnt          = 0;
LENDIFF_W_LOOPS: 
       ret             = fwrite(lendiff, sizeof(lendiff), 1, newfp);
       if(ret != 1){
           if(trycnt++ < MAX_TRYCNT)
             goto LENDIFF_W_LOOPS;
           else
             return -1;
       } 
         
    }


    aes_free(&context);

    fclose(fp);
    fclose(newfp);       
    
    return 0;
} 





/**eg.
 * binfilecrypto -e demobin #对demobin文件加密
 * binfilecrypto -d demobin-encode #对demobin-encode文件解密
*/
int main(int argc,char*argv[])
{
   int exemode;

   //匹配必须为三个参数
   if(argc != 3){
       #ifdef DEBUG
       printf("argc error!\n");
       #endif
       return -1;
   }

   //加密模式
   if(!strcmp(argv[1],"-e"))
   {
      exemode = 0;          
   }
   //解密模式 
   else if(!strcmp(argv[1],"-d"))
   {
      exemode = 1;
   }
   else{

	   //暂时不支持的模式
       #ifdef DEBUG
       printf("format not support\n");
       #endif

       return -1;
   }

 
   //加解密统一函数
   return bin_file_xcode(argv[2],exemode);
}

交叉编译Makefile文件

CC=/home/openwrt_renew/openwrt-master/staging_dir/toolchain-mips_74kc_gcc-5.3.0_musl-1.1.16/bin/mips-openwrt-linux-gcc

OTHER_HEADERS = aes.h

binfilecrypto:aes_code.o binfilecrypto.o
	$(CC) aes_code.o binfilecrypto.o -o binfilecrypto 

aes_code.o: $(OTHER_HEADERS)
	$(CC) -c aes_code.c

binfilecrypto.o:
	$(CC) -c binfilecrypto.c 
	
clean:
	rm -rf *.o binfilecrypto

	

完整源码

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值