单片机固件MD5校验、AES加密、gzip压缩方案(QT)

时间:2024-01-22 12:11:06

方案简介

先使用glib对固件进行压缩;然后使用MD5对固件进行添加头部校验值;最后使用AES对固件进行加密。

MD5

MD5,全称Message Digest Algorithm 5,即信息摘要算法5,是一种被广泛使用的密码散列函数。它可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开,用以取代MD4算法。这套算法的程序在RFC 1321标准中被加以规范。

MD5的功能(作为校验值)可以看这一篇:MD5数据加密方法

AES加密

AES加密,全称Advanced Encryption Standard,是一种对称的分组加密技术。它使用128位分组加密数据,每次加密16个字节,提供比WEP/TKIPS的RC4算法更高的加密强度。AES的加密码表和解密码表是分开的,并且支持子密钥加密,这种做法优于以前用一个特殊的密钥解密的做法。此外,AES算法支持任意分组大小,初始时间快,特别是它具有的并行性可以有效地利用处理器资源。

AES算法具有以下优点:

  1. 应用范围广:可以用来加密数据、电子邮件和网络传输,以保护隐私和网络数据的安全性。
  2. 等待时间短:相对于其他加密算法,AES加密速度较快。
  3. 相对容易隐藏:AES加密算法相对容易隐藏,不容易被破解。
  4. 吞吐量高:能够提供高吞吐量,适用于大规模的数据加密。

此外,AES加密的安全性非常高,它使用128位、192位或256位的密钥,可以抵抗各种类型的攻击,包括密码穷举攻击、密码分析攻击和密码拓展攻击。因此,AES加密算法被认为是目前世界上最安全、最先进的加密算法之一。

AES的具体功能及其实现原理可以参考这一篇:AES加密算法原理的详细介绍与实现

gzip

gzip是一个使用广泛的压缩程序,最早由Jean-loup Gailly和Mark Adler创建,用于UNⅨ系统的文件压缩。它可以用来压缩文件,压缩后的文件名通常会添加“.gz”的扩展名。gzip不仅可以用来压缩大的、较少使用的文件以节省磁盘空间,还可以和tar命令一起构成linux操作系统中比较流行的压缩文件格式。

zlib是一套通用的解压缩开源库,提供了内存(in-memory)压缩和解压函数,能检测解压出来的数据完整性,支持读写gzip(.gz)格式的文件。该库使用DEFLATE算法压缩数据部分,这是一种Huffman编码的加强。

本次研究的是在QT上面使用glib库。

glib库的简介和主要函数的功能可以看这一篇:第三方库介绍——zlib库

在QT中使用MD5、AES、glib

QT环境

必须使用MinGW来构建项目

MD5

使用QT内嵌的QCryptographicHash库,这个库提供了以下加密类型,这里只使用了MD5。

类型


描述

QCryptographicHash::Md4

0

Generate an MD4 hash sum

QCryptographicHash::Md5

1

Generate an MD5 hash sum

QCryptographicHash::Sha1

2

Generate an SHA-1 hash sum

QCryptographicHash::Sha224

3

Generate an SHA-224 hash sum (SHA-2). Introduced in Qt 5.0

QCryptographicHash::Sha256

4

Generate an SHA-256 hash sum (SHA-2). Introduced in Qt 5.0

QCryptographicHash::Sha384

5

Generate an SHA-384 hash sum (SHA-2). Introduced in Qt 5.0

QCryptographicHash::Sha512

6

Generate an SHA-512 hash sum (SHA-2). Introduced in Qt 5.0

QCryptographicHash::Sha3_224

RealSha3_224

Generate an SHA3-224 hash sum. Introduced in Qt 5.1

QCryptographicHash::Sha3_256

RealSha3_256

Generate an SHA3-256 hash sum. Introduced in Qt 5.1

QCryptographicHash::Sha3_384

RealSha3_384

Generate an SHA3-384 hash sum. Introduced in Qt 5.1

