ESP32学习笔记(47)——加密算法AES/MD5/SHA

一、简介

1.1 SSL

SSL:(Secure Socket Layer,安全套接字层),位于可靠的面向连接的网络层协议和应用层协议之间的一种协议层。SSL通过互相认证、使用数字签名确保完整性、使用加密确保私密性,以实现客户端和服务器之间的安全通讯。该协议由两层组成:SSL记录协议和SSL握手协议。

1.2 TLS

TLS:(Transport Layer Security,传输层安全协议),用于两个应用程序之间提供保密性和数据完整性。该协议由两层组成:TLS记录协议和TLS握手协议。
ESP32学习笔记(47)——加密算法AES/MD5/SHA_第1张图片

1.3 mbed TLS

乐鑫esp-idf框架集成开源的 mbedtls 加密库。mbedtls 也许是最小巧的SSL代码库。高效、便于移植和集成。支持常见的安全算法,如:AES、DES、RSA、ECC、SHA256、MD5、BASE64等等。除此之外还支持公钥证书体系。它提供了具有直观的 API 和可读源代码的 SSL 库。该工具即开即用,可以在大部分系统上直接构建它,也可以手动选择和配置各项功能。

从功能角度来看,该mbedtls分为三个主要部分:

  • SSL/TLS 协议实施。
  • 一个加密库。
  • 一个 X.509 证书处理库。

二、AES - ECB

2.1 简介

AES(Advanced Encryption Standard,高级加密标准) 又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。

ECB(Electronic Code Book电子密码本),是最早采用和最简单的模式,它将加密的数据分成若干组,每组的大小跟加密密钥长度相同,然后每组都用相同的密钥进行加密。

优点:

  • 简单;
  • 有利于并行计算;
  • 误差不会被传送;

缺点:

  • 不能隐藏明文的模式;
  • 可能对明文进行主动攻击;

因此,此模式适于加密小消息。

2.2 API说明

API 文档查看 mbed TLS源码文档

2.2.1 mbedtls_aes_init

功能 初始化指定的 AES 上下文。它必须是在使用上下文之前调用的第一个 API。
函数定义 void mbedtls_aes_init(mbedtls_aes_context * ctx)
参数 ctx:要初始化的 AES 上下文。这一定不是NULL
返回

2.2.2 mbedtls_aes_setkey_enc

功能 设置加密密钥。
函数定义 int mbedtls_aes_setkey_enc(mbedtls_aes_context * ctx, const unsigned char * key, unsigned int keybits)
参数 ctx:密钥应绑定到的 AES 上下文。它必须被初始化。
key:加密密钥。这必须是大小keybits位的可读缓冲区。
keybits:以位为单位传递的数据大小。有效的选项是:128 位 / 192位 / 256 位
返回 0 - 成功,0x0020 - 密钥长度无效

2.2.3 mbedtls_aes_crypt_ecb

功能 执行 AES 单块加密或解密操作。
它对mode参数中定义的输入数据缓冲区执行参数中定义的操作(加密或解密)input
mbedtls_aes_init()以及mbedtls_aes_setkey_enc()mbedtls_aes_setkey_dec()必须在第一次使用相同上下文调用此 API 之前调用。
函数定义 int mbedtls_aes_crypt_ecb(mbedtls_aes_context * ctx, int mode, const unsigned char input[16], unsigned char output[16])
参数 ctx:用于加密或解密的 AES 上下文。它必须被初始化并绑定到一个键。
mode:AES 操作:MBEDTLS_AES_ENCRYPTMBEDTLS_AES_DECRYPT
input:保存输入数据的缓冲区。它必须是可读的,并且16长度至少为Bytes。
output:将写入输出数据的缓冲区。它必须是可写的,并且16长度至少为Bytes。
返回 0 - 成功

2.2.4 mbedtls_aes_setkey_dec

功能 设置解密密钥。
函数定义 int mbedtls_aes_setkey_dec(mbedtls_aes_context * ctx, const unsigned char * key, unsigned int keybits)
参数 ctx:密钥应绑定到的 AES 上下文。它必须被初始化。
key:解密密钥。这必须是大小keybits位的可读缓冲区。
keybits:以位为单位传递的数据大小。有效的选项是:128 位 / 192位 / 256 位
返回 0 - 成功,0x0020 - 密钥长度无效

2.2.5 mbedtls_aes_free

功能 释放并清除指定的 AES 上下文。
函数定义 void mbedtls_aes_free(mbedtls_aes_context * ctx)
参数 ctx:要清除的 AES 上下文。如果是NULL,则此函数不执行任何操作。否则,上下文必须至少已初始化。
返回

