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

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

[复制链接]
小萝卜啦啦啦 发布时间:2024-5-10 22:52
STM32U08是带硬件AES加解密模块的,硬件加解密的最大优势就是快。
& x9 Y) O, z" Z( E4 I9 {' i: y
一、cube配置
首先需要在cube中开启AES模块(工程就是上一篇中创建的模板工程)

& ~& O- g/ ^  G  {
参数这一块主要关注的是加密模式(Data encryption type)、秘钥长度(KeySize)、秘钥(Encryption/Decryption key),其他参数保持默认就可以
1.png
其中加密模式支持如下
2.png
秘钥长度支持128位、256位
秘钥的值可以在cube中配置,也可以这里保持默认值,回头在代码中重新配置(当然上述的这些参数都可以通过代码再次配置,这个待会实战部分会有介绍)
$ O5 C# j% _$ I3 s& a
最后点击右上角生成代码
3.png

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

) u2 ]. ]' R( e$ m& ^" C  S4 m5 b
8.png

/ ~" n4 B% ^+ @2 \: t4 E' ]
在初始化函数中可以看到,配置了各个参数,和cube中的一致。然后就是调用了初始化,秘钥、加密模式等就是在init时配置进去的,如果需要更换,那就要调用HAL_CRYP_DeInit(),修改配置参数,然后再调用HAL_CRYP_Init()(这个待会儿我也会尝试一下)
, L, V1 _. k2 ]3 B9 @2 H/ V7 u
在使用加密前,需要在main函数的最一开始就开启AES的时钟
  1. __HAL_RCC_AES_CLK_ENABLE();
复制代码
4.png

( j9 i$ F- v8 L: E/ I
加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密
具体函数如下
  1. HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,4 h+ n. ]. i  Z0 }$ h
  2.                                    uint32_t Timeout);
    / x( k1 L- j7 x" {0 s& |6 l  s
  3. HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
    * U& A0 c* C7 K4 r4 ^6 G
  4.                                    uint32_t Timeout);
    & T- U: j* v4 w) v/ {8 B9 M3 E
  5. HAL_StatusTypeDef HAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);/ C' L: H- R/ c) C2 L  i2 ~
  6. HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
    9 o& {0 o. _$ U
  7. HAL_StatusTypeDef HAL_CRYP_Encrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);2 Y5 F% p1 b4 @1 |6 i9 C
  8. HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码
5.png
+ A7 U! m: C9 }2 a
这里我再插一嘴,AES是需要加解密数据为16字节的倍数才可以运行,如果你的不是16字节的倍数,那么就需要做一下填充,加解密接口是不提供填充的,需要自己实现