QCryptographicHash::Sha3_512

RealSha3_512

Generate an SHA3-512 hash sum. Introduced in Qt 5.1

QCryptographicHash::Keccak_224

7

Generate a Keccak-224 hash sum. Introduced in Qt 5.9.2

QCryptographicHash::Keccak_256

8

Generate a Keccak-256 hash sum. Introduced in Qt 5.9.2

QCryptographicHash::Keccak_384

9

Generate a Keccak-384 hash sum. Introduced in Qt 5.9.2

QCryptographicHash::Keccak_512

10

Generate a Keccak-512 hash sum. Introduced in Qt 5.9.2

QCryptographicHash::Blake2b_160

15

Generate a BLAKE2b-160 hash sum. Introduced in Qt 6.0

QCryptographicHash::Blake2b_256

16

Generate a BLAKE2b-256 hash sum. Introduced in Qt 6.0

QCryptographicHash::Blake2b_384

17

Generate a BLAKE2b-384 hash sum. Introduced in Qt 6.0

QCryptographicHash::Blake2b_512

18

Generate a BLAKE2b-512 hash sum. Introduced in Qt 6.0

QCryptographicHash::Blake2s_128

19

Generate a BLAKE2s-128 hash sum. Introduced in Qt 6.0

QCryptographicHash::Blake2s_160

20

Generate a BLAKE2s-160 hash sum. Introduced in Qt 6.0

QCryptographicHash::Blake2s_224

21

Generate a BLAKE2s-224 hash sum. Introduced in Qt 6.0

QCryptographicHash::Blake2s_256

22

Generate a BLAKE2s-256 hash sum. Introduced in Qt 6.0

MD5的使用没有什么难点,这是QT做完的内容,直接使用就行。

///这个库需要在目标文件中包含
#include <QCryptographicHash>
--------------------------------------
QByteArray array; ///< 假定的源数据
--------------------------------------

QT中使用MD5加密:

QCryptographicHash hash(QCryptographicHash::Md5); ///< Md5加密
hash.addData(array.toHex()); ///< 添加数据
QByteArray retArray = hash.result(); ///< 加密后的数据

QT中使用MD5校验:

QCryptographicHash hash(QCryptographicHash::Md5); ///< Md5加密
hash.addData(array.toHex()); ///< 添加数据
QByteArray retArray = hash.result(); ///< 加密后的数据
	
其实就是将文件再次加密,最后将文件加密得到的MD5校验值与第一次加密的MD5值进行比较,如果相同则表示文件未被修改,主要用于验证文件的完整性。

AES

QT部署AES

QT中没有可以直接使用的AES加密库,需要外部开源的AES加密库,这里使用https://github.com/bricke/Qt-AES开源库,这个库需要复制两个文件到工程中,这个库具体的功能和使用开源查看Qt-AES加密库文章。

AES使用

///这个库需要在目标文件中包含
#include "qaesencryption.h"

使用AES对数据进行加密:

static QByteArray encodedText(QByteArray data)
{
    if(data.isEmpty())
    {
        return 0;
    }
    /// keyLen_main、mode_main、padding_main、iv:全局变量
    QAESEncryption encryption((QAESEncryption::Aes)keyLen_main,
                              (QAESEncryption::Mode)mode_main,
                              (QAESEncryption::Padding)padding_main);
    //QString str = QString::fromUtf8(data);
    //对源数据加密
    QByteArray encoded = encryption.encode(data, keys_main, iv);

    return encoded;
}

使用AES对数据进行解密

static QByteArray decodedText(QByteArray data)
{
    if(data.isEmpty())
    {
        return 0;
    }
    /// keyLen_main、mode_main、padding_main、iv:全局变量
    QAESEncryption encryption((QAESEncryption::Aes)keyLen_main,
                              (QAESEncryption::Mode)mode_main,
                              (QAESEncryption::Padding)padding_main);

    //解密
    QByteArray decodedText = encryption.decode(data, keys_main, iv);

    return decodedText;
}