2.3 实例

ECB模式只能实现16字节的明文加解密。

需要包含 mbedtls/aes.h

#include 
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"

#include "mbedtls/aes.h"

void app_main(void)
{
     
    printf("AES-ECB 加密-数据块(128位),偏移量为0\n");

    mbedtls_aes_context aes_ctx;
    //密钥数值
    unsigned char key[16] = {
     'e', 'c', 'b', 'p', 'a', 's', 's', 'w', 'o', 'r', 'd', '1', '2', '3', '4'};
    //明文空间
    unsigned char plain[16] = "test1234";
    //解密后明文的空间
    unsigned char dec_plain[16] = {
     0};
    //密文空间
    unsigned char cipher[16] = {
     0};

    mbedtls_aes_init(&aes_ctx);
    mbedtls_aes_setkey_enc(&aes_ctx, key, 128);
    printf("要加密的数据: %s\n", plain);
    printf("加密的密码: %s\n", key);
    mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, plain, cipher);
    printf("加密结果,二进制表示: ");
    for(int loop = 0; loop < 16; loop++)
    {
     
        printf("%02x", cipher[loop]);
    }
    printf("\r\n");

    //设置解密密钥
    mbedtls_aes_setkey_dec(&aes_ctx, key, 128);
    mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_DECRYPT, cipher, dec_plain);
    printf("解密后的数据: %s\n", dec_plain);
    mbedtls_aes_free(&aes_ctx);
}

2.4 加密解密验证

在线AES-ECB加密解密:http://tool.chacuo.net/cryptaes

ESP32学习笔记(47)——加密算法AES/MD5/SHA_第2张图片
与网站加密后结果一致:
ESP32学习笔记(47)——加密算法AES/MD5/SHA_第3张图片

三、AES - CBC

3.1 简介

AES(Advanced Encryption Standard,高级加密标准) 又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。

CBC(Cipher Block Chaining,加密块链) 模式。

优点:

  • 不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。

缺点:

  • 不利于并行计算;
  • 误差传递;
  • 需要初始化向量IV;

3.2 API说明

API 文档查看 mbed TLS源码文档

3.2.1 mbedtls_aes_init

功能 初始化指定的 AES 上下文。它必须是在使用上下文之前调用的第一个 API。
函数定义 void mbedtls_aes_init(mbedtls_aes_context * ctx)
参数 ctx:要初始化的 AES 上下文。这一定不是NULL
返回

3.2.2 mbedtls_aes_setkey_enc

功能 设置加密密钥。
函数定义 int mbedtls_aes_setkey_enc(mbedtls_aes_context * ctx, const unsigned char * key, unsigned int keybits)
参数 ctx:密钥应绑定到的 AES 上下文。它必须被初始化。
key:加密密钥。这必须是大小keybits位的可读缓冲区。
keybits:以位为单位传递的数据大小。有效的选项是:128 位 / 192位 / 256 位
返回 0 - 成功,0x0020 - 密钥长度无效

3.2.3 mbedtls_aes_crypt_cbc

功能 执行 AES-CBC 加密或解密操作。
它对mode参数中定义的输入数据缓冲区执行参数中定义的操作(加密或解密)input
mbedtls_aes_init()以及mbedtls_aes_setkey_enc()mbedtls_aes_setkey_dec()必须在第一次使用相同上下文调用此 API 之前调用。该函数对完整块进行操作,即输入大小必须是 AES 块大小的16Bytes的倍数。
函数定义 int mbedtls_aes_crypt_cbc(mbedtls_aes_context * ctx, int mode, size_t length, unsigned char iv[16], const unsigned char * input, unsigned char * output)
参数 ctx:用于加密或解密的 AES 上下文。它必须被初始化并绑定到一个键。
mode:AES 操作:MBEDTLS_AES_ENCRYPTMBEDTLS_AES_DECRYPT
length:输入数据的长度(以字节为单位)。这必须是块大小(16字节)的倍数。
iv:初始化向量(使用后更新)。它必须是一个可读可写的16字节缓冲区。
input:保存输入数据的缓冲区。它必须是可读的并且大小为lengthBytes。
output:保存输出数据的缓冲区。它必须是可写的并且大小为lengthBytes。
返回 0 - 成功

3.2.4 mbedtls_aes_setkey_dec

功能 设置解密密钥。
函数定义 int mbedtls_aes_setkey_dec(mbedtls_aes_context * ctx, const unsigned char * key, unsigned int keybits)
参数 ctx:密钥应绑定到的 AES 上下文。它必须被初始化。
key:解密密钥。这必须是大小keybits位的可读缓冲区。
keybits:以位为单位传递的数据大小。有效的选项是:128 位 / 192位 / 256 位
返回 0 - 成功,0x0020 - 密钥长度无效

