ESP32学习笔记(47)——加密算法AES/MD5/SHA
Posted Leung_ManWah
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ESP32学习笔记(47)——加密算法AES/MD5/SHA相关的知识,希望对你有一定的参考价值。
一、简介
1.1 SSL
SSL:(Secure Socket Layer,安全套接字层),位于可靠的面向连接的网络层协议和应用层协议之间的一种协议层。SSL通过互相认证、使用数字签名确保完整性、使用加密确保私密性,以实现客户端和服务器之间的安全通讯。该协议由两层组成:SSL记录协议和SSL握手协议。
1.2 TLS
TLS:(Transport Layer Security,传输层安全协议),用于两个应用程序之间提供保密性和数据完整性。该协议由两层组成:TLS记录协议和TLS握手协议。
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_ENCRYPT 或MBEDTLS_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 <stdio.h>
#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
与网站加密后结果一致:
三、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 块大小的16 Bytes的倍数。 |
---|---|
函数定义 | 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_ENCRYPT 或MBEDTLS_AES_DECRYPT 。length:输入数据的长度(以字节为单位)。这必须是块大小( 16 字节)的倍数。iv:初始化向量(使用后更新)。它必须是一个可读可写的 16 字节缓冲区。input:保存输入数据的缓冲区。它必须是可读的并且大小为 length Bytes。output:保存输出数据的缓冲区。它必须是可写的并且大小为 length Bytes。 |
返回 | 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/
与网站加密后结果一致:
五、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:保存输入数据的缓冲区。这必须是长度为 ilen Bytes的可读缓冲区。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 校验和结果。这必须是长度为 20 Bytes的可写缓冲区。 |
返回 | 无 |
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
与网站加密后结果一致:
六、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 或1 SHA-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:保存数据的缓冲区。这必须是长度为 ilen Bytes的可读缓冲区。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 校验和结果。这必须是长度为 32 Bytes的可写缓冲区。 |
返回 | 无 |
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
与网站加密后结果一致:
• 由 Leung 写于 2021 年 10 月 27 日
• 参考:乐鑫Esp32学习之旅 22 讨论下程序员 “青春饭” 那些事,分享在esp32实现多种加密算法md5 |AES CBC-ECB| Sha1 | Sha256 等,附带Demo
以上是关于ESP32学习笔记(47)——加密算法AES/MD5/SHA的主要内容,如果未能解决你的问题,请参考以下文章
密码学应用(DES,AES, MD5, SHA1, RSA, Salt, Pkcs8)
ESP32学习笔记 - 基于 ESP32 移植 LVGL8.3
基于arduino的ESP32 学习笔记 基于ESP32的智能花盆