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

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

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

; |, ~" m% d& p
一、cube配置
首先需要在cube中开启AES模块(工程就是上一篇中创建的模板工程)

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

6 m& L2 l0 R& {, N  q
最后点击右上角生成代码
3.png

" u9 j2 Y" K( E* I, p+ g- X
二、实战
2.1 AES时钟初始化及函数介绍
先来看一下CUBE自动生成的代码
首先是变量
  1. CRYP_HandleTypeDef hcryp;) H( l5 l: F. m/ t9 o& T
  2. uint32_t pKeyAES[4] = {0x00000000,0x00000000,0x00000000,0x00000000};
复制代码
6.png
这边的pKeyAES就是秘钥,和之前cube中设置的一致(下面的测试中我会尝试更换秘钥)
然后就是AES模块的初始化函数
  1. MX_AES_Init();
复制代码
7.png

& c5 G% V! Z; x5 ]+ F- k
8.png

# z! J' Z. P1 U- O" }
在初始化函数中可以看到,配置了各个参数,和cube中的一致。然后就是调用了初始化,秘钥、加密模式等就是在init时配置进去的,如果需要更换,那就要调用HAL_CRYP_DeInit(),修改配置参数,然后再调用HAL_CRYP_Init()(这个待会儿我也会尝试一下)
, L; d# y/ ^. P2 w) t+ x
在使用加密前,需要在main函数的最一开始就开启AES的时钟
  1. __HAL_RCC_AES_CLK_ENABLE();
复制代码
4.png

8 R2 R: b/ N( o1 E& v
加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密
具体函数如下
  1. HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
    + A( H) B, p' v
  2.                                    uint32_t Timeout);. b+ E0 Z" _2 @# u# W, ~) ~1 d
  3. HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
    8 ?, R" _  y1 b2 t0 R0 n& F' h0 m
  4.                                    uint32_t Timeout);
    , Y" Q+ X$ t! y
  5. HAL_StatusTypeDef HAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);: n4 d9 o2 G4 |8 R% Y3 [! t
  6. HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);$ V$ R; i+ f: L' K
  7. HAL_StatusTypeDef HAL_CRYP_Encrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
    ! r4 h7 Z6 O# @9 v
  8. HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码