3.2.5 mbedtls_aes_free

功能 释放并清除指定的 AES 上下文。
函数定义 void mbedtls_aes_free(mbedtls_aes_context * ctx)
参数 ctx:要清除的 AES 上下文。如果是NULL,则此函数不执行任何操作。否则,上下文必须至少已初始化。
返回

3.3 实例

CBC能实现大于16字节的明文加解密,前提是需要为16的整数倍。

需要包含 mbedtls/aes.h

void app_main(void)
{
     
    printf("AES-CBC 加密-数据块(128位)\n");
    int i;
    mbedtls_aes_context aes_ctx;
    //密钥数值
    unsigned char key[16] = {
     'c', 'b', 'c', 'p', 'a', 's', 's', 'w', 'o', 'r', 'd', '1', '2', '3', '4'};
    //iv
    unsigned char iv[16];
    //明文空间
    unsigned char plain[64] = "hello_worled1234";
    //解密后明文的空间
    unsigned char dec_plain[64] = {
     0};
    //密文空间
    unsigned char cipher[64] = {
     0};

    mbedtls_aes_init(&aes_ctx);
    mbedtls_aes_setkey_enc(&aes_ctx, key, 128);
    for(i = 0; i < 16; i++)
    {
     
        iv[i] = 0x01;
    }
    printf("要加密的数据: %s\n", plain);
    printf("加密的密码: %s\n", key);
    mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, 64, iv, plain, cipher);
    printf("加密结果,二进制表示: ");
    for(int loop = 0; loop < 64; loop++)
    {
     
        printf("%02x", cipher[loop]);
    }
    printf("\r\n");

    //设置解密密钥
    mbedtls_aes_setkey_dec(&aes_ctx, key, 128);
    for(i = 0; i < 16; i++)
    {
     
        iv[i] = 0x01;
    }
    mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, 64, iv, cipher, dec_plain);
    printf("解密后的数据: %s\n", dec_plain);
    mbedtls_aes_free(&aes_ctx);
}

四、MD5

4.1 简介

MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。

应用场景:

  • 密码管理
  • 电子签名
  • 垃圾邮件筛选

4.2 API说明

API 文档查看 mbed TLS源码文档

MD5 被认为是一种弱消息摘要,它的使用构成了安全风险。我们建议考虑使用更强的消息摘要。

4.2.1 mbedtls_md5_init

功能 初始化 MD5 上下文。
函数定义 void mbedtls_md5_init(mbedtls_md5_context * ctx)
参数 ctx:要初始化的 MD5 上下文。
返回

4.2.2 mbedtls_md5_starts

功能 MD5 上下文设置。在 2.7.0 中被mbedtls_md5_starts_ret()取代
函数定义 void mbedtls_md5_starts(mbedtls_md5_context * ctx)
参数 ctx:要初始化的 MD5 上下文。
返回

4.2.3 mbedtls_md5_update

功能 MD5 进程缓冲区。在 2.7.0 中被mbedtls_md5_update_ret()取代
函数定义 void mbedtls_md5_update(mbedtls_md5_context * ctx, const unsigned char * input, size_t ilen)
参数 ctx:MD5 上下文
input:保存数据的缓冲区
ilen:输入数据的长度
返回

4.2.4 mbedtls_md5_finish

功能 MD5 最终摘要。在 2.7.0 中被mbedtls_md5_finish_ret()取代
函数定义 void mbedtls_md5_finish(mbedtls_md5_context * ctx, unsigned char output[16])
参数 ctx:MD5 上下文
output:MD5 校验和结果
返回

4.2.5 mbedtls_md5_free

功能 清除 MD5 上下文。
函数定义 void mbedtls_md5_free(mbedtls_md5_context * ctx)
参数 ctx:要清除的 MD5 上下文
返回

4.3 实例

需要包含 mbedtls/md5.h

void app_main(void)
{
     
    printf("MD5 加密\n");

    mbedtls_md5_context md5_ctx;

    unsigned char encrypt[] = "hello_worled1234";
    unsigned char decrypt[16];

    mbedtls_md5_init(&md5_ctx);
    mbedtls_md5_starts(&md5_ctx);
    mbedtls_md5_update(&md5_ctx, encrypt, strlen((char *)encrypt));
    mbedtls_md5_finish(&md5_ctx, decrypt);

    printf("MD5加密前:[%s]\n", encrypt);
    printf("MD5加密后(32位):");
    for(int i = 0; i < 16; i++)
    {
     
        printf("%02x", decrypt[i]);
    }
    printf("\r\n");

    mbedtls_md5_free(&md5_ctx);
}