glib

glib是放置在了QT库中,

只需要在工程.pro文件中加入
 LIBS += -lz 
 ------------------------------------
并且在目标文件中加入头文件
 #include <zlib.h>

在使用glib库时必须使用MinGW来构建工程,MSVC2019构建带有glib库的工程会报错。 使用glib时需要对其进行封装以确保直接使用 QByteArray 类型进行压缩(glib中的compress函数传入的参数是Bytef),具体的封装开源参考zlib库实现数据流的压缩与解压缩

/**
 * @brief 压缩数据
 * @param postBody  数据(QByteArray类型)
 * @return 压缩完成的数据
 */
static QByteArray GzipCompress(QByteArray postBody)
{
    QByteArray outBuf;
    int *errorCode = NULL;
    /// ZlibCompress用于预测压缩后的数据大小
    long outlength = ZlibCompress(outBuf,postBody,errorCode);

    if(outlength != (-1))
    {
        return outBuf;
    }
    outBuf = postBody;
    return outBuf;
}
/**
 * @brief 解压缩
 * @param src 目标数据(QByteArray)
 * @return 解压缩的数据
 */
static QByteArray GZipUnCompress(QByteArray src)
{
	QByteArray outBuffer;
    int *errorCode = NULL;
    long outlength = ZlibUncompress(outBuffer,src,errorCode);

    if(outlength != (-1))
    {
        return outBuffer;
    }
    outBuffer = src;
    return outBuffer;
}

ui设计

主界面

单片机固件MD5校验、AES加密、gzip压缩方案(QT)_MCU

AES配置界面

主界面中点击工具栏 设置AES 即可跳转至AES配置界面。

单片机固件MD5校验、AES加密、gzip压缩方案(QT)_数据_02

验证(结果)

打开固件加密软件,点击主界面的浏览按钮打开选择固件窗口,在选择固件窗口中选中要加密的bin文件(实际可以加密任何文件,只需要将对应文件重命名为.bin后缀即可)。

单片机固件MD5校验、AES加密、gzip压缩方案(QT)_Qt_03

选中下面的三个选项框(使用gzip、使用MD5、使用AES),并且点击工具栏的 设置AES 打开AES配置界面,在AES 密钥在线生成器中生成一个256bit的密钥(BuB6PiubJnKu4hDTnr4k0tIiI4v2HrgE),其余保持默认点击 AES配置 界面的 ok 按钮。

单片机固件MD5校验、AES加密、gzip压缩方案(QT)_Qt_04

点击开始加密等待主界面下方显示输出结果即可,显示 加密完成 并且显示了输出文件位置和文件名称表示加密完成,并且在输出文件位置中可以找到一个 result.ldx 的文件,该文件比源文件缩小了1倍左右,并且已经被加密,使用Beyond Compare 4软件可以发现 rtthread.bin 与 result.ldx 文件内容不一致,表示压缩及加密完成。

单片机固件MD5校验、AES加密、gzip压缩方案(QT)_MCU_05

单片机固件MD5校验、AES加密、gzip压缩方案(QT)_Qt_06

接着验证解密功能,保持设置即不修改AES配置,只修改文件即可,点击浏览,选中刚刚生成的result.ldx文件点击解密,等待状态框输出解密完成和输出文件位置,在输出文件目录下可以找到一个restore.bin文件,将rtthread.bin与restore.bin文件使用Beyond Compare 4软件打开,可以看到rtthread.bin与restore.bin文件一致即表示加密解密功能完成无误。

单片机固件MD5校验、AES加密、gzip压缩方案(QT)_Qt_07

单片机固件MD5校验、AES加密、gzip压缩方案(QT)_MCU_08

至此结束。

备注

文章为原创,个人博客。

源码

https://gitee.com/ldxlxx/QT_bootloader/tree/master/