5.png
. K: @- }6 F( t6 ^
这里我再插一嘴,AES是需要加解密数据为16字节的倍数才可以运行,如果你的不是16字节的倍数,那么就需要做一下填充,加解密接口是不提供填充的,需要自己实现
! Z& H% A) d! M
今天我们的测试的是最基础的阻塞加解密函数
7 t0 b2 e% }! _) d6 A
2.2 AES ECB 128bit加解密测试
我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试
先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上
  1. /* 计算得到的秘文 */6 V( R/ X  b+ H: @7 k, E3 e
  2. uint32_t Computed_Ciphertext[AES_DATA_SIZE];9 q) y7 j- O: g+ L
  3. /* 计算得到的明文 */
    ! D/ o, w$ j  `# b  H
  4. uint32_t Computed_plainText[AES_DATA_SIZE];
    / m4 V8 a9 K  H0 C. E

  5. ' @/ _3 _# d) U' h
  6. /* 用户自定义128bit秘钥 */
    4 o" h4 |# ^0 c' o
  7. uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =. L2 a: n2 l$ Y, K& _) H
  8. {! S7 I, D; y' |+ |& Y+ W
  9.   0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff  i7 A9 s: {, T7 N& G+ e
  10. };
    9 ^3 r1 p' L, O! j
  11. /* 加密前的明文 */
    . f$ E0 ]( L% `8 @; y% R
  12. uint32_t AES_plainText[AES_DATA_SIZE] =% V1 A0 v$ x3 _
  13. {" v7 I2 v  h0 w6 i& d
  14.   0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f9 u2 k* B; T8 `
  15. };, g0 r% H1 F- s7 Y. b

  16. + _7 ?0 i# a$ r9 {* v
  17. /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */8 L9 E! f- ]. G  B+ w  a% T5 G8 K
  18. uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
    3 U5 u2 k8 ?7 U( Y( S" p! d9 B
  19. {3 z: b# G. A# }8 R2 S
  20.   0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE0036 m" D9 e* _" l! F* t
  21. };; N1 ?  e3 y" z+ _; a: ]% Z
  22. /* AES ECB使用cube默认128bit秘钥加密后的秘文 */
    ) u9 P7 s7 L7 a* F8 ^$ E$ [3 f
  23. uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =5 j& \7 v8 F) W$ a% X
  24. {# r% k" K- M1 ~3 v+ G1 f! K1 p
  25.   0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A282
    7 o& x' s$ _9 M; x, E* g
  26. };
复制代码
9.png
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的

( b8 \: p5 z: B) N
然后在加一下宏定义
  1. /* AES加解密阻塞式函数超时时间 */- }( H3 E% I* C4 c2 |9 b
  2. #define AES_TIMEOUT_VALUE 0xFF  //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说- S3 y& \0 ^% t0 L2 Q
  3. /* AES加解密数据的长度(byte) */$ v/ V% I6 ?& J8 Q) E% _* }9 C  q0 R
  4. #define AES_DATA_SIZE_BYTE 16. L7 s) H' H! V8 h0 M9 c! o) u; a
  5. /* AES加解密数据的长度(uint32_t) */$ v4 `2 ^2 B4 h, l) O5 f! J6 U7 X
  6. #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4)4 a6 p) j, }8 ?7 D; [6 W8 G$ ^: W* g
  7. /* AES加解密秘钥的长度(bit) */7 k. y# P4 r6 D4 _; P1 k
  8. #define AES_KEY_SIZE_BIT 128. C+ b0 B3 }) e2 G$ [# C
  9. /* AES加解密数据的长度(uint32_t) */
    ( d0 K$ L* r; ~& d8 \
  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)
    4 P  v3 d3 h7 Z# ?
  2. {
    ! m; e% y0 j# }3 ^
  3.   for (uint8_t i = 0; i < Size; i++)
    " s1 H3 t. u7 ^+ u; H$ d7 C
  4.   {
    5 Z' U2 o$ d$ l  z) u  b0 S9 g
  5.     printf("%02X ", ((*pData & 0xFF000000) >> 24));
    1 ^8 T6 v0 i% G! A4 w/ F& e1 `
  6.     printf("%02X ", ((*pData & 0x00FF0000) >> 16));
    . J* \" ]( y/ V2 O% o
  7.     printf("%02X ", ((*pData & 0x0000FF00) >> 8));, N0 y9 q0 R. C6 B2 \
  8.     printf("%02X ", ((*pData & 0x000000FF)));3 d4 O- i, V0 `& X' Z! h. \$ g8 q
  9.     pData++;
    0 f; l# a0 Q2 \/ X' x9 `
  10.   }- d+ `% v) g: ]  a
  11.   printf("\r\n");
    9 e  @% v+ X- m. D% A% W
  12. }9 s6 ]& W. S& k1 G
  13. - \* W  u1 n- b. E; L
  14. void AES_encrypt_test(uint32_t *plainText)
    4 r% z! A1 Z& l/ S% ?& W4 P) H
  15. {. |0 V+ l, U3 O, d3 Y
  16.   printf("plainText = ");
    7 x+ \# B9 _+ c1 e; A, s4 A
  17.   dump_data(plainText, AES_DATA_SIZE);
    8 [) e9 M* D8 f$ l$ ?0 C
  18. " }, l5 K' y- ]: U: |1 B
  19.   if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK)2 ]! I! |' [$ ?5 ^! u8 q
  20.   {& ?7 \& @: ?- w/ o( e
  21.     printf("AES encrypt success\r\n");# ]( b5 \( z7 ^4 o( L
  22.     printf("Computed_Ciphertext = ");
    ! r2 U, P6 M- V% ]# @3 g
  23.     dump_data(Computed_Ciphertext, AES_DATA_SIZE);
    5 s8 N6 P$ D) w2 D( E  d
  24.   }
    1 Y* M8 ?! ]/ a1 M3 ^0 i
  25.   else. N  J) O' o. Y# u9 _% g5 g3 z0 Z' p
  26.   {
    3 w0 o# N1 p/ O2 t& A6 T
  27.     printf("AES encrypt error\r\n");& o* ^6 J  \# P. B
  28.     Error_Handler();
    . i+ `) N# Q7 {) j
  29.   }' G' L7 B1 V3 t  C
  30.   printf("\r\n");" ^5 N& F$ Y1 ^. a$ y
  31. }
    1 G$ t$ x) ]; [* e) p
  32. ) f0 W; S0 W1 a3 t  p
  33. void AES_dencrypt_test(uint32_t *cipherText)
    : R" z& G: _9 z. u8 E, e3 [
  34. {1 T6 D3 l- M, O: e
  35.   printf("cipherText = ");
    2 A; h4 K9 @! d2 c5 k
  36.   dump_data(cipherText, AES_DATA_SIZE);
    # b: S. H2 Q8 B
  37. ; z. k: S, o7 P: r+ Z5 J( q& L
  38.   if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK)  ]; z$ X( u5 p8 ]5 b7 l: o
  39.   {
    3 M8 l7 ?3 P' G* a. F
  40.     printf("AES dencrypt success\r\n");
    % h/ v# |; h( O+ r( o, G9 p& k/ t
  41.     printf("Computed_plainText = ");
    8 {9 D" ?& Z7 X" ]0 O
  42.     dump_data(Computed_plainText, AES_DATA_SIZE);
    / `! h7 G/ I! v
  43.   }* v. r0 D& m7 A: c6 w4 L
  44.   else! G7 j! T0 u* q; A& ~. Y
  45.   {
    . }. H% X$ Z! Z# f3 s0 Q
  46.     printf("AES dencrypt error\r\n");, l2 b4 z8 N: i# ]( u
  47.     Error_Handler();
    & C+ q) J! ]2 D" L2 P( }7 q
  48.   }2 s+ n& I2 S$ _- S( p5 j
  49.   printf("\r\n");% ^* g0 Z. x1 Q; O  v- n5 g2 O9 W
  50. }
复制代码
11.png

2 h) U6 d0 Y  U6 H4 ]8 `6 Y+ Y  T2 U# k! h' w% O
然后在main中调用
  1.   printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");8 C, F, c9 V9 f+ g' C7 m
  2.   AES_encrypt_test(&AES_plainText[0]);4 @1 E: J; m+ Q
  3.   printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n");% n' N9 S# h7 ~# n
  4.   AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码
12.png
编译运行一下,结果如下
13.png
和在线工具对比一下,结果一致
14.png

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

2 v9 l2 z: o1 }. P0 g
改变秘钥函数
  1. void change_key_to_user_defined_AesKey_128bit()
      V! O8 C: G* s0 K& h& J% Z
  2. {
    0 e( I3 H% E0 C
  3.   printf("change AES KEY to user_defined_AesKey_128bit\r\n");  S1 d& C; G8 V" W/ a7 }9 T6 O
  4.   /* 先去初始化 */
    3 K& ~0 [" j3 D
  5.   if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)# D1 s2 D7 ?( ~3 D
  6.   {
    ; d1 B8 y  `% |
  7.     printf("HAL_CRYP_DeInit error\r\n");
    7 H! W* J% j: g4 [2 ~
  8.     Error_Handler();
    / A- M: R# ^& T: V
  9.   }
    1 A# y; e% r! w- m8 z- n
  10. 3 L7 c0 N7 f2 Z4 |1 c$ {
  11.   /* 修改使用的秘钥 */" M4 [' o9 P8 j1 l6 x7 h
  12.   hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;
    1 ~6 g# u. m0 X! ?, @+ n! g

  13. . E: p' C5 T* [1 ^
  14.   /* 再次初始化 */
    ! T& j4 u  V: @
  15.   if (HAL_CRYP_Init(&hcryp) != HAL_OK)
    6 U) ]& i( d% W6 ^5 E3 |
  16.   {7 `6 e; h, E0 N" A# W9 o& e5 S
  17.     printf("HAL_CRYP_Init error\r\n");
    , L7 C6 C2 `3 I6 s0 W  ^( P3 g
  18.     Error_Handler();
    0 j3 l, c; X4 E% A& e, w9 k( u
  19.   }, u) D# D. Z+ \' ~
  20.   printf("\r\n");' w5 b  C4 ~, [9 z* y
  21. }
复制代码
15.png

. r3 }  q5 V* ?( X+ }8 H8 O4 `2 B, r/ M6 H3 K
然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功
  1.   change_key_to_user_defined_AesKey_128bit();
    1 A1 \: F) L% A! b! b

  2. ) I4 k* X( {: V- M
  3.   printf("AES ECB use user defined key 128Bit encrypt test\r\n");+ b0 u" O: |7 H, ?5 N$ {/ E
  4.   AES_encrypt_test(&AES_plainText[0]);/ T; D, P2 X/ C- m" }
  5.   printf("AES ECB use user defined key 128Bit dencrypt test\r\n");5 t+ ^5 q: s* z  J+ T3 _
  6.   AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码
16.png
编译下载运行效果如下
17.png
和在线工具对比一下,结果一致
18.png

: {5 ], s5 Z. ]8 B
2.2 AES CBC 128bit加解密测试
然后我们把AES模式切换至CBC模式,来进行测试
CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下
  1. /* AES CBC使用的IV */
复制代码
然后准备一下CBC加密后的结果的数组,回头给解密时使用
  1. /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */
    , j- ]2 a9 V5 _. B9 k
  2. uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
    6 O* R% r1 q2 t5 ~# S( b
  3. {, w; b0 r8 ^* h7 ~- A
  4.   0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E783- O# H5 W: Y1 T
  5. };
复制代码
19.png
写一下切换至CBC模式的函数
  1. void change_to_aes_cbc_mode(). j0 s  ^2 V2 o5 d$ Y( C
  2. {
    2 T' s4 H. l8 W9 {/ b( i+ D; h0 K
  3.   printf("change to AES CBC mode\r\n");
    * p5 F- V- f, ?# V
  4.   /* 先去初始化 */
    ) o5 G1 l6 b$ c6 p# ?
  5.   if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)
    ! H( q; {; H0 @
  6.   {
    4 f# d2 N0 M! G$ K! v7 f) X# _
  7.     printf("HAL_CRYP_DeInit error\r\n");& N# E  j$ g: @& _
  8.     Error_Handler();" I' |& b4 t* b0 L* {$ C
  9.   }
    " L5 b7 r' Q- U; }8 f
  10. 1 H, `8 m) S  ~. L3 L5 p
  11.   /* 修改为CBC模式 */
    6 `, B' L2 w6 f( Z
  12.   hcryp.Init.Algorithm = CRYP_AES_CBC;$ D5 X( t$ Y3 V! I" s5 G' O
  13.   /* 设置IV */: k. I: A4 @& `
  14.   hcryp.Init.pInitVect  = AES_CBC_IV;1 r7 f2 G( T# I
  15. 3 m; ?/ V$ |/ ]7 J
  16.   /* 再次初始化 */" }  b; a/ T  n+ t3 ?  c/ m  K9 J
  17.   if (HAL_CRYP_Init(&hcryp) != HAL_OK)
    4 X4 H# m  W: T7 c- O2 O7 t# i& C0 r
  18.   {4 a! _. T0 n. W& n" |7 b
  19.     printf("HAL_CRYP_Init error\r\n");
    9 [9 k1 p% _: z7 N9 k+ S
  20.     Error_Handler();* F0 y/ r: w' j. }9 X- v$ p
  21.   }/ P/ A' T) u% `. e
  22.   printf("\r\n");) K* L, G2 t+ b
  23. }
复制代码
20.png
在main中调用切换函数,然后进行CBC加解密测试
  1.   change_to_aes_cbc_mode();8 U. z/ ?' \2 _6 r. j% B$ e" f
  2. / }& Y4 r8 B; n. W
  3.   printf("AES CBC use user defined key 128Bit encrypt test\r\n");
    ( X" Q( P1 i2 x1 I. `  g
  4.   AES_encrypt_test(&AES_plainText[0]);
    2 H# X5 x: r) I( |! G
  5.   printf("AES CBC use user defined key 128Bit dencrypt test\r\n");/ F5 A" X  T: s/ z0 P) z
  6.   AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码
21.png
编译下载,结果如下
22.png
和在线工具对比一下,结果一致
23.png
三、总结
今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。

* p0 o, i; B; A$ t  J* S本次工程代码: STM32U0_AES_test.rar (5.21 MB, 下载次数: 5)
赞 1 收藏 评论2 发布时间:2024-5-10 22:52

举报

2个回答
STMCU-管管 回答时间:2024-5-11 09:03:52
赞,用心了; \8 N) J# E' R' M/ ?( F
Yude 回答时间:2024-5-22 16:55:14

好详细啊👍

所属标签

相似技术帖

官网相关资源

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