4.4 加密验证

在线MD5加密:https://www.cmd5.com/

ESP32学习笔记(47)——加密算法AES/MD5/SHA_第4张图片

与网站加密后结果一致:

ESP32学习笔记(47)——加密算法AES/MD5/SHA_第5张图片

五、SHA-1

5.1 简介

SHA-1(英语:Secure Hash Algorithm 1,中文名:安全散列算法1)是一种密码散列函数,美国国家安全局设计,并由美国国家标准技术研究所(NIST)发布为联邦数据处理标准(FIPS)。SHA-1可以生成一个被称为消息摘要的160位(20字节)散列值,散列值通常的呈现形式为40个十六进制数。

SHA在很多安全协定中广为运用,包含TLS和SSL、PGP、SSH、S/MIME和IPsec,曾被视为是MD5(更早之前被广为运用的杂凑函数)的后继者。 但SHA-1的安全性现在被密码学家严峻质疑,有学者曾经爆出NSA在SHA-1留下的后门。

5.2 API说明

API 文档查看 mbed TLS源码文档

SHA-1 被认为是一种弱消息摘要,它的使用构成了安全风险。我们建议考虑使用更强的消息摘要。

5.2.1 mbedtls_sha1_init

功能 初始化 SHA-1 上下文。
函数定义 void mbedtls_sha1_init(mbedtls_sha1_context * ctx)
参数 ctx:要初始化的 SHA-1 上下文。这一定不是NULL
返回

5.2.2 mbedtls_sha1_starts

功能 启动 SHA-1 校验和计算。在 2.7.0 中被mbedtls_sha1_starts_ret()取代。
函数定义 void mbedtls_sha1_starts(mbedtls_sha1_context * ctx)
参数 ctx:要初始化的 SHA-1 上下文。这必须被初始化。
返回

5.2.3 mbedtls_sha1_update

功能 将输入缓冲区提供给正在进行的 SHA-1 校验和计算。在在 2.7.0 中被mbedtls_sha1_update_ret()取代。
函数定义 void mbedtls_sha1_update(mbedtls_sha1_context * ctx, const unsigned char * input, size_t ilen)
参数 ctx:SHA-1 上下文。这必须初始化并启动散列操作。
input:保存输入数据的缓冲区。这必须是长度为ilenBytes的可读缓冲区。
ilen:输入数据的长度(input以字节为单位)。
返回

5.2.4 mbedtls_sha1_finish

功能 完成 SHA-1 操作,并将结果写入输出缓冲区。在 2.7.0 中被mbedtls_sha1_finish_ret()取代。
函数定义 void mbedtls_sha1_finish(mbedtls_sha1_context * ctx, unsigned char output[20])
参数 ctx:SHA-1 上下文。这必须初始化并启动散列操作。
output:SHA-1 校验和结果。这必须是长度为20Bytes的可写缓冲区。
返回

5.2.5 mbedtls_sha1_free

功能 清除 SHA-1 上下文。
函数定义 void mbedtls_sha1_free(mbedtls_sha1_context * ctx)
参数 ctx:要清除的 SHA-1 上下文。这可能是NULL,在这种情况下这个函数什么都不做。如果不是NULL,它必须指向一个初始化的 SHA-1 上下文。
返回

5.3 实例

需要包含 mbedtls/sha1.h

void app_main(void)
{
     
    printf("SHA-1 加密\n");

    mbedtls_sha1_context sha1_ctx;;

    const unsigned char encrypt[] = "hello_worled1234";
    unsigned char decrypt[32];

    mbedtls_sha1_init(&sha1_ctx);
    mbedtls_sha1_starts(&sha1_ctx);
    mbedtls_sha1_update(&sha1_ctx, encrypt, strlen((char *)encrypt));
    mbedtls_sha1_finish(&sha1_ctx, decrypt);

    printf("SHA1加密前:[%s]\n", encrypt);
    printf("SHA1加密后(40位):");
    for(int i = 0; i < 20; i++)
    {
     
        printf("%02x", decrypt[i]);
    }
    printf("\r\n");

    mbedtls_sha1_free(&sha1_ctx);
}

5.4 加密验证

在线SHA1加密:http://www.ttmd5.com/hash.php?type=5

ESP32学习笔记(47)——加密算法AES/MD5/SHA_第6张图片

与网站加密后结果一致:

