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

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

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

. k8 @; T+ ^; e& G( b
一、cube配置
首先需要在cube中开启AES模块(工程就是上一篇中创建的模板工程)

, L5 A' w$ ?$ b4 B: h! z
参数这一块主要关注的是加密模式(Data encryption type)、秘钥长度(KeySize)、秘钥(Encryption/Decryption key),其他参数保持默认就可以
1.png
其中加密模式支持如下
2.png
秘钥长度支持128位、256位
秘钥的值可以在cube中配置,也可以这里保持默认值,回头在代码中重新配置(当然上述的这些参数都可以通过代码再次配置,这个待会实战部分会有介绍)
  V, m  z  v+ M5 J9 k& G! j# j
最后点击右上角生成代码
3.png

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

) L# i+ K) L7 O
8.png

7 P0 m! J/ F0 ~, e2 K
在初始化函数中可以看到,配置了各个参数,和cube中的一致。然后就是调用了初始化,秘钥、加密模式等就是在init时配置进去的,如果需要更换,那就要调用HAL_CRYP_DeInit(),修改配置参数,然后再调用HAL_CRYP_Init()(这个待会儿我也会尝试一下)
7 w+ o) N. {6 [- @
在使用加密前,需要在main函数的最一开始就开启AES的时钟
  1. __HAL_RCC_AES_CLK_ENABLE();
复制代码
4.png

: t3 k' v. B, }6 @% R
加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密
具体函数如下
  1. HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
      R. h  K4 b& K" k* I0 \
  2.                                    uint32_t Timeout);
    " ^0 z) `- r  ?7 u& a6 n# i& d. I
  3. HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
    5 G3 R) ?" D8 _
  4.                                    uint32_t Timeout);
    . N# q8 q9 X' G5 \
  5. HAL_StatusTypeDef HAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);2 E* |$ Y5 ?0 X8 q6 X
  6. HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);+ ~' M; K# ^2 e3 p. F
  7. HAL_StatusTypeDef HAL_CRYP_Encrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
    8 y. Y1 g3 x1 }6 h4 D1 b1 a
  8. HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码
5.png
, o' p1 C. j! Q" n  C- U1 N1 w
这里我再插一嘴,AES是需要加解密数据为16字节的倍数才可以运行,如果你的不是16字节的倍数,那么就需要做一下填充,加解密接口是不提供填充的,需要自己实现

) t: g, g. j- _- _
今天我们的测试的是最基础的阻塞加解密函数

