当前位置: 首页 > news >正文

STM32Cube系列教程11:STM32 AES加解密模块性能测试

文章目录

  • 本次测试环境
    • 本次测试所使用的系统时钟为48MHz
    • 本次测试主要测试对大量数据进行加解密所需的时间,本次为不严谨测试,忽略了程序调用耗时,结果仅供参考。
  • AES算法与数据加解密
    • 加密与解密
    • 对称加解密
    • AES算法
      • AES-ECB
      • AES-CBC
    • 填充算法
      • PKCS7Padding
  • 配置硬件AES模块初始化
  • 编写测试代码
    • 编写填充与解填充代码
    • 编写大小端转换代码
    • 编写aes模块密钥与模式配置代码
    • 封装加解密接口
    • 编写ecb测试代码
    • 编写cbc测试代码
    • 创建密钥与待加密的数据
  • 调用测试接口对aes模块进行测试
    • 测试结果

今天使用NUCLEO-U083RC的评估板,测试一下他内置的AES加速模块性能如何。

全部代码以上传到github:https://github.com/what-sudo/stm32U083


正文开始,本工程基于前期配置的工程模板,感兴趣的可查看之前的文章。
《STM32Cube系列教程10:STM32CubeIDE工程创建+串口DMA+IDLE+printf重定向+软中断处理串口数据+非阻塞延时任务》

本次测试环境

本次测试所使用的系统时钟为48MHz

本次测试主要测试对大量数据进行加解密所需的时间,本次为不严谨测试,忽略了程序调用耗时,结果仅供参考。

AES算法与数据加解密

在使用aes模块之前,这里先简单说一下什么是加解密以及aes算法的特性
以下内容摘录自我的另一篇文章,其中简单讲述了对称加密算法,非对称加密算法,数据散列算法等内容,感兴趣的请移步观看。
《数据安全-签名、加密、与填充》

加密与解密

加密:将明文(原始数据)和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文。
解密:使用密钥及对应的解密算法对密文进行解密,使其恢复成可读明文。

加解密通常需要使明文数据按照一定长度对齐,叫做块大小(BlockSize),例如AES加解密的BlockSize为16字节,RSA加解密的BlockSize等于密钥长度。

如果数据长度无法对齐到要求的长度,就需要使用填充算法,加密前与解密后需要使用相同的填充算法对数据进行填充或解填充。

加密与解密一般需要对数据进行分包,将明文数据分包处理后,使用加密算法对每包数据进行运算,求出密文数据,每包密文数据的长度通常都是等长的,将每包密文依次连接,形成完整的密文数据。

解密时,按照加解密算法对应的包长度,依次将每包密文进行解密运算,拼凑出明文数据。

对称加解密

加密密钥与解密密钥相同的加密算法。
特点:

  1. 算法公开
  2. 计算量小
  3. 速度快,效率高
  4. 密钥传输与密钥管理麻烦

通常用于对大量数据进行加密,
常用的加密算法:AES、DES。

AES算法

AES算法安全性与密钥长度关联,密钥长度越长,越安全。
AES密钥分为AES128、AES192、AES256。
明文需要被分为固定长度的块进行加密,BlockSize为16字节。
数据如果被损坏,解密能正常运算,但会得到错误的明文。
AES算法通常分为ECB与CBC模式,我们通常使用的时CBC模式。

AES-ECB

  • ECB模式是最简单的AES加密模式
  • 使用一个固定长度的密钥
  • 固定的明文将会生成固定的密文,如果有两个相同的明文块,则加密结果也相同。

优点
简单,有利于并行计算,误差不会传递。

缺点
安全性低,容易被爆破

加密流程
在这里插入图片描述
解密流程
在这里插入图片描述

AES-CBC

  • 加解密需要使用一个固定长度的密钥
  • 加解密需要一个16字节的初始向量
  • 相同的明文不会生成相同的密文

优点

安全性比ECB好

缺点

不利于并行计算,误差会被传递,需要保存初始向量IV

加密流程
在这里插入图片描述
解密流程
在这里插入图片描述

填充算法

AES加解密算法仅支持按照block大小进行加解密,如果需要加密的数据无法被block大小整除,则无法加密,因此这里需要对原始数据进行填充,aes加密算法使用的填充方法为PKCS7Padding算法,这也是openssl库中,对aes加解密时默认使用的填充算法,我们需要保证我们加密出的数据能够与openssl互通,因此需要以openssl为标准,(openssl是一个开源的软件库,程序可以使用这个库进行安全通信,数据加解密等操作,详情请自行百度)。
在进行加密操作之前。需要对原始数据进行填充,在密文解密为明文后,需要按照填充规则,对解密数据进行解填充,才能获取到真实的原始数据。

内容摘录自我的另一篇文章,其中简单讲述了对称加密算法,非对称加密算法,数据散列算法等内容,感兴趣的请移步观看。
《数据安全-签名、加密、与填充》

