你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【NUCLEO-U083RC评测】③AES加解密测试

[复制链接]
小萝卜啦啦啦 发布时间:2024-5-10 22:52
STM32U08是带硬件AES加解密模块的,硬件加解密的最大优势就是快。

一、cube配置
首先需要在cube中开启AES模块(工程就是上一篇中创建的模板工程)

参数这一块主要关注的是加密模式(Data encryption type)、秘钥长度(KeySize)、秘钥(Encryption/Decryption key),其他参数保持默认就可以
1.png
其中加密模式支持如下
2.png
秘钥长度支持128位、256
秘钥的值可以在cube中配置,也可以这里保持默认值,回头在代码中重新配置(当然上述的这些参数都可以通过代码再次配置,这个待会实战部分会有介绍)

最后点击右上角生成代码
3.png

二、实战
2.1 AES时钟初始化及函数介绍
先来看一下CUBE自动生成的代码
首先是变量
  1. CRYP_HandleTypeDef hcryp;
  2. uint32_t pKeyAES[4] = {0x00000000,0x00000000,0x00000000,0x00000000};
复制代码
6.png
这边的pKeyAES就是秘钥,和之前cube中设置的一致(下面的测试中我会尝试更换秘钥)
然后就是AES模块的初始化函数
  1. MX_AES_Init();
复制代码
7.png

8.png

在初始化函数中可以看到,配置了各个参数,和cube中的一致。然后就是调用了初始化,秘钥、加密模式等就是在init时配置进去的,如果需要更换,那就要调用HAL_CRYP_DeInit(),修改配置参数,然后再调用HAL_CRYP_Init()(这个待会儿我也会尝试一下)

在使用加密前,需要在main函数的最一开始就开启AES的时钟
  1. __HAL_RCC_AES_CLK_ENABLE();
复制代码
4.png

加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密
具体函数如下
  1. HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
  2.                                    uint32_t Timeout);
  3. HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
  4.                                    uint32_t Timeout);
  5. HAL_StatusTypeDef HAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
  6. HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
  7. HAL_StatusTypeDef HAL_CRYP_Encrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
  8. HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码
5.png

这里我再插一嘴,AES是需要加解密数据为16字节的倍数才可以运行,如果你的不是16字节的倍数,那么就需要做一下填充,加解密接口是不提供填充的,需要自己实现

今天我们的测试的是最基础的阻塞加解密函数

2.2 AES ECB 128bit加解密测试
我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试
先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上
  1. /* 计算得到的秘文 */
  2. uint32_t Computed_Ciphertext[AES_DATA_SIZE];
  3. /* 计算得到的明文 */
  4. uint32_t Computed_plainText[AES_DATA_SIZE];

  5. /* 用户自定义128bit秘钥 */
  6. uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =
  7. {
  8.   0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff
  9. };
  10. /* 加密前的明文 */
  11. uint32_t AES_plainText[AES_DATA_SIZE] =
  12. {
  13.   0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f
  14. };

  15. /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */
  16. uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
  17. {
  18.   0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE003
  19. };
  20. /* AES ECB使用cube默认128bit秘钥加密后的秘文 */
  21. uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =
  22. {
  23.   0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A282
  24. };
复制代码
9.png
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的

然后在加一下宏定义
  1. /* AES加解密阻塞式函数超时时间 */
  2. #define AES_TIMEOUT_VALUE 0xFF  //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说
  3. /* AES加解密数据的长度(byte) */
  4. #define AES_DATA_SIZE_BYTE 16
  5. /* AES加解密数据的长度(uint32_t) */
  6. #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4)
  7. /* AES加解密秘钥的长度(bit) */
  8. #define AES_KEY_SIZE_BIT 128
  9. /* AES加解密数据的长度(uint32_t) */
  10. #define AES_KEY_SIZE (AES_KEY_SIZE_BIT / 4)
