ota升级到底升级什么(OTA升级功能系列一)
ota升级到底升级什么(OTA升级功能系列一)以下是这个头文件里面的内容在编译出.a库文件后,接下来我们就需要先编写测试代码,在本地环境下先测试对应加解密代码的可用性,后续移植也会方便许多。我们采用的是aes加密算法来加解密,头文件是./crypt/aes/文件夹下的aes.h文件。进入该目录后依次执行以下两条命令编译出我们代码需要的库文件./config make all在编译成功后,我们可以看到目录下面多出了一些文件,如下图:其中libcrypto.a和libssl.a这两个文件就是我们需要的东西。
前言最近被安排要在产品上新增一个OTA升级功能,一开始也没当回事,以为也就是一个从服务器上下载执行程序到本地,成功后弹出提示框并重启的简单功能。奈何自己还是想得太简单,在开发过程中逐渐发现这个过程还涉及到加解密,升级包的解压缩,以及最后对升级文件的校验比对等操作。把这些功能都加上去也颇费了一些时间,这几天把这阵子的收获做一个记录,也算是对这阵子的工作做一个总结。
由于涉及到的内容有点多,因此就分为几篇文章来叙述。今天,就先从文件的加解密开始讲起吧。
一、OTA升级包的加解密
在ota的升级过程中,为了保护产品不受外界恶意攻击,被窃取数据,或者被植入恶意代码,在本地上传升级包前的加密以及客户端下载升级包并解密的操作是必不可少的。
如何实现对升级包的加解密操作呢?
当然自己去写算法对文件进行加解密也是可以的,但是安全性可能不太高,因此就需要去找一下是否有开源的加解密算法库能拿来直接用。百度过后,找到了openssl这个开源库里面有我们想要的东西(具体这个库是做什么用的,这里就不再赘述,百度上有很多相关的资料),话不多说,就决定用这个了。
在使用openssl库里面的加解密算法前,我们需要先编译。
进入该目录后依次执行以下两条命令编译出我们代码需要的库文件
./config
make all
在编译成功后,我们可以看到目录下面多出了一些文件,如下图:
其中libcrypto.a和libssl.a这两个文件就是我们需要的东西。
2.头文件说明在编译出.a库文件后,接下来我们就需要先编写测试代码,在本地环境下先测试对应加解密代码的可用性,后续移植也会方便许多。
我们采用的是aes加密算法来加解密,头文件是./crypt/aes/文件夹下的aes.h文件。
以下是这个头文件里面的内容
/* crypto/aes/aes.h -*- mode:C; c-FILE-style: "eay" -*- */
/* ====================================================================
* Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms with or without
* modification are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT INDIRECT INCIDENTAL
* SPECIAL EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING BUT
* NOT LIMITED TO PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE DATA OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY WHETHER IN CONTRACT
* STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
*/
#ifndef HEADER_AES_H
#define HEADER_AES_H
#include <openssl/opensslconf.h>
#ifdef OPENSSL_NO_AES
#error AES is disabled.
#endif
#include <stddef.h>
#define AES_ENCRYPT 1
#define AES_DECRYPT 0
/* Because array size can't be a const in C the following two are macros.
Both sizes are in bytes. */
#define AES_MAXNR 14
#define AES_BLOCK_SIZE 16
#ifdef __cplusplus
extern "C" {
#endif
/* This should be a hidden type but EVP requires that the size be known */
struct aes_key_st {
#ifdef AES_LONG
unsigned long rd_key[4 *(AES_MAXNR 1)];
#else
unsigned int rd_key[4 *(AES_MAXNR 1)];
#endif
int rounds;
};
typedef struct aes_key_st AES_KEY;
const char *AES_options(void);
int AES_set_encrypt_key(const unsigned char *userKey const int bits
AES_KEY *key);
int AES_set_decrypt_key(const unsigned char *userKey const int bits
AES_KEY *key);
int private_AES_set_encrypt_key(const unsigned char *userKey const int bits
AES_KEY *key);
int private_AES_set_decrypt_key(const unsigned char *userKey const int bits
AES_KEY *key);
void AES_encrypt(const unsigned char *in unsigned char *out
const AES_KEY *key);
void AES_decrypt(const unsigned char *in unsigned char *out
const AES_KEY *key);
void AES_ecb_encrypt(const unsigned char *in unsigned char *out
const AES_KEY *key const int enc);
void AES_cbc_encrypt(const unsigned char *in unsigned char *out
size_t length const AES_KEY *key
unsigned char *ivec const int enc);
void AES_cfb128_encrypt(const unsigned char *in unsigned char *out
size_t length const AES_KEY *key
unsigned char *ivec int *num const int enc);
void AES_cfb1_encrypt(const unsigned char *in unsigned char *out
size_t length const AES_KEY *key
unsigned char *ivec int *num const int enc);
void AES_cfb8_encrypt(const unsigned char *in unsigned char *out
size_t length const AES_KEY *key
unsigned char *ivec int *num const int enc);
void AES_ofb128_encrypt(const unsigned char *in unsigned char *out
size_t length const AES_KEY *key
unsigned char *ivec int *num);
void AES_ctr128_encrypt(const unsigned char *in unsigned char *out
size_t length const AES_KEY *key
unsigned char ivec[AES_BLOCK_SIZE]
unsigned char ecount_buf[AES_BLOCK_SIZE]
unsigned int *num);
/* NB: the IV is _two_ blocks long */
void AES_ige_encrypt(const unsigned char *in unsigned char *out
size_t length const AES_KEY *key
unsigned char *ivec const int enc);
/* NB: the IV is _four_ blocks long */
void AES_bi_ige_encrypt(const unsigned char *in unsigned char *out
size_t length const AES_KEY *key
const AES_KEY *key2 const unsigned char *ivec
const int enc);
int AES_wrap_key(AES_KEY *key const unsigned char *iv
unsigned char *out
const unsigned char *in unsigned int inlen);
int AES_unwrap_key(AES_KEY *key const unsigned char *iv
unsigned char *out
const unsigned char *in unsigned int inlen);
#ifdef __cplusplus
}
#endif
#endif /* !HEADER_AES_H */
可以看到,这个库提供的加解密算法,还是挺多的。本来以为应该有对应的demo代码,但是找了很久没找到,因此对于这些函数,只能边查资料边试
三、测试代码1.Makefile编写
首先,我们先回到主目录下,创建一个otaPack文件夹,用于存放我们的测试代码
接着先创建一个otaPack.c文件,用于编写我们的测试代码
touch otaPack.c
接下来我们需要编写Makefile,用编译我们的代码
CC=cc
CFLAGS=-O -I../crypto/aes -I../include
OTAPACK_OBJS = otaPack.o ../libcrypto.a ../libssl.a
.c.o:
$(CC) -c $(CFLAGS) $*.c
all: otaPack
otaPack: $(OTAPACK_OBJS)
$(CC) $(CFLAGS) -o $@ $(OTAPACK_OBJS)
clean:
/bin/rm -f *.o otaPack
2.AES文件加解密代码
编写完Makefile后,最后就是文件加解密测试代码的编写。
main主函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <aes.h>
unsigned char indate[AES_BLOCK_SIZE];
unsigned char outdate[AES_BLOCK_SIZE];
unsigned char decryptdate[AES_BLOCK_SIZE];
static void _encrypt_file(char *file_in char *file_out char *passwd);
static void _decrypt_file(char *file_in char *file_out char *passwd);
int main(int argc char *argv[])
{
if(argc < 5)
{
printf("enter parameter error!!!\r\n");
exit(-1);
}
char file_in[64];
char file_out[64];
int mode = -1;
char passwd[16 1];
if(*(argv[1] 0) == '-') //加密
{
if(*(argv[1] 1) == 'd')
mode = AES_DECRYPT;
else if(*(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);
}
else if(mode == AES_ENCRYPT)
{
_encrypt_file(file_in file_out passwd);
}
return 0;
}
文件加密函数
static void _encrypt_file(char *file_in char *file_out char *passwd)
{
FILE *fp_in = fopen(file_in "r ");
FILE *fp_out = fopen(file_out "w ");
unsigned char iv[AES_BLOCK_SIZE];
int postion = 0;
int bytes_read bytes_write;
AES_KEY aes_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_read < AES_BLOCK_SIZE)
break;
}
fclose(fp_in);
fclose(fp_out);
}
文件解密函数
static void _decrypt_file(char *file_in char *file_out char *passwd)
{
FILE *fp_in = fopen(file_in "r ");
FILE *fp_out = fopen(file_out "w ");
unsigned char iv[AES_BLOCK_SIZE];
int postion = 0;
int bytes_read bytes_write;
AES_KEY aes_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_read < AES_BLOCK_SIZE)
break;
}
fclose(fp_in);
fclose(fp_out);
}
测试
代码编写完了,最后我们需要对代码进行测试,看看是否可能正常对文件进行加解密。
我们先在otaPack下make,编译出可执行程序。
make all
编译正常,接下来就是测试环节。
touch test
echo 123456789test1111 >> test
zip test.zip test
加密
./otaPack -e test.zip encrypt.zip 123456
解密
./otaPack -d encrypt.zip decrypt.zip 123456
到这里,测试后发现经过我们的代码加解密后,最后的decrypt.zip压缩包是无法正常解压缩的。那么问题出在哪里呢?这里我查了很多资料,最后查到说是这里passwd是需要16个字符才能正常加解密的,如果没有满16个字符,内部会做填充。我们项目对密码长度没有要求,因此这一块先不花时间去深究。重新设置16个字符长度的密码进行加密测试
./otaPack -e test.zip encrypt.zip 1234567890123456
./otaPack -d encrypt.zip decrypt.zip 1234560123456
最后是可以对加解密后的压缩包进行正常的解压缩操作的,因此可能说明我们的代码是没有什么大问题的。最后就是需要将相应的解密代码移植到开发板平台上,这里也不再赘述。
好了,今天就先讲到这里吧。有时间在讲其他部分的内容