/ t! W1 C, x5 h8 p
今天我们的测试的是最基础的阻塞加解密函数
& n' B& z# L( c
2.2 AES ECB 128bit加解密测试
我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试
先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上
  1. /* 计算得到的秘文 */7 p1 u  }- e8 K& \' D  c+ O
  2. uint32_t Computed_Ciphertext[AES_DATA_SIZE];$ ~3 Q/ d/ T$ u* |( r( o* R1 @
  3. /* 计算得到的明文 */. ~! M" K! g/ E% \# f; X+ O  K
  4. uint32_t Computed_plainText[AES_DATA_SIZE];, A5 D9 z& }+ `* @
  5. % {) G5 Y1 G0 s# }
  6. /* 用户自定义128bit秘钥 */
    ' `# p; |% q" E6 g
  7. uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =
    # g! j' r2 |* M+ y* o; E9 i
  8. {. u7 {$ e  m* P0 f
  9.   0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff  \+ d6 J- h/ `: t
  10. };) a% i, H/ c. D
  11. /* 加密前的明文 */  x$ u( N0 L3 b$ k$ r1 v
  12. uint32_t AES_plainText[AES_DATA_SIZE] =) _0 i6 T, ]: u# h; u
  13. {5 B# j5 s' l5 A  l! z
  14.   0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f) q- t+ e2 m' O1 k4 e* N6 L
  15. };
    6 F2 V1 {6 E( ~& O: R

  16. ; j% g. w, T3 v; F7 O7 A  b6 A, i2 D
  17. /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */" W8 e3 {) X5 t; a1 e4 D2 W
  18. uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
    2 X; L/ j2 ~5 O  l& H
  19. {
    7 p, o! D6 {4 Y# e  ~, Z
  20.   0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE003
    : @  T+ {6 T8 G9 ]
  21. };
    6 g1 C9 i6 a7 _; p7 ~- |% D
  22. /* AES ECB使用cube默认128bit秘钥加密后的秘文 */
    9 [/ R+ D9 |6 A
  23. uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =- {9 P$ ^5 C0 s, k) H6 S
  24. {
    & D0 ^$ ~* Q6 J8 {* M
  25.   0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A282
    - a, X9 U! X8 b9 N7 ?2 U- F
  26. };
复制代码
9.png
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的
( X! v4 Y: ]) w3 l+ U# a
然后在加一下宏定义
  1. /* AES加解密阻塞式函数超时时间 */" ]8 g  t/ ^2 v: k7 Q
  2. #define AES_TIMEOUT_VALUE 0xFF  //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说
    3 F- Q  J- Z6 A: G3 u' n* w
  3. /* AES加解密数据的长度(byte) */
    & S% O% E2 b* G) H2 w  K4 U7 `* }
  4. #define AES_DATA_SIZE_BYTE 16" h6 @$ K5 |+ U
  5. /* AES加解密数据的长度(uint32_t) */
    3 l9 j3 O+ L' S; J
  6. #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4)
      o# m3 R: q7 q) z  j
  7. /* AES加解密秘钥的长度(bit) */
    : G6 e4 q8 f7 V% R5 M  ~
  8. #define AES_KEY_SIZE_BIT 128
    0 ~9 ^% \" m" E- N
  9. /* AES加解密数据的长度(uint32_t) */( ]8 Z8 \& m! G$ C6 O% C! r% K
  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)
    + ~7 W* [1 Q, b
  2. {: l  [; i. s: Z7 @
  3.   for (uint8_t i = 0; i < Size; i++)
    + `% x6 u2 ?9 b2 A
  4.   {
    ; o- U/ q" _- N7 L4 L
  5.     printf("%02X ", ((*pData & 0xFF000000) >> 24));
    ( k. f6 ?% d4 G9 e7 Z$ S; a
  6.     printf("%02X ", ((*pData & 0x00FF0000) >> 16));* G7 E* S. n9 C
  7.     printf("%02X ", ((*pData & 0x0000FF00) >> 8));- W5 L9 r. g; N; x
  8.     printf("%02X ", ((*pData & 0x000000FF)));
    6 l: r5 ?& `2 e7 L: W  C
  9.     pData++;+ I+ ~0 L2 j, p' {8 W" @8 f/ G# ?
  10.   }! s. {0 n* n5 o% M6 @
  11.   printf("\r\n");
    ' l2 k# v# O5 u
  12. }
    - {7 O+ O& H( G7 V" U' t

  13. 3 K6 l. |6 t. h/ n" p
  14. void AES_encrypt_test(uint32_t *plainText)% j( H! B1 w* R( `3 b
  15. {
    ! D) U: y9 y+ a) c' T
  16.   printf("plainText = ");1 L. T8 h4 z! G0 X5 ~4 D
  17.   dump_data(plainText, AES_DATA_SIZE);
    9 l; b9 ]8 c# f& W

  18. $ X8 F! }" Z5 B9 v4 v
  19.   if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK)# \6 z# F* h4 C, q9 p
  20.   {: P4 [2 q9 h' |* N
  21.     printf("AES encrypt success\r\n");6 `. b5 B/ u& X2 l4 I2 W. `
  22.     printf("Computed_Ciphertext = ");4 X- }7 W$ K" E( Y4 m
  23.     dump_data(Computed_Ciphertext, AES_DATA_SIZE);; U' b  y& J- D) j2 I; R- i7 u. }
  24.   }
    . j0 L  T* A  S, s/ V8 _
  25.   else/ a* t& Q7 r8 K
  26.   {
    , W. j3 m5 Q) v# w! a
  27.     printf("AES encrypt error\r\n");7 Q8 Z( X4 \+ |/ r" ?4 y
  28.     Error_Handler();2 g9 B5 T' k* M
  29.   }
    # K: `7 x' C" w( T4 J
  30.   printf("\r\n");, H  }2 j6 H- i. V
  31. }1 R5 `, j' P( c% |3 n

  32. 6 F3 a% y( K: ]" ^& P) w6 [- f
  33. void AES_dencrypt_test(uint32_t *cipherText)
    : k3 O9 k: y( q' \9 G) j9 @
  34. {
    - f6 ]0 [+ q# \3 V* T8 M
  35.   printf("cipherText = ");9 Z" C2 G2 E; w3 P
  36.   dump_data(cipherText, AES_DATA_SIZE);7 v6 F, F$ j* M! V% V9 ^5 d

  37. 5 w4 i5 c* P. M( Y. Q
  38.   if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK)
    0 r4 A6 C% z5 D2 D" C
  39.   {
    2 T* {% g* A% W# V2 }9 ^
  40.     printf("AES dencrypt success\r\n");+ b% }" |3 Q. u+ b2 s4 n9 t* K
  41.     printf("Computed_plainText = ");
    4 r8 O) m+ g- r
  42.     dump_data(Computed_plainText, AES_DATA_SIZE);
    & c3 b- j6 D3 `3 z7 F* Z
  43.   }9 i1 Y% [/ U" T' H0 a) Q  w6 }/ f
  44.   else
    ; w; }, ~+ C; R! Z
  45.   {
    $ s( ?+ I8 v0 D; O" S+ D8 Y3 U1 Z
  46.     printf("AES dencrypt error\r\n");
    & q3 z/ |. r+ `$ ^+ |- Z, u
  47.     Error_Handler();
    ; U* C5 ~7 z0 q* K0 F9 S
  48.   }
    0 Q5 m% q/ ]# D$ L$ U
  49.   printf("\r\n");* M8 p! i, ^0 a' R, n  t
  50. }
复制代码
11.png

+ s" I) G' U) b& e# g! C: n; q2 Y3 d4 H2 p. F6 d- c, T
然后在main中调用
  1.   printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");: U/ T" v( n) y  s! S. V0 c
  2.   AES_encrypt_test(&AES_plainText[0]);7 Y) O. e  _. C" }: }4 O
  3.   printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n");
    0 t- E4 v9 m1 f1 {1 K' q5 e1 _
  4.   AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码
12.png
编译运行一下,结果如下
13.png
和在线工具对比一下,结果一致
14.png
- a6 Y/ z" _$ c$ e3 ~3 D  D6 o9 j
接下来尝试更换一下秘钥,再运行加解密
更换秘钥有2种方案,第一是直接对MX_AES_Init中的内容修改,但是因为这里是cube自动生成的,后续cube再生成一次就又变回去了。所以我选择方案二:去初始化,修改参数,再初始化。
2 v2 W3 f) B9 x3 A
改变秘钥函数
  1. void change_key_to_user_defined_AesKey_128bit(). R" u( z& N& U7 j9 |
  2. {
    * X0 g8 T9 Y7 u
  3.   printf("change AES KEY to user_defined_AesKey_128bit\r\n");: s0 O& Y3 `  L, Z8 @7 u
  4.   /* 先去初始化 */! h9 a0 U% T: n, \3 m
  5.   if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)7 N$ F4 x% V. `3 e! m
  6.   {
    " _4 J0 _7 s7 v' ~
  7.     printf("HAL_CRYP_DeInit error\r\n");* ~8 O% D) h9 m) ], t& f2 K$ ?2 Q
  8.     Error_Handler();
    1 i' K5 b2 u- {1 P
  9.   }* h3 c- i) `" f' [0 p5 @- L
  10. ( Q3 t$ P, }1 w4 d2 w$ v
  11.   /* 修改使用的秘钥 */4 K" ^, Z& q% B' R
  12.   hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;
    9 L% D6 x8 o( j. f7 K3 ]

  13. ; U( W7 S  K' J* ], X5 `- \
  14.   /* 再次初始化 */
    5 H3 h/ @% F' u
  15.   if (HAL_CRYP_Init(&hcryp) != HAL_OK)
    . [; C/ k6 b& d% Q6 _2 Y. F( M
  16.   {( V- [' F9 p' y" \1 q
  17.     printf("HAL_CRYP_Init error\r\n");' s0 F& f; s( e' j1 R* F
  18.     Error_Handler();
    * j0 I& m4 x  ~0 s" F( u
  19.   }
    1 W' j" O# e7 `( V+ Z: r9 c
  20.   printf("\r\n");4 \9 j3 J7 U' R! |+ ]6 X
  21. }
复制代码
15.png

  b! P, v1 U& h; j1 C; x& i/ ~
+ S9 K' x8 I( _9 `
然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功
  1.   change_key_to_user_defined_AesKey_128bit();+ K1 E/ W* U+ d% U
  2. : D' D! F4 Q% _* i0 ]
  3.   printf("AES ECB use user defined key 128Bit encrypt test\r\n");( M9 {  ]- {) S; |! S/ I
  4.   AES_encrypt_test(&AES_plainText[0]);
    2 O' |* `$ @/ T
  5.   printf("AES ECB use user defined key 128Bit dencrypt test\r\n");
    * ~9 X$ _5 o: t! C1 x3 O" E
  6.   AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码
16.png
编译下载运行效果如下
17.png
和在线工具对比一下,结果一致
18.png

6 s- _& L& f; L/ G+ C7 ~
2.2 AES CBC 128bit加解密测试
然后我们把AES模式切换至CBC模式,来进行测试
CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下
  1. /* AES CBC使用的IV */
复制代码
然后准备一下CBC加密后的结果的数组,回头给解密时使用
  1. /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */
    & f' m' r8 m% A1 _) p% D0 S
  2. uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =3 b% z& m& Y0 S* B
  3. {
    ( B) ]7 E; K8 _+ _2 s" I& m8 J2 M9 ]
  4.   0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E783
    & f) l7 C8 ?; o7 g
  5. };
复制代码
19.png
写一下切换至CBC模式的函数
  1. void change_to_aes_cbc_mode()* _7 i$ d" k8 s: ~* ~1 [
  2. {
    0 y2 m% C" |* U, G# B% s
  3.   printf("change to AES CBC mode\r\n");
    1 w3 _: \0 a. f9 O
  4.   /* 先去初始化 */0 A8 ~. S* U' w# i0 D8 T
  5.   if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)
    ( \: C$ E2 E5 M
  6.   {6 M/ r% `# Q: q+ h1 ~5 G; `
  7.     printf("HAL_CRYP_DeInit error\r\n");* j% P- ~1 A, v/ M7 V/ s
  8.     Error_Handler();
    - x' ^" v5 H& V, V. i# H4 q
  9.   }: F7 m- t0 T0 ~( J7 l
  10. 6 G1 S& R3 _' a" A' K. o( @% u$ V9 @- N
  11.   /* 修改为CBC模式 */
      ~+ o8 i& [0 p' d# N
  12.   hcryp.Init.Algorithm = CRYP_AES_CBC;3 O: [( l# m* B: i) A9 E
  13.   /* 设置IV */
    8 j( Q5 e- S: S6 R
  14.   hcryp.Init.pInitVect  = AES_CBC_IV;
      c7 `& K7 ^% `5 O
  15. ) ^  \( b. C3 ~! P
  16.   /* 再次初始化 */1 R; g# I  g' `$ `/ O
  17.   if (HAL_CRYP_Init(&hcryp) != HAL_OK)& o7 A1 f# t6 V# R5 Z+ Q+ M" l: I: k
  18.   {
    0 j( Z# U( ~4 S# a
  19.     printf("HAL_CRYP_Init error\r\n");
    - L0 \$ b2 [! Q' I* G
  20.     Error_Handler();
    : f, G3 }0 |5 C5 @. W
  21.   }' v4 f$ V7 a  X) H
  22.   printf("\r\n");
    2 K. z# n9 ]" J' E, q! o$ R
  23. }
复制代码
20.png
在main中调用切换函数,然后进行CBC加解密测试
  1.   change_to_aes_cbc_mode();6 o/ `& f4 |, H8 r# B
  2. 9 ?  H$ h3 @. {% N
  3.   printf("AES CBC use user defined key 128Bit encrypt test\r\n");
    + A0 e0 I: G+ Q
  4.   AES_encrypt_test(&AES_plainText[0]);
    * E4 X! d' h: ~! p; ^: O. w5 ^
  5.   printf("AES CBC use user defined key 128Bit dencrypt test\r\n");
    ; G0 {# C4 m) O( z
  6.   AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码
21.png
编译下载,结果如下
22.png
和在线工具对比一下,结果一致
23.png
三、总结
今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。

' [( U2 i; d( g本次工程代码: STM32U0_AES_test.rar (5.21 MB, 下载次数: 5)
赞 1 收藏 评论2 发布时间:2024-5-10 22:52

举报

2个回答
STMCU-管管 回答时间:2024-5-11 09:03:52
赞,用心了
5 B( G$ h1 G2 V5 |
Yude 回答时间:2024-5-22 16:55:14

好详细啊👍

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版