复制代码
10.png
然后写一下AES ECB 128bit秘钥的加解密测试函数以及dump函数
  1. void dump_data(uint32_t *pData, uint8_t Size)
  2. {
  3.   for (uint8_t i = 0; i < Size; i++)
  4.   {
  5.     printf("%02X ", ((*pData & 0xFF000000) >> 24));
  6.     printf("%02X ", ((*pData & 0x00FF0000) >> 16));
  7.     printf("%02X ", ((*pData & 0x0000FF00) >> 8));
  8.     printf("%02X ", ((*pData & 0x000000FF)));
  9.     pData++;
  10.   }
  11.   printf("\r\n");
  12. }

  13. void AES_encrypt_test(uint32_t *plainText)
  14. {
  15.   printf("plainText = ");
  16.   dump_data(plainText, AES_DATA_SIZE);

  17.   if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK)
  18.   {
  19.     printf("AES encrypt success\r\n");
  20.     printf("Computed_Ciphertext = ");
  21.     dump_data(Computed_Ciphertext, AES_DATA_SIZE);
  22.   }
  23.   else
  24.   {
  25.     printf("AES encrypt error\r\n");
  26.     Error_Handler();
  27.   }
  28.   printf("\r\n");
  29. }

  30. void AES_dencrypt_test(uint32_t *cipherText)
  31. {
  32.   printf("cipherText = ");
  33.   dump_data(cipherText, AES_DATA_SIZE);

  34.   if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK)
  35.   {
  36.     printf("AES dencrypt success\r\n");
  37.     printf("Computed_plainText = ");
  38.     dump_data(Computed_plainText, AES_DATA_SIZE);
  39.   }
  40.   else
  41.   {
  42.     printf("AES dencrypt error\r\n");
  43.     Error_Handler();
  44.   }
  45.   printf("\r\n");
  46. }
复制代码
11.png


然后在main中调用
  1.   printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");
  2.   AES_encrypt_test(&AES_plainText[0]);
  3.   printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n");
  4.   AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码
12.png
编译运行一下,结果如下
13.png
和在线工具对比一下,结果一致
14.png

接下来尝试更换一下秘钥,再运行加解密
更换秘钥有2种方案,第一是直接对MX_AES_Init中的内容修改,但是因为这里是cube自动生成的,后续cube再生成一次就又变回去了。所以我选择方案二:去初始化,修改参数,再初始化。

改变秘钥函数
  1. void change_key_to_user_defined_AesKey_128bit()
  2. {
  3.   printf("change AES KEY to user_defined_AesKey_128bit\r\n");
  4.   /* 先去初始化 */
  5.   if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)
  6.   {
  7.     printf("HAL_CRYP_DeInit error\r\n");
  8.     Error_Handler();
  9.   }

  10.   /* 修改使用的秘钥 */
  11.   hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;

  12.   /* 再次初始化 */
  13.   if (HAL_CRYP_Init(&hcryp) != HAL_OK)
  14.   {
  15.     printf("HAL_CRYP_Init error\r\n");
  16.     Error_Handler();
  17.   }
  18.   printf("\r\n");
  19. }
复制代码
15.png


然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功
  1.   change_key_to_user_defined_AesKey_128bit();

  2.   printf("AES ECB use user defined key 128Bit encrypt test\r\n");
  3.   AES_encrypt_test(&AES_plainText[0]);
  4.   printf("AES ECB use user defined key 128Bit dencrypt test\r\n");
  5.   AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码
16.png
编译下载运行效果如下
17.png
和在线工具对比一下,结果一致
18.png

2.2 AES CBC 128bit加解密测试
然后我们把AES模式切换至CBC模式,来进行测试
CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下
  1. /* AES CBC使用的IV */
复制代码
然后准备一下CBC加密后的结果的数组,回头给解密时使用
  1. /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */
  2. uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
  3. {
  4.   0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E783
  5. };
复制代码
19.png
写一下切换至CBC模式的函数
  1. void change_to_aes_cbc_mode()
  2. {
  3.   printf("change to AES CBC mode\r\n");
  4.   /* 先去初始化 */
  5.   if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)
  6.   {
  7.     printf("HAL_CRYP_DeInit error\r\n");
  8.     Error_Handler();
  9.   }

  10.   /* 修改为CBC模式 */
  11.   hcryp.Init.Algorithm = CRYP_AES_CBC;
  12.   /* 设置IV */
  13.   hcryp.Init.pInitVect  = AES_CBC_IV;

  14.   /* 再次初始化 */
  15.   if (HAL_CRYP_Init(&hcryp) != HAL_OK)
  16.   {
  17.     printf("HAL_CRYP_Init error\r\n");
  18.     Error_Handler();
  19.   }
  20.   printf("\r\n");
  21. }
复制代码
20.png
在main中调用切换函数,然后进行CBC加解密测试
  1.   change_to_aes_cbc_mode();

  2.   printf("AES CBC use user defined key 128Bit encrypt test\r\n");
  3.   AES_encrypt_test(&AES_plainText[0]);
  4.   printf("AES CBC use user defined key 128Bit dencrypt test\r\n");
  5.   AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码
21.png
编译下载,结果如下
22.png
和在线工具对比一下,结果一致
23.png
三、总结
今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。

本次工程代码: STM32U0_AES_test.rar (5.21 MB, 下载次数: 3)
1 收藏 评论2 发布时间:2024-5-10 22:52

举报

2个回答
STMCU-管管 回答时间:2024-5-11 09:03:52
赞,用心了
Yude 回答时间:2024-5-22 16:55:14

好详细啊👍

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版