2 e: z$ C2 g7 X$ O* C0 P% Z
2.2 AES ECB 128bit加解密测试
我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试
先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上
  1. /* 计算得到的秘文 */
    8 s" o/ I, k8 f0 Q& m. n1 e( U1 E( d# o
  2. uint32_t Computed_Ciphertext[AES_DATA_SIZE];
    0 J: P2 R# Z! \# t
  3. /* 计算得到的明文 */" J! Z* k- z; S3 h
  4. uint32_t Computed_plainText[AES_DATA_SIZE];5 d' U' j8 _$ V  {: N

  5.   y% `. u6 G& Y$ ~, A0 B
  6. /* 用户自定义128bit秘钥 */
    ! e. A( y  Z$ d& J, I, F' {& q
  7. uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =
    ! A/ ?; K2 ~6 c9 V4 m
  8. {, ]# D1 N( o/ I+ z1 Q
  9.   0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff' D+ W% z/ @! I  Z4 U5 B- [
  10. };1 n7 L9 z" w' ^/ }
  11. /* 加密前的明文 */1 C2 y# w) a6 W1 w% ~2 r! G
  12. uint32_t AES_plainText[AES_DATA_SIZE] =
    , }! v2 t, m# w' K6 w" _
  13. {
    5 H* X" A! D4 j
  14.   0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f' R1 @* v$ ^+ E0 n3 W5 i( ?
  15. };* u* _& K5 G( r- |) G+ S

  16. 0 ^1 K  h6 f' T0 N. D8 q5 [& u
  17. /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */3 D; ]2 J+ Q* f7 ?8 H; f% F
  18. uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
    6 H+ {; o/ _; X6 ~2 _% L% f
  19. {
    ! e* ]2 j3 ]0 O1 v" y) g8 k* `
  20.   0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE003
    5 q6 U1 Y0 X/ G5 A# s/ s
  21. };2 ?  F6 x' ~; O  x' D( G
  22. /* AES ECB使用cube默认128bit秘钥加密后的秘文 */
    5 d- ^+ A. `5 Y  t
  23. uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =
    + B* ^4 X# G6 j
  24. {; D- p2 a- ^& Q# f
  25.   0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A282
    2 e% P6 j( @# P7 N5 w3 B% z
  26. };
复制代码
9.png
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的

4 G! J( ?4 H, {: j
然后在加一下宏定义
  1. /* AES加解密阻塞式函数超时时间 */. o  h2 d$ @# k- j
  2. #define AES_TIMEOUT_VALUE 0xFF  //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说3 u/ W' }8 ~( [2 p3 {: D5 Y8 `
  3. /* AES加解密数据的长度(byte) */8 h9 r/ A) |) D5 i& B
  4. #define AES_DATA_SIZE_BYTE 16
    " M3 F9 q: l9 G$ a1 H
  5. /* AES加解密数据的长度(uint32_t) */
    1 O2 }! S( L3 o; c* P$ C6 U
  6. #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4)) d2 p+ f% K  j
  7. /* AES加解密秘钥的长度(bit) */4 F1 _9 a) ~  ~2 j  _  s8 a
  8. #define AES_KEY_SIZE_BIT 128
    " c; u' N! n2 S2 }( P3 H  f
  9. /* AES加解密数据的长度(uint32_t) */
    0 C" v9 E+ ]) S' ]4 }' z$ d
  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)* C% e$ J( e  I# i2 ?0 j" V( {  M
  2. {
    # c, T4 u0 v: j0 _8 {
  3.   for (uint8_t i = 0; i < Size; i++)
    % X4 ?; @: l, {9 n9 E. D9 t% B% s
  4.   {! Q# m) C& D9 v( T0 N. l9 L
  5.     printf("%02X ", ((*pData & 0xFF000000) >> 24));* [9 ~# `  J1 @
  6.     printf("%02X ", ((*pData & 0x00FF0000) >> 16));
    ) n, [$ P9 Z% W( p5 G) M) [
  7.     printf("%02X ", ((*pData & 0x0000FF00) >> 8));
    - v& J) p/ h+ n7 J. i4 B: {; C
  8.     printf("%02X ", ((*pData & 0x000000FF)));" C  j" n- i0 L% ^
  9.     pData++;
    * x/ f, S3 v' _' u! s
  10.   }
    ) t9 r# P7 {) c/ l0 Y
  11.   printf("\r\n");
    - y: U3 }* W. T" {5 n2 {( H5 ]
  12. }7 N. z3 f! e) s) Z* q
  13. - X: ~& z! s  w/ ~5 A5 [/ c
  14. void AES_encrypt_test(uint32_t *plainText)' g; R' f% Y: y9 Y: F
  15. {! j" `  o7 M  T+ V$ Z/ l% _) o
  16.   printf("plainText = ");
    6 C$ R3 ^8 b( ^4 B" o5 E7 R3 n
  17.   dump_data(plainText, AES_DATA_SIZE);: d0 m# t$ |# E! k. L9 B
  18. 1 p8 V$ |$ w, d5 i, u" k) {, v
  19.   if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK)- p: _0 E, \2 q8 z
  20.   {
    ) W% y" X, i/ H* D* ?  {
  21.     printf("AES encrypt success\r\n");
    / D* Y% f1 L; u/ r; A
  22.     printf("Computed_Ciphertext = ");
    0 \6 A, V" R; `/ T, @+ }6 U
  23.     dump_data(Computed_Ciphertext, AES_DATA_SIZE);
    : W" g/ U# d# p- F0 J
  24.   }
    ' ?& z# D7 b% }7 l1 B, h% _
  25.   else- ^* T, M4 n" N" A
  26.   {
    # W8 ]5 H; `4 {# @: K
  27.     printf("AES encrypt error\r\n");. I; f# ?, z4 c8 n  V8 `- y/ M
  28.     Error_Handler();3 I7 ?- N" _. e+ L
  29.   }2 E5 i. y4 `) Q- z
  30.   printf("\r\n");
    ( G- U9 _& F) d' n2 d) [
  31. }6 [0 e4 h2 L# u( @) ]. O
  32. ' U# M; `9 Y/ H
  33. void AES_dencrypt_test(uint32_t *cipherText)
    7 R8 ?$ E+ J2 t
  34. {" i) a' g( B1 P3 x' |' A$ X
  35.   printf("cipherText = ");
    + Z' r7 Y& e4 b2 c
  36.   dump_data(cipherText, AES_DATA_SIZE);: N5 i, O) ^* y9 D  _
  37. ' G9 g1 T0 c9 h- z/ D
  38.   if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK); P: i  J, |& {& ]% k4 {8 I$ S
  39.   {* n2 s8 h% \6 Q  R3 A4 }7 D
  40.     printf("AES dencrypt success\r\n");
    ) w5 Q& J2 t2 t# Z; Q, z5 g
  41.     printf("Computed_plainText = ");
    1 n8 z0 v' f, x# g, j
  42.     dump_data(Computed_plainText, AES_DATA_SIZE);. z1 S: x: ?, ~+ k$ U$ S! C
  43.   }
    / a5 k+ u# _7 A$ n, {
  44.   else
    * p6 O. P- \. P7 T
  45.   {
    * X/ j% W( F! q  j9 _& U
  46.     printf("AES dencrypt error\r\n");( P' Y$ S1 ^; n: g5 R. r3 Z" o5 y' d
  47.     Error_Handler();
    9 K7 m- P( p9 J/ A! A3 d4 {
  48.   }$ Z. ^, p4 W' c# C/ j
  49.   printf("\r\n");; r* Z( e: o% _9 b& m
  50. }
复制代码
11.png

- V% @7 h; J5 ~$ j4 a: F, F, [% v- |. u
然后在main中调用
  1.   printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");
    ( R) X6 t8 e& A% D" u. {) O
  2.   AES_encrypt_test(&AES_plainText[0]);$ \" ?. H9 Y4 p. b  v
  3.   printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n");
    * B9 k% d2 {$ z- Y# s! ]
  4.   AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码
12.png
编译运行一下,结果如下
13.png
和在线工具对比一下,结果一致
14.png

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

( A" B1 s% g. l" o
改变秘钥函数
  1. void change_key_to_user_defined_AesKey_128bit()
    ! J1 G3 j* x- e' _9 T' }
  2. {: }/ ]7 y" p4 d6 Y! C9 H: }. M4 p
  3.   printf("change AES KEY to user_defined_AesKey_128bit\r\n");
    ; z4 e+ Y3 Z( X1 k+ c
  4.   /* 先去初始化 */5 M& B" l1 {* O6 I7 ?. o; [
  5.   if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)+ q" k3 c* d5 [, d, D% F
  6.   {3 y' ~" r6 B7 ~4 S. b
  7.     printf("HAL_CRYP_DeInit error\r\n");
    3 z  z; t6 f  E1 O5 m$ K' E
  8.     Error_Handler();3 J  u% m; T' I- Z1 D5 I
  9.   }8 |: A  X% v- I% j
  10. 5 Q. {, _# i' Z& V( T1 Y( s+ H
  11.   /* 修改使用的秘钥 */( ~4 X& B8 I( W, O6 f1 `" H
  12.   hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;
    * L" J. w; j5 H
  13. 1 X7 _& n; s  f" {
  14.   /* 再次初始化 */
    9 H' @- |, L2 j# f2 E
  15.   if (HAL_CRYP_Init(&hcryp) != HAL_OK)
    & Y" q6 r/ Q2 N; S& J
  16.   {7 a+ \4 }0 M( q3 f0 d
  17.     printf("HAL_CRYP_Init error\r\n");2 H: ^0 Z! {; c6 I3 {$ F: ]
  18.     Error_Handler();
    " d6 j7 `& K- X' ?) m' m
  19.   }
    3 K( _1 h  q! t$ D9 p
  20.   printf("\r\n");& _" h) L. g: z# x* G
  21. }
复制代码
15.png
; e3 t4 ]8 ^4 n1 X& K5 o3 F
. i" G: `0 G+ z4 w2 w9 E
然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功
  1.   change_key_to_user_defined_AesKey_128bit();1 m8 w( U" o7 d4 k) }+ x% x& x8 L
  2. 7 u9 t4 k' s4 Z! U: N' D
  3.   printf("AES ECB use user defined key 128Bit encrypt test\r\n");
    . Y+ b5 u$ ?1 q1 n8 ~
  4.   AES_encrypt_test(&AES_plainText[0]);
    * l% J& |( V( j$ e" d0 P
  5.   printf("AES ECB use user defined key 128Bit dencrypt test\r\n");/ z5 w4 L- o- ~& G' N, e9 m
  6.   AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码
16.png
编译下载运行效果如下
17.png
和在线工具对比一下,结果一致
18.png

! K2 D' |: K1 Q$ o2 ]3 H5 X
2.2 AES CBC 128bit加解密测试
然后我们把AES模式切换至CBC模式,来进行测试
CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下
  1. /* AES CBC使用的IV */
复制代码
然后准备一下CBC加密后的结果的数组,回头给解密时使用
  1. /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */- ^$ }% d) N( x3 H' [+ z5 T% A, I+ S
  2. uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
    $ i7 E  U# e: l8 `+ H* H
  3. {
    % i. y0 I2 n' J
  4.   0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E783
    + {( N' J) b$ A) E- \
  5. };
复制代码
19.png
写一下切换至CBC模式的函数
  1. void change_to_aes_cbc_mode()
      V  ?  M  S, {, O8 s1 q
  2. {; w/ x& d+ @8 H. H! i' ?
  3.   printf("change to AES CBC mode\r\n");
    1 ?& b" L$ ~6 n& [
  4.   /* 先去初始化 */
    ( O, T+ W8 B1 m  c
  5.   if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)- @- H# J- ~, R: H0 o: R2 O$ R! n
  6.   {
    8 F3 F- [6 a  n  Q+ h1 U
  7.     printf("HAL_CRYP_DeInit error\r\n");
    : c6 F# y) ?7 ]- J! }9 k! A9 }4 w
  8.     Error_Handler();
    & r& X' s% w3 m% I8 V' s4 @
  9.   }
    ) `/ B/ ], l( n$ b5 l& P, n

  10. # j7 W# ]7 V5 J, l' f
  11.   /* 修改为CBC模式 */
    5 d, w) e$ {! U1 Z% X4 l
  12.   hcryp.Init.Algorithm = CRYP_AES_CBC;
    2 U6 F' k5 b3 i
  13.   /* 设置IV */
    7 Y3 k6 z! J- h. ^% x6 {- O
  14.   hcryp.Init.pInitVect  = AES_CBC_IV;
    7 c: `7 i- d" G1 z3 f7 w
  15. : G% n( R* y" R" G* X% j8 B
  16.   /* 再次初始化 */8 Y$ J/ z; \) ?0 F/ Z3 g1 b. ]
  17.   if (HAL_CRYP_Init(&hcryp) != HAL_OK)0 Q, e! N: y) H: J  U" r
  18.   {( L. t/ t0 m) d
  19.     printf("HAL_CRYP_Init error\r\n");
    : O2 t/ q9 B3 \( V
  20.     Error_Handler();
    9 e: e) m, `" L
  21.   }
      S- I" l0 y6 {6 O- v7 A9 U  K
  22.   printf("\r\n");, s& S  `9 M" e+ _" U
  23. }
复制代码
20.png
在main中调用切换函数,然后进行CBC加解密测试
  1.   change_to_aes_cbc_mode();
    3 t8 U1 E$ l! g; Z6 ~3 w; [
  2. * }) I' j; D) y- u
  3.   printf("AES CBC use user defined key 128Bit encrypt test\r\n");# }# Z3 r3 [+ u+ J! D
  4.   AES_encrypt_test(&AES_plainText[0]);
    . A9 Z; w, r9 g7 C0 R
  5.   printf("AES CBC use user defined key 128Bit dencrypt test\r\n");( k) k  d' w5 a9 ]* G  ^
  6.   AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码
21.png
编译下载,结果如下
22.png
和在线工具对比一下,结果一致
23.png
三、总结
今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。
3 L, b8 ?4 R; J5 E) P' Q0 t
本次工程代码: STM32U0_AES_test.rar (5.21 MB, 下载次数: 5)
赞 1 收藏 评论2 发布时间:2024-5-10 22:52

举报

2个回答
STMCU-管管 回答时间:2024-5-11 09:03:52
赞,用心了
  E5 u& q" @( A, u0 `; T8 a8 I7 p
Yude 回答时间:2024-5-22 16:55:14

好详细啊👍

所属标签

相似技术帖

官网相关资源

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