PKCS7Padding

PKCS7是16字节填充的,即填充一定数量的内容,使得成为16的整数倍,而填充的内容取决于需要填充的数目。
例如:

// 原数组
{0x56}
//PKCS7填充结果
{0x56, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f}// 原数组
{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
//PKCS7填充结果
{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}// 原数组
{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
//PKCS7填充结果
{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
}

如果已经满足了16的整倍数,按照PKCS7的规则,仍然需要在尾部填充16个字节,并且内容是0x10,目的是为了加解密时统一处理填充。
因此进行pkcs7填充后的数据,最多会比原始数据长16个字节
原理讲到这里,下面我们写代码测试一下。

配置硬件AES模块初始化

打开我们的工程模板,在CubeMX配置中,打开Security --> AES配置,勾选Activated功能,注意Data type设置是否为默认值32b,Data width unit与Header width unit需要保持为word类型,其他配置保持默认即可,我这里曾改为CBC模式,系统默认应该时ECB模式,这里无影响,后面我会在代码中重新配置加解密模式与密钥key。保存并生成代码。

在这里插入图片描述

编写测试代码

这里我们主要使用ECB与CBC两种模式,进行多轮加解密,通过计算加解密的时间,来衡量aes模块的性能。

编写填充与解填充代码

通过这两个函数,在加密前与解密后,对数据进行填充与解填充。

/*** @brief  pkcs7填充算法* @param  p: 需要填充的数据指针* @param  len: 需要填充的数据长度* @param  block_size: 按照多大的block进行填充,通常为16* @return 填充后的数据长度* @author joseph* @date   2024.5.27*/
static size_t pkcs7Padding(unsigned char *p, size_t len, uint8_t block_size)
{uint8_t i = 0;uint8_t padding = 0;padding = block_size - len%block_size;for (i = 0; i < padding; i++) {p[len + i] = padding;}return (len + padding);
}/*** @brief  pkcs7解填充算法* @param  p: 需要解填充的数据指针* @param  len: 需要解填充的数据长度* @param  block_size: 按照多大的block进行填充,通常为16* @return 解填充后的数据长度* @author joseph* @date   2024.5.27*/
static size_t pkcs7UnPadding(unsigned char *p, size_t len, uint8_t block_size)
{uint8_t unPadding  = 0;unPadding  = p[len - 1];int i = 0;if (unPadding > 16) {return -1;}for (i = 0; i < unPadding; i++) {if (p[len - 1 - i] != unPadding)return -1;}return (len - unPadding);
}

编写大小端转换代码

STM32中数据的保存方式为小端模式,但是在openssl中,默认使用的是大端模式,为了保证在使用相同的输入时,能够获取到相同的输出,因此需要进行大小端转换。

#define BLSWAP32(val) \((val) = ((uint32_t)((((uint32_t)(val) & (uint32_t)0x000000ffU) << 24) | \(((uint32_t)(val) & (uint32_t)0x0000ff00U) <<  8) | \(((uint32_t)(val) & (uint32_t)0x00ff0000U) >>  8) | \(((uint32_t)(val) & (uint32_t)0xff000000U) >> 24))))

编写aes模块密钥与模式配置代码

通过这个函数对aes模块进行密钥与算法模式进行配置

typedef enum {AES_ALGO_ECB,AES_ALGO_CBC,
} AES_Algorithm_t;/*** @brief  aes模块密钥与模式配置代码* @param  key: aes密钥指针* @param  key_len: aes密钥长度* @param  mode: aes算法模式,ECB/CBC* @param  iv: 初始向量指针,如果为ECB时,入参NULL即可* @return 0:SUCCESS, <0: fail* @author joseph* @date   2024.5.27*/
int aes_set_config(uint8_t *key, int key_len, AES_Algorithm_t mode, uint8_t *iv)
{int ret = -1;CRYP_ConfigTypeDef cryp_conf = {0};do {if (key_len != 32 || key == NULL) {printf("error: The key length only supports 32\n");break;}if (mode == CRYP_AES_CBC && iv == NULL) {printf("error: iv param is null\n");break;}for (int i = 0; i < key_len >> 2; i ++)BLSWAP32(((uint32_t*)key)[i]);if (HAL_CRYP_GetConfig(&hcryp, &cryp_conf) != HAL_OK) {printf("error: HAL_CRYP_GetConfig fail\n");break;}cryp_conf.Algorithm = (mode == AES_ALGO_ECB) ? CRYP_AES_ECB : CRYP_AES_CBC;cryp_conf.pKey = (uint32_t *)key;if (mode == AES_ALGO_CBC) {for (int i = 0; i < 4; i ++)BLSWAP32(((uint32_t*)iv)[i]);cryp_conf.pInitVect = (uint32_t *)iv;}if (HAL_CRYP_SetConfig(&hcryp, &cryp_conf) != HAL_OK) {printf("error: HAL_CRYP_SetConfig fail\n");break;}ret = 0;} while (0);return ret;
}

封装加解密接口

通过封装的这个接口,完成对数据的加密与解密
##### 注意:代码中的CRYPT_NUM_TIMES 时我进行多轮测试时使用的,正常进行加解密时,应该删除与CRYPT_NUM_TIMES有关的代码,或将CRYPT_NUM_TIMES设置为1。#####


typedef enum {AES_ENCRYPTO_MODE,AES_DECRYPTO_MODE,
} AES_Crypt_Mode_t;#define CRYPT_NUM_TIMES 1   // 设置加解密测试轮数/*** @brief  aes加解密接口* @param  mode: aes加解密模式,EN/DE* @param  in_buffer: 等待加解密的数据指针* @param  inlen: 输入的数据长度* @param  out_buffer: 保存加解密后数据的内存指针* @return 0:输出的数据长度, <0: fail* @author joseph* @date   2024.5.27*/
int aes_crypt(AES_Crypt_Mode_t mode, unsigned char *in_buffer, int inlen, unsigned char *out_buffer)
{int ret = -1;int plain_len = 0;memmove(tmp_buffer, in_buffer, inlen);do{start = HAL_GetTick();for (i = 0; i < CRYPT_NUM_TIMES; i++){memmove(in_buffer, tmp_buffer, inlen);if (mode == AES_ENCRYPTO_MODE) {plain_len = pkcs7Padding((uint8_t *)in_buffer, inlen, AES_BLOCK_SIZE);for (int i = 0; i < plain_len >> 2; i++)BLSWAP32(((uint32_t *)in_buffer)[i]);if (HAL_CRYP_Encrypt(&hcryp, (uint32_t *)in_buffer, plain_len >> 2, (uint32_t *)out_buffer, 0xff) != HAL_OK){printf("error: HAL_CRYP_Encrypt fail\n");break;}for (int i = 0; i < plain_len >> 2; i++)BLSWAP32(((uint32_t *)out_buffer)[i]);} else {for (int i = 0; i < inlen >> 2; i++)BLSWAP32(((uint32_t *)in_buffer)[i]);if (HAL_CRYP_Decrypt(&hcryp, (uint32_t *)in_buffer, inlen >> 2, (uint32_t *)out_buffer, 0xff) != HAL_OK){printf("error: HAL_CRYP_Decrypt fail\n");break;}for (int i = 0; i < inlen >> 2; i++)BLSWAP32(((uint32_t *)out_buffer)[i]);plain_len = pkcs7UnPadding((uint8_t*)out_buffer, inlen, AES_BLOCK_SIZE);}}end = HAL_GetTick();if (i != CRYPT_NUM_TIMES) {printf("[%d] error: CRYPT_NUM_TIMES i:%d fail\n", __LINE__, i);break;}interval = end - start;printf("%s %d times: %ld\n", mode == 0 ? "encrypto" : "decrypto", CRYPT_NUM_TIMES, interval);ret = plain_len;} while (0);return ret;
}

编写ecb测试代码


int aes_ecb_test(void)
{int ret = -1;int text_len = strlen(Text);int length = 0;do {memmove(AES_key, AES_key1, 32);aes_set_config(AES_key, 32, AES_ALGO_ECB, NULL);printf("==== aes_ecb_test 1 ==== \n");memset(plain, 0, sizeof(plain));memmove(plain, Text, text_len);length = aes_crypt(AES_ENCRYPTO_MODE, plain, text_len, cipher);if (length < 0) {printf("[%d] error: aes_crypt fail\n", __LINE__);break;}printf("encrypto len: %d\n", length);// show_hex(cipher, 64);memset(plain, 0, sizeof(plain));length = aes_crypt(AES_DECRYPTO_MODE, cipher, length, plain);if (length < 0) {printf("[%d] error: aes_crypt fail\n", __LINE__);break;}printf("decrypto len: %d\n", length);// printf("%.*s\n", 64, plain);if (text_len == length && memcmp(plain, Text, length) == 0) {printf("\naes_ecb_test success\n");} else {printf("\naes_ecb_test fail\n");}ret = 0;} while (0);return ret;
}

编写cbc测试代码


int aes_cbc_test(void)
{int ret = -1;int text_len = strlen(Text);uint16_t length = 0;do {memmove(AES_key, AES_key1, 32);memmove(aesiv, aesiv1, 16);aes_set_config(AES_key, 32, AES_ALGO_CBC, aesiv);printf("==== aes_cbc_test 1 ==== \n");memset(plain, 0, sizeof(plain));memmove(plain, Text, text_len);length = aes_crypt(AES_ENCRYPTO_MODE, plain, text_len, cipher);if (length < 0) {printf("[%d] error: aes_crypt fail\n", __LINE__);break;}printf("encrypto len: %d\n", length);// show_hex(cipher, 64);memset(plain, 0, sizeof(plain));length = aes_crypt(AES_DECRYPTO_MODE, cipher, length, plain);if (length < 0) {printf("[%d] error: aes_crypt fail\n", __LINE__);break;}printf("decrypto len: %d\n", length);// printf("%.*s\n", 64, plain);if (text_len == length && memcmp(plain, Text, length) == 0) {printf("\naes_cbc_test success\n");} else {printf("\naes_cbc_test fail\n");}ret = 0;} while (0);return ret;
}

创建密钥与待加密的数据

以下这些变量是在程序执行过程中需要使用的数据,其中明文数据约3.5k字符,用于测试加解密性能。


// 加解密的key
uint8_t AES_key1[33] = "12345678901234561234567890123456";
// cbc模式下需要使用的初始向量iv
uint8_t aesiv1[17] = "1234567890123456";// 多轮加密时,需要传入的密钥内存
uint8_t AES_key[32] = {0};
uint8_t aesiv[16] = {0};// 待加密的原始数据,约3.5K字符。
char Text1[] = " \
-----BEGIN PRIVATE KEY-----                                      \
MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQCsXDZ8s9ToFi+t \
+HE9KfJSPOYjGR/OxnAUNPxKWoQ6l5nCS9Uhazdl9hF6PDjy0mGE6ZFdW7c+Tsmg \
uTIMVY0BlOT6hRwfxoSLqjF6L99Nb906cOX5eGxEbOE0k9OFkKZw3KGiPpm007TN \
3IBwYRLoVLwnXHFfcsJ4w52GfwOyFAlc99Nv45/o4lzj3yYdBWBey1bLotoTcK1u \
J97iv6DFTb28GN/XR3qbSHNFJsxKtwoj8Rwj3aAq/4cVpH7uhkOOLjCclBdsWTlb \
fmuZJ4ISfHnMDtZjIEH3LAb8ILoGnytcqTd9nb4d0gYsKFsqAjrK4akDq85ZQQx7 \
At4jzY5+C0lwM89WxP0/saph6lsgdhjjS9P8I7dwJyFTaLfiaKIOYf31w9mHrpnS \
yIRGg+Enw+osow6cQ49m6klCnvs46bJ9ZaSg1wqKkrp8VSvBs1tto749NS5YcTKT \
+oQwpqHWpbrEr78oTCYRrf/8ggk0LHP/PRj6GNJYMX62BafInz6RnwWUb6n+BoF8 \
ioXZ17aa0mBAx+REfjwxk1S+5EblhU1a92V5x1YwVUTfnN19FVmXJpv/o3nx6cwk \
c8j0xMRMNPHVJIOGNcgYmlzpRGMC6DYP69Cj64k9uLmESVCRuyQzJjZbANqDNvFa \
0cjpbKkRDOtzxzjjivawPc6okW7W7QIDAQABAoICAADp3aKjI/D1ikmVRE4Y5nYc \
aPL/Y3MgnbJ1uJO+4cmI23PYHAzdgkFx4KaNInK1UFJKzunJ+bpyUJmx+ruSboJA \
bEcggDMEWCFb8n+dgcT78d8pEVAeiqKl7DrLChKcFeAJsQsNUJo+Zd624mes73gT \
oS7P8Gfkdi2Niif8jRGtfMuAtQyKjhmiiO/u0zT2Bx6pgNANWdgerSAS10+n7Vtu \
W2kEBrxETDhrej4SOsllKa3PhI6X0nrcbyQSS+mllvWlLJl/2yej7kgcE8hY9J3k \
UtynFp9gl5szIS6iNOo0f5+NUcQwLX1tZp5ClVrUAKAzFdkHoii18lZYSVT79kkD \
yN66XwwrIRUeZkRAy+gI2IxtsA1T0rexN/bRV/ZRLyW5GVlMnd4z7h8OGj+WcMjh \
PCniGxu03wp2rulRSYPs0/krZ3+mKYNtzkv/2fKJZKlqA8qvsFKWxcODMHtFoglf \
ea6rHoCRckRzIB30I8ro7b+XXZN3B9hgHQuXtwEUq6jnnF9l9x+eEQC/qf2wtxAK \
EO3Dd/fRUbbPEr8gvRBNdbEEQRxMCaKBGHmqu+5RELhsnrgGKmHnbricxouVIS54 \
1MS1DakaqZRJkz//5IYR6lP08kDGqWIbCo5B9vlrJtg3iwHf86W8anBHMZC1PtcC \
lh1anrVvt3V4pr2T3xrPAoIBAQDqyOGddJL7Rx5Wd2RuIXA+8WmIFqBzwsRyS9oN \
Ns1IP9etANzt5Tmhs5yxb7RsI5olwOVtdgVpieUPRkUgrmt1bkSxRPKtZ7k753aV \
rgqNaaOrZGEYwW7jC5xPmQAkqJthhIgTWjJh7N5Sby5nvLsSD4dhp6AfGBN6kEzs \
KH9IlDdO+fuCPgCBGEZnkKIuOM/NFRO/VEJpGRuaGqPMZhbmDKkilP3yfSezqDuT \
3Put+0XsfPzucozDfe/07O99Fwi/zQyI5Wz5ZSICnmkXH7HDbb4jH/VP8rO6HhCf \
z48Hlk3xAY9aD13PSmaJauqwpu2RPsvkse1ZdhZDKeyfiKF7AoIBAQC7706o1us+ \
p+RbY5JqruO5b3+yb0c/sGHX77c/qSFWQ1QOy9iVtmzWR9+yajzUqa5zwIm1awit \
/PFlw444ClESAV4Qy47TwwU4SIGBn2+5g0bQI2/x/TYG+EYxKUiIlvGcZlnrz6/H \
z60y0usTzNTNDKVcjnt7lBEM2XcEGwxNbwWfRzwHGGLFOurJmuKZF1JE9js3nLHN \
QbwPI1JGAnfMKTvLWa9CV3Mq6xhTazoTe1S2ubnG/wa9getgrziiqKlPshmmjzCi \
YK8YiFRF72E+mY/bl5DSiN2X/ltuepGjTe0iZ9Bd64puhmI1Nyoy1vEAME5Fw7je \
CTpaFgKCKbi3AoIBACLpResU13o3xAIVdMCPhlJFsWyD+M3dyzo3ny/R00qH+7kE \
5NUW/a/WtlkIBCsETDqK6VKSdxGPaJkR2NuYM/BdOiel2fQA9WE79L0jCPyoFac5 \
oNp+gM+P/Wk0lfndfGVOwLEn+0/mWdSmJZ9VR/fSiU3zD/MvsE3MQTPofay8JVFA \
CK8AKzEG/AkQT51R40xacvpDPDDGg/0xMuQE1ijU/x1eTDiPdaTYQiulc2MWdvpI \
R4/pRpcXFeQ0ixPtpeZnRhLhEogvCpSbG4NNujAWFGzCpsaBj0oAiHZK9biqF+Lb \
WYaJvGhDZuXOGSG1YKP1U3opHuLrlTnddQrv1RsCggEAKsU8rpoy8ZB+HPpdQSBK \
PVKNykse+PSoX99zYe6Y4qvx/mgQA4p/3IiA9XbOH0v6oudHr90LHaW6PoGx5Tkb \
2DAtez8IY1M35eZCawChCaRBwm6+NGF/ITjxqJCPrF5F4GU+w7cBd0ThUvbDfz8X \
kw70t0rJ+YbqFnWLa4jIVPsWWXh5xdeb6u0MsBMqzNKM65rqQS7NHDyAkyVjvQEk \
yHb937qqczu5vyO/5oQ5tGNWFTvRduNlYk2mBtv51LLzzWpoAgsGc33ze27TVxMy \
m2+RWNV2pSN24veFUXBdor/CXxknR6iqWZsF0LycQvO952AXADOZ6BZLjGMD8SGT \
owKCAQBSY8O/L6/vtICdfyX24S1FTxrQdQVCk03a3LcRnO9Loaxuvawy6lcjicDE \
YAP51EYhOKW9akxBRSEB2soRs92rnuBS522re6k/c8GUc+k3tkj5Go8v8Dqg+biW \
D5Zu2x0rXJ/caO6u0le6UrI+IOScuIPJ6tuu9OhV9sr5zJzAfIUupRpckD6TP7/X \
T6fG4lNteg8ftRfRvYd6g/jEmh/ECHvc5YDdXihDGv028BFj5fWY/iZEjMGektRf \
tPyMMOI4+t93oni0Go8OkF2FIYsquWMEh4IILMm27mVZk7A+FLW+hK/FXec3dogO \
7IbiS/98RTtjVN4NIQJ9Jc8hUhkW                                     \
-----END PRIVATE KEY-----                                        \
";char *Text = Text1;// 加解密过程中,需要的内存
uint8_t plain[4096 + 16] = {0};
uint8_t cipher[4096 + 16] = {0};
uint8_t tmp_buffer[4096 + 16] = {0};// 计算加解密时间所需要的变量
int i = 0;
uint32_t start, end, interval;

调用测试接口对aes模块进行测试

到这里,测试需要的代码已经全部编写完成,只需要在while循环之前调用对应的测试接口,就可以完成对aes模块的性能测试

** 注意: 需要修改上文曾提到的宏CRYPT_NUM_TIMES,通过修改这个宏的值,来设置加密的轮数。这里我已经将其设置为1000

// 分别测试ecb与cbc加密aes_ecb_test();aes_cbc_test();while (1){// *****************

测试结果

编译代码,查看是否有编译报错,编译成功后,将代码烧录到单片机,通过串口调试工具,可查看到结果。
数据显示:

加密模式单次计算字节计算轮数总计算字节所用时间(ms)每KB耗时(ms)
ECB加密339210003312.5KB60611.83
ECB解密338110003301.8KB60391.83
CBC加密339210003312.5KB60631.83
CBC解密338110003301.8KB60411.83

在这里插入图片描述
以上就是本次测试的所有内容,结果仅供参考。

相关文章:

STM32Cube系列教程11:STM32 AES加解密模块性能测试

文章目录 本次测试环境本次测试所使用的系统时钟为48MHz本次测试主要测试对大量数据进行加解密所需的时间&#xff0c;本次为不严谨测试&#xff0c;忽略了程序调用耗时&#xff0c;结果仅供参考。 AES算法与数据加解密加密与解密对称加解密AES算法AES-ECBAES-CBC 填充算法PKCS…...

Vue2基础:.sync修饰符的使用,认识,作用,本质案例演示,实现父子之间的通信。

.sync的作用&#xff1a; 可以实现子组件与父组件数据的双向绑定&#xff0c;简化代码。 与v-model的不同点,prop属性名可以自定义&#xff0c;不要一定要用value. .sync的本质&#xff1a; 就是&#xff1a;属性名和update&#xff1a;属性名合写。 下面我们进行代码演示…...

【数据结构与算法】使用单链表实现队列:原理、步骤与应用

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法》 期待您的关注 ​ 目录 一、引言 &#x1f384;队列的概念 &#x1f384;为什么要用单链表实现队列 二、单…...

DHCP服务

文章目录 一、DHCP介绍二、DHCP应用场景三、DHCP工作原理3.1&#xff09;工作方式3.2&#xff09;工作原理解析3.3)计算机获得IP的时间点3.4&#xff09;租约更新阶段 四、DHCP服务器部署4.1&#xff09;DHCP安装4.2&#xff09;DHCP配置文件详解4.3&#xff09;DHCP启动 五、D…...

C++笔试-剑指offer

剑指offer 文章目录 剑指offer数组[数组中重复的数据 ](https://leetcode.cn/problems/find-all-duplicates-in-an-array/description/)将元素交换到对应的位置 二维数组中的查找二叉搜索树 旋转数组的最小数字二分查找 数组中出现次数超过一半的数字相互抵消 连续子数组的最大…...

Mac安装jadx并配置环境

jadx官网&#xff1a;GitHub - skylot/jadx: Dex to Java decompiler 第一种&#xff1a; 安装jadx命令&#xff1a; brew install jadx 启动jadx-gui命令&#xff1a; jadx-gui 可能遇到的问题&#xff1a; Downloading https://formulae.brew.sh/api/formula.jws.json** h…...

前端学习----css基础语法

CSS概述 CAscading Style Sheets(级联样式表) CSS是一种样式语言,用于对HTML文档控制外观,自定义布局等,例如字体,颜色,边距等 可将页面的内容与表现形式分离,页面内容存放在HTML文档中,而用于定义表现形式的CSS在一个.css文件中或HTML文档的某一部分 HTML与CSS的关系 HTM…...

超详解——python条件和循环——小白篇

目录 1. 缩进和悬挂else 2. 条件表达式 3. 和循环搭配的else 4. 可调用对象 总结&#xff1a; 1. 缩进和悬挂else 在Python中&#xff0c;代码块是通过缩进来表示的。条件判断和循环结构的代码块需要正确缩进。悬挂else指的是else子句和相应的if或循环在同一级别的缩进。 …...

DNS协议 | NAT技术 | 代理服务器

目录 一、DNS协议 1、DNS背景 2、DNS协议 域名 域名解析 二、NAT技术 1、NAT技术 2、NAPT技术 3、NAT技术的缺陷 三、代理服务器 1、正向代理服务器 2、反向代理服务器 一、DNS协议 域名系统&#xff08;Domain Name System&#xff0c;缩写&#xff1a;DNS&#…...

深入ES6:解锁 JavaScript 类与继承的高级玩法

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;JavaScript 精粹 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; ES5、ES6介绍 文章目录 &#x1f4af;Class&#x1f35f;1 类的由来&#x1f35f;2 co…...

领域驱动设计:异常处理

一、异常的处理 异常处理是领域模型要考虑的一部分&#xff0c;原因在于模型的责任不可能无限大。在遇到自己处理能力之外的情况时&#xff0c;要采用异常机制报告错误&#xff0c;并将处理权转交。异常就是这样一种机制&#xff0c;某种程度上&#xff0c;它可以保证领域模型…...

网络网络层之(6)ICMPv6协议

网络网络层之(6)ICMPv6协议 Author: Once Day Date: 2024年6月2日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: 通信网络技术_Once-Day的博客-CS…...

《大道平渊》· 拾壹 —— 商业一定是个故事:讲好故事,员工奋发,顾客买单。

《大道平渊》 拾壹 "大家都在喝&#xff0c;你喝不喝&#xff1f;" 商业一定是个故事&#xff0c;人民群众需要故事。 比如可口可乐的各种故事。 可口可乐公司也只是被营销大师们&#xff0c; 作为一种故事载体&#xff0c;发挥他们的本领。 营销大师们开发故事…...

JavaScript 如何访问本地文件夹

在浏览器环境中的JavaScript&#xff08;通常指的是前端JavaScript&#xff09;由于安全限制&#xff0c;无法直接访问用户的本地文件或文件夹。这是为了防止恶意脚本访问并窃取用户的敏感数据。 但是&#xff0c;有几种方法可以间接地让用户选择并访问本地文件&#xff1a; 使…...

ArrayList顺序表简单实现

一、创建MyArrayList框架 1.1 MyArrayList 类中实现 arr 数组 import java.util.Arrays;public class MyArrayList {private int[] arr;private int usesize;private static final int P 10;public MyArrayList() {arr new int[P];} 在 MyArrayList 类内创建 arr 数组&…...

144、二叉树的前序递归遍历

题解&#xff1a; 递归书写三要素&#xff1a; 1&#xff09;确定递归函数的参数和返回值。要确定每次递归所要用到的参数以及需要返回的值 2&#xff09;确定终止条件。操作系统也是用栈的方式实现递归&#xff0c;那么如果不写终止条件或者终止条件写的不对&#xff0c;都…...

youtube 1080 分辨率 下载方式

YouTube 1080p Video Downloader 这张图像代表了Autodesk Maya中一个名为rocket_body_MAT的材质的着色器网络。下面是对节点及其连接的细分: 节点 place2dTexture12: 该节点用于控制2D纹理在表面上的位置映射。输出: Out UVrocket_body2.jpg: 该节点代表一个纹理文件,具体是…...

计算机网络ppt和课后题总结(下)

常用端口总结 计算机网络中&#xff0c;端口是TCP/IP协议的一部分&#xff0c;用于标识运行在同一台计算机上的不同服务。端口号是一个16位的数字&#xff0c;范围从0到65535。通常&#xff0c;0到1023的端口被称为“熟知端口”或“系统端口”&#xff0c;它们被保留给一些标准…...

测试基础12:测试用例设计方法-边界值分析

课程大纲 1、定义 经验发现&#xff0c;较多的错误往往发生在输入或输出范围的边界上&#xff0c;因为边界值是代码判断语句的点&#xff0c;一般容易出问题&#xff08;数值写错、多加或丢失等号、写错不等号方向…&#xff09;。所以增加对取值范围的边界数据的测试&#xff…...

AI大模型在健康睡眠监测中的深度融合与实践案例

文章目录 1. 应用方案2. 技术实现2.1 数据采集与预处理2.2 构建与训练模型2.3 个性化建议生成 3. 优化策略4. 应用示例&#xff1a;多模态数据融合与实时监测4.1 数据采集4.2 实时监测与反馈 5. 深入分析模型选择和优化5.1 LSTM模型的优势和优化策略5.2 CNN模型的优势和优化策略…...

【西瓜书】9.聚类

聚类任务是无监督学习的一种用于分类等其他任务的前驱过程&#xff0c;作为数据清洗&#xff0c;基于聚类结果训练分类模型 1.聚类性能度量&#xff08;有效性指标&#xff09; 分类任务的性能度量有错误率、精度、准确率P、召回率R、F1度量(P-R的调和平均)、TPR、FPR、AUC回归…...

使用jemalloc实现信号驱动的程序堆栈信息打印

使用jemalloc实现信号驱动的程序堆栈信息打印 本文介绍应用如何集成jemalloc&#xff0c;在接收到SIGUSR1信号10时打印程序的堆栈信息。 1. 编译jemalloc 首先&#xff0c;确保你已经编译并安装了启用prof功能的jemalloc。以下是ubuntu18.04上的编译步骤&#xff1a; git c…...

树的4种遍历

目录 树的四种遍历方式的总结 1. 前序遍历&#xff08;Pre-order Traversal&#xff09; 2. 中序遍历&#xff08;In-order Traversal&#xff09; 3. 后序遍历&#xff08;Post-order Traversal&#xff09; 4. 层序遍历&#xff08;Level-order Traversal 或 广度优先遍…...

深入探讨5种单例模式

文章目录 一、对比总览详细解释 二、代码1. 饿汉式2. 饱汉式3. 饱汉式-双检锁4. 静态内部类5. 枚举单例 三、性能对比 一、对比总览 以下是不同单例模式实现方式的特性对比表格。表格从线程安全性、延迟加载、实现复杂度、反序列化安全性、防反射攻击性等多个方面进行考量。 …...

SPOOL

-----How to Pass UNIX Variable to SPOOL Command (Doc ID 1029440.6) setenv只有csh才有不行啊PROBLEM DESCRIPTION: You would like to put a file name in Unix and have SQL*Plus read that file name, instead of hardcoding it, because it will change.You want to pa…...

挑战绝对不可能:再证有长度不同的射线

黄小宁 一空间坐标系中有公共汽车A&#xff0c;A中各座位到司机处的距离h是随着座位的不同而不同的变数&#xff0c;例如5号座位到司机处的距离是h3&#xff0c;…h5&#xff0c;…。A移动了一段距离变为汽车B≌A&#xff0c;B中5号座位到司机处的距离h’h3&#xff0c;…h’h5…...

【机器学习】Python与深度学习的完美结合——深度学习在医学影像诊断中的惊人表现

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、引言二、深度学习在医学影像诊断中的突破1. 技术原理2. 实际应用3. 性能表现 三、深度学习在医学影像诊断中的惊人表现1. 提高疾病诊断准确率2. 辅助制定治疗方案 四、深度学习对医疗行业的影响和推动作用 一、引言 随着…...

MapStruct的用法总结及示例

MapStruct是一个代码生成器&#xff0c;它基于约定优于配置的原则&#xff0c;使用Java注解来简化从源对象到目标对象的映射过程。它主要用于减少样板代码&#xff0c;提高开发效率&#xff0c;并且通过编译时代码生成来保证性能。 我的个人实践方面是在2021年前那时候在项目中…...

redis 05 复制 ,哨兵

01.redis的复制功能&#xff0c;使用命令slaveof 2. 2.1 2.2 3. 3.1 3.1.1 3.1.2 3.1.3 4 4.1 4.2 例子 5.1 这里是从客户端发出的指令 5.2 套接字就是socket 这里是和redis事件相关的知识 5.3 ping一下...

强大的.NET的word模版引擎NVeloDocx

在Javer的世界里&#xff0c;存在了一些看起来还不错的模版引擎&#xff0c;比如poi-tl看起来就很不错&#xff0c;但是那是人家Javer们专属的&#xff0c;与我们.Neter关系不大。.NET的世界里Word模版引擎完全是一个空白。 很多人不得不采用使用Word XML结合其他的模版引擎来…...

wordpress 支持mkv播放/推广图片制作

DW3000的自动应答功能允许芯片在接收并验证包含确认请求的帧时自动发送确认帧。自动确认功能只有在启用帧过滤和自动确认时才会起作用。 为了使自动确认启用&#xff0c;必须进行以下操作: 必须启用帧过滤&#xff0c;接收的数据或MAC命令帧必须正确寻址并通过接收帧过滤 htt…...

百度推广需要自己做网站吗/怎么创建公司网站

如何用matlab调用VS15创建的.exe文件&#xff08;C语言编写&#xff09;Step 1.编写C代码Step 2.matlab调用.exe附录&#xff1a;C中字符串转数据的函数Step 1.编写C代码 主函数格式&#xff1a;int main(int argc, char *argv[]) 若想从外部向main函数传递参数&#xff0c;该…...

查做空运磁检的网站/运营培训班有用吗

Spring Boot 默认使用的是 Tomcat 作为内嵌的服务器。所以&#xff0c;我们搭建一个 Web 工程将会变得非常的简单。 内嵌的 Tomcat&#xff0c;一个Jar包运行 还记得&#xff0c;《Spring Boot 揭秘与实战&#xff08;一&#xff09; 快速上手》讲到的例子么&#xff1f;我们来…...

网站建设合作品牌/哈尔滨网络seo公司

每次用到正则都要蛋疼一下&#xff0c;索性总结一下在这里。 正则 正則表達式主要分为基础正则和扩展正则。注意&#xff0c;正则和一般命令行输入的命令的通配符不同。正则仅仅使用于支持这样的表示法的工具&#xff0c;如:vi&#xff0c;grep&#xff0c;sed、awk。而ls等命令…...

总结做网站诊断步骤/seo的内容怎么优化

广告设计与制作数字媒体与游戏设计方向方向简介广告设计与制作--数字媒体与游戏设计是我院广告专业的特色专业方向。在互联网和数媒游戏行业快速兴起之下&#xff0c;为顺应时代发展&#xff0c;赶上信息技术的浪潮&#xff0c;广告专业在传统专业上与新媒体高度融合&#xff0…...

如何给网站做排名/seo实战优化

研究了一下腾讯信鸽的demo&#xff0c;感觉里面一个自定义handler类有问题这是该handler的代码private static class HandlerExtension extends Handler {WeakReference mActivity;HandlerExtension(MainActivity activity) {mActivity new WeakReference(activity);}Override…...