ESP32学习笔记(47)——加密算法AES/MD5/SHA_第7张图片

六、SHA-256

6.1 简介

SHA256 是SHA-2下细分出的一种算法。SHA-2,名称来自于安全散列算法2(英语:Secure Hash Algorithm 2)的缩写,一种密码散列函数算法标准,由美国国家安全局研发,属于SHA算法之一,是SHA-1的后继者。虽然至今尚未出现对SHA-2有效的攻击,但是它的算法跟SHA-1基本上仍然相似,因此有些人开始发展其他替代的杂凑算法。

SHA-2下又可再分为六个不同的算法标准,包括了:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。这些变体除了生成摘要的长度 、循环运行的次数等一些微小差异外,算法的基本结构是一致的。

6.2 API说明

API 文档查看 mbed TLS源码文档

6.2.1 mbedtls_sha256_init

功能 初始化 SHA-256 上下文。
函数定义 void mbedtls_sha256_init(mbedtls_sha256_context * ctx)
参数 ctx:要初始化的 SHA-256 上下文。这一定不是NULL
返回

6.2.2 mbedtls_sha256_starts

功能 启动 SHA-224 或 SHA-256 校验和计算。在 2.7.0 中被mbedtls_sha256_starts_ret()取代。
函数定义 void mbedtls_sha256_starts(mbedtls_sha256_context * ctx, int is224)
参数 ctx:要使用的上下文。这必须被初始化。
is224:确定要使用的函数。这必须0适用于 SHA-256 或1SHA-224。
返回

6.2.3 mbedtls_sha256_update

功能 将输入缓冲区提供给正在进行的 SHA-256 校验和计算。在 2.7.0 中被mbedtls_sha256_update_ret()取代。
函数定义 void mbedtls_sha256_update(mbedtls_sha256_context * ctx, const unsigned char * input, size_t ilen)
参数 ctx:SHA-1 上下文。这必须初始化并启动散列操作。
input:保存数据的缓冲区。这必须是长度为ilenBytes的可读缓冲区。
ilen:输入数据的长度(以字节为单位)。
返回

6.2.4 mbedtls_sha256_finish

功能 完成 SHA-256 操作,并将结果写入输出缓冲区。在 2.7.0 中被mbedtls_sha256_finish_ret()取代。
函数定义 void mbedtls_sha256_finish(mbedtls_sha256_context * ctx, unsigned char output[32])
参数 ctx:SHA-256 上下文。这必须初始化并启动散列操作。
output:SHA-224 或 SHA-256 校验和结果。这必须是长度为32Bytes的可写缓冲区。
返回

6.2.5 mbedtls_sha256_free

功能 清除 SHA-256 上下文。
函数定义 void mbedtls_sha256_free(mbedtls_sha256_context * ctx)
参数 ctx:要清除的 SHA-256 上下文。这可能是NULL,在这种情况下这个函数什么都不做。如果不是NULL,它必须指向一个初始化的 SHA-256 上下文。
返回

6.3 实例

需要包含 mbedtls/sha256.h

void app_main(void)
{
     
    printf("SHA-256 加密\n");

    mbedtls_sha256_context sha256_ctx;;

    const unsigned char encrypt[] = "hello_worled1234";
    unsigned char decrypt[32];

    mbedtls_sha256_init(&sha256_ctx);
    mbedtls_sha256_starts(&sha256_ctx, 0); // 0表示传sha256 , 1 表示传SHA-244
    mbedtls_sha256_update(&sha256_ctx, encrypt, strlen((char *)encrypt));
    mbedtls_sha256_finish(&sha256_ctx, decrypt);

    printf("SHA256加密前:[%s]\n", encrypt);
    printf("SHA256加密后:");
    for(int i = 0; i < 32; i++)
    {
     
        printf("%02x", decrypt[i]);
    }
    printf("\r\n");

    mbedtls_sha256_free(&sha256_ctx);
}

6.4 加密验证

在线SHA256加密:http://www.ttmd5.com/hash.php?type=5

ESP32学习笔记(47)——加密算法AES/MD5/SHA_第8张图片

与网站加密后结果一致:

ESP32学习笔记(47)——加密算法AES/MD5/SHA_第9张图片


• 由 Leung 写于 2021 年 10 月 27 日

• 参考:乐鑫Esp32学习之旅 22 讨论下程序员 “青春饭” 那些事,分享在esp32实现多种加密算法md5 |AES CBC-ECB| Sha1 | Sha256 等,附带Demo

你可能感兴趣的:(ESP32,aes,ESP32,md5,sha,mbedtls)