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

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

[复制链接]
小萝卜啦啦啦 发布时间:2024-5-10 22:52
STM32U08是带硬件AES加解密模块的,硬件加解密的最大优势就是快。
( u' G$ k) v2 A3 V# f2 _& L0 u+ f
一、cube配置
首先需要在cube中开启AES模块(工程就是上一篇中创建的模板工程)
% t- a8 ]. e( u$ n$ _6 z2 u
参数这一块主要关注的是加密模式(Data encryption type)、秘钥长度(KeySize)、秘钥(Encryption/Decryption key),其他参数保持默认就可以
1.png
其中加密模式支持如下
2.png
秘钥长度支持128位、256
秘钥的值可以在cube中配置,也可以这里保持默认值,回头在代码中重新配置(当然上述的这些参数都可以通过代码再次配置,这个待会实战部分会有介绍)
* F  ^* M% v% L, o0 y- Z/ p+ h
最后点击右上角生成代码
3.png
0 b; y8 [9 [7 o: U6 g6 q8 `
二、实战
2.1 AES时钟初始化及函数介绍
先来看一下CUBE自动生成的代码
首先是变量
  1. CRYP_HandleTypeDef hcryp;
    7 ]+ A! G  n. y4 g5 V$ k+ x) |% Y% P7 b: I
  2. uint32_t pKeyAES[4] = {0x00000000,0x00000000,0x00000000,0x00000000};
复制代码
6.png
这边的pKeyAES就是秘钥,和之前cube中设置的一致(下面的测试中我会尝试更换秘钥)
然后就是AES模块的初始化函数
  1. MX_AES_Init();
复制代码
7.png
3 W8 x8 b) F6 Z3 T! q
8.png
  R5 t1 ~5 H! g8 g' s
在初始化函数中可以看到,配置了各个参数,和cube中的一致。然后就是调用了初始化,秘钥、加密模式等就是在init时配置进去的,如果需要更换,那就要调用HAL_CRYP_DeInit(),修改配置参数,然后再调用HAL_CRYP_Init()(这个待会儿我也会尝试一下)

9 n3 A4 z+ D* S0 j" @* |5 L
在使用加密前,需要在main函数的最一开始就开启AES的时钟
  1. __HAL_RCC_AES_CLK_ENABLE();
复制代码
4.png
, j0 r4 ]* V* _4 P/ x% r4 \  w
加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密
具体函数如下
  1. HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,( N3 \6 {7 f/ u9 D' K
  2.                                    uint32_t Timeout);* `( ~$ @! _; M0 _' q  k% K
  3. HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,4 c! x$ P, R: q# E
  4.                                    uint32_t Timeout);* ]% R7 H6 r7 {: g
  5. HAL_StatusTypeDef HAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);# s3 P- ?8 d1 J, J
  6. HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);- w, w" x) S# W9 v
  7. HAL_StatusTypeDef HAL_CRYP_Encrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);% A: D! H! H' j; W7 L  F7 b
  8. HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码
5.png
( S6 M, q7 y/ C) d' i4 V5 D
这里我再插一嘴,AES是需要加解密数据为16字节的倍数才可以运行,如果你的不是16字节的倍数,那么就需要做一下填充,加解密接口是不提供填充的,需要自己实现

+ w+ _$ g% ^) F, i" _+ ]
今天我们的测试的是最基础的阻塞加解密函数

1 T( h! I4 P  H* c
2.2 AES ECB 128bit加解密测试
我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试
先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上
  1. /* 计算得到的秘文 */3 L6 ?3 J* p$ H: X( @
  2. uint32_t Computed_Ciphertext[AES_DATA_SIZE];$ B4 W% J5 K8 s/ `+ [: R1 M
  3. /* 计算得到的明文 */! j( t$ X5 @' Y% H! g& {& u
  4. uint32_t Computed_plainText[AES_DATA_SIZE];- n& _6 B0 G, E/ M# B" j0 n% i

  5. ' P' C; [; ?+ ]
  6. /* 用户自定义128bit秘钥 */; Y' ^; \3 {$ G: U3 p
  7. uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =
    1 p. |3 h6 l* @, ^/ d' Q0 g" E
  8. {
    ! Q; z" ?. L7 h" E5 y. V/ g6 E, z
  9.   0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff
    , J* P* G& J, N' m2 J( s
  10. };  X' z! m) w: E& Y# q
  11. /* 加密前的明文 */8 }2 N: d9 h, G- Q
  12. uint32_t AES_plainText[AES_DATA_SIZE] =
    3 a) B  p4 h  o: g3 D6 j% {+ s
  13. {
    ; D. U% O7 A/ [
  14.   0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f' t7 Q* U  M/ C3 f9 a% `, K% J/ c+ p
  15. };
    7 s5 J2 G9 M: }' t+ L

  16. ! v; k8 x. F4 ?
  17. /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */
    9 O- J) B  U/ X5 p: R! |: _3 M
  18. uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =4 B, E/ J3 w; e1 l5 e0 n
  19. {& E5 C/ a& s( v
  20.   0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE003  {; h& ^8 Y$ V+ W, \4 N
  21. };
    5 r" }* q  t3 f! H8 O; Z
  22. /* AES ECB使用cube默认128bit秘钥加密后的秘文 */+ ~$ ~/ B: V4 ~
  23. uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =* n' ~5 Y# u: L" @$ J' P  D8 O4 P
  24. {- ?9 l( ?9 U/ Q, I, z/ N0 Z
  25.   0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A2827 |/ L# y6 {# P3 V5 U  U0 L
  26. };
复制代码
9.png
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的
6 L+ S' p, J+ B
然后在加一下宏定义
  1. /* AES加解密阻塞式函数超时时间 */
    ( `/ ]$ u6 L) ]% V3 G
  2. #define AES_TIMEOUT_VALUE 0xFF  //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说: X; w8 d/ T, Z' q; B2 ~7 p
  3. /* AES加解密数据的长度(byte) */& w+ ]8 l/ [( l( \( a+ f$ c8 J
  4. #define AES_DATA_SIZE_BYTE 16( E: c# A3 O! L' w7 g$ g" o
  5. /* AES加解密数据的长度(uint32_t) */
    $ z, W  X8 S+ Z. t9 M3 [
  6. #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4)+ L- Y/ Q0 M" t) X
  7. /* AES加解密秘钥的长度(bit) */
    7 [2 m9 v# J. ?: i' Y
  8. #define AES_KEY_SIZE_BIT 128
    ! }- b. D  `) @
  9. /* AES加解密数据的长度(uint32_t) */
    $ [# N  M) m% Y% Z. m
  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)
    9 U+ q3 {% k7 X$ Q; E' [1 }9 ^
  2. {$ a/ g5 T* m5 x) d/ W0 \
  3.   for (uint8_t i = 0; i < Size; i++)
    3 O6 [  ?* B) z
  4.   {0 b( r2 }2 C1 x& _& T9 o
  5.     printf("%02X ", ((*pData & 0xFF000000) >> 24));
    2 ?" @% r/ t; i" z7 q
  6.     printf("%02X ", ((*pData & 0x00FF0000) >> 16));0 A* V0 J2 r4 h
  7.     printf("%02X ", ((*pData & 0x0000FF00) >> 8));
    + r# O) G- d1 Y7 f6 k5 ~7 ?% j7 m% o
  8.     printf("%02X ", ((*pData & 0x000000FF)));
    7 C3 B  P8 e: Y9 T! D" P
  9.     pData++;( |; _9 ^" n! u
  10.   }
    ' |8 j9 q! `/ L. D: W4 ?! A$ l' ]
  11.   printf("\r\n");
    0 y! p" q! S# z) [4 A- D
  12. }- V/ e% j2 e& `: @7 S
  13. , o# b  M0 C: g/ l& W- O3 M
  14. void AES_encrypt_test(uint32_t *plainText)8 f# R+ G+ n8 L. \# m5 r
  15. {
    4 H7 ?  H, O, V) J" h4 u( O
  16.   printf("plainText = ");
    0 v' H) N# R- `( C% M
  17.   dump_data(plainText, AES_DATA_SIZE);
    ) J# E( L  k, [9 E9 j. X

  18. 2 X; _. _: b; [# _% c& |
  19.   if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK). f5 `4 b- A9 V. j, O
  20.   {
    / W$ s% \" A! N3 {/ [. ?6 B; a
  21.     printf("AES encrypt success\r\n");  t1 W9 U1 r; u! [7 _- T+ Z
  22.     printf("Computed_Ciphertext = ");% b! d+ q( c, ~* R; t
  23.     dump_data(Computed_Ciphertext, AES_DATA_SIZE);
    8 x/ M( G- A1 L" l" w
  24.   }
    4 n) J+ D1 b$ ?2 g, {
  25.   else/ `+ O" p" ?, E* k  p) S
  26.   {+ ^$ K# }3 W. r2 \
  27.     printf("AES encrypt error\r\n");% N5 N  j& E) w6 y. O
  28.     Error_Handler();
    ' g% g, j8 n' d5 z! @
  29.   }# X4 U8 \; L* c& \
  30.   printf("\r\n");; X) P9 X# I# X$ [
  31. }4 `  ?. @9 Z" Y- J- ^5 O# r4 R

  32. " L/ R- v! b; D3 u/ {3 C! [# H7 n
  33. void AES_dencrypt_test(uint32_t *cipherText)! J. a, _" V8 ^8 A  c
  34. {
    ; X& H7 n$ D" b: Z$ T- E$ T! a
  35.   printf("cipherText = ");6 v( [* x' x) i- h
  36.   dump_data(cipherText, AES_DATA_SIZE);
    & s+ b, i% r! d1 c3 r' t( b
  37. 8 P4 k* H$ ]& h/ N
  38.   if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK)4 }8 c* g2 }7 K
  39.   {
    1 e/ }& p, l8 ~% w' J: L
  40.     printf("AES dencrypt success\r\n");
    + ?  e$ Z+ @' @
  41.     printf("Computed_plainText = ");
    ' {+ t1 g& {( Y5 j
  42.     dump_data(Computed_plainText, AES_DATA_SIZE);* F! q& o5 X* D5 l% ]4 T
  43.   }# M0 X: P; F1 A5 t9 S
  44.   else; Q- T+ B% S! l* V* d
  45.   {  D/ T+ u) L* f
  46.     printf("AES dencrypt error\r\n");
    + F5 B- F& }1 J2 W$ ?
  47.     Error_Handler();
    2 k$ _" N+ E: P3 G, H% g( u" y
  48.   }$ B# o9 f! {+ G8 E, c5 _& Z
  49.   printf("\r\n");
    - s% U/ K' n( r, Z: R$ g
  50. }
复制代码
11.png

- \  G8 D2 \( S1 O1 i! B+ k+ l6 ~6 t4 d' T6 K. Z: b" T2 ~
然后在main中调用
  1.   printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");2 u# W0 W( J$ i' |, y
  2.   AES_encrypt_test(&AES_plainText[0]);
    ) D$ A) {- R$ B
  3.   printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n");
    + c( f1 y1 Z+ E; a$ V# e' e
  4.   AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码
12.png
编译运行一下,结果如下
13.png
和在线工具对比一下,结果一致
14.png
1 Y9 [# \8 f" p2 Y( E: c: d
接下来尝试更换一下秘钥,再运行加解密
更换秘钥有2种方案,第一是直接对MX_AES_Init中的内容修改,但是因为这里是cube自动生成的,后续cube再生成一次就又变回去了。所以我选择方案二:去初始化,修改参数,再初始化。
1 p% m1 {7 x' `0 ], L+ f& u
改变秘钥函数
  1. void change_key_to_user_defined_AesKey_128bit()' V  g0 p, A; d5 V' K
  2. {; S0 @% m# a' X
  3.   printf("change AES KEY to user_defined_AesKey_128bit\r\n");6 R+ c) o' s: Q3 f7 ?  y# K
  4.   /* 先去初始化 */
    3 O2 k( N* r5 Y$ Y* f
  5.   if (HAL_CRYP_DeInit(&hcryp) != HAL_OK): C8 {- {) R% w9 t
  6.   {
    1 ~5 w- i! c* m/ s
  7.     printf("HAL_CRYP_DeInit error\r\n");/ f; k' q. H2 N5 a$ h
  8.     Error_Handler();
    . J+ F6 L; f5 p& ]; ?
  9.   }3 Y4 A, K7 c0 C" H+ m6 }
  10. , M# E  v$ v4 z9 r" Z- b# C+ l( h
  11.   /* 修改使用的秘钥 */
    + V5 _0 G1 D% D! h& M7 Z
  12.   hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;
    7 v& i$ ^* C" P7 z

  13. . E# L. R. L5 e9 G! p- @. S6 O
  14.   /* 再次初始化 */
    ( N! n1 Z& T! O* {  W
  15.   if (HAL_CRYP_Init(&hcryp) != HAL_OK)
    6 P. I& J3 ]  K8 Z  s: X
  16.   {9 y  x" ~6 J+ Y2 \9 n
  17.     printf("HAL_CRYP_Init error\r\n");
    / W; A7 b+ x+ x2 M, Q" d
  18.     Error_Handler();
    6 x$ a5 e: J( W
  19.   }% R6 R7 `9 c" p0 e
  20.   printf("\r\n");. n6 m6 \- A8 j
  21. }
复制代码
15.png
% `$ e) D( s5 `
1 S9 j, k1 ^3 X6 }( k5 ^
然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功
  1.   change_key_to_user_defined_AesKey_128bit();
    ! S6 G7 W. m. V
  2. 7 c  B, |/ ?- V# A' E
  3.   printf("AES ECB use user defined key 128Bit encrypt test\r\n");
    9 W) `$ g: |: C
  4.   AES_encrypt_test(&AES_plainText[0]);1 U5 q# Y6 D4 I: j
  5.   printf("AES ECB use user defined key 128Bit dencrypt test\r\n");
    $ k; p% U3 P2 h& h; S7 I* p9 s* ?
  6.   AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码
16.png
编译下载运行效果如下
17.png
和在线工具对比一下,结果一致
18.png
$ ?8 i" ?% I  h, p. j( q
2.2 AES CBC 128bit加解密测试
然后我们把AES模式切换至CBC模式,来进行测试
CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下
  1. /* AES CBC使用的IV */
复制代码
然后准备一下CBC加密后的结果的数组,回头给解密时使用
  1. /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */
    4 b8 m3 Z6 t( O2 d( Y
  2. uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =/ Y. `& n' j) @+ w$ V
  3. {
    * S3 ^" a" _: t
  4.   0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E783/ m/ |" [8 \( V: l6 L# J
  5. };
复制代码
19.png
写一下切换至CBC模式的函数
  1. void change_to_aes_cbc_mode()
    / J9 C" \0 u. T  c, n  `9 j
  2. {
    0 U. O& j/ z4 M* T' ]- @
  3.   printf("change to AES CBC mode\r\n");
    , e5 }* s& c% H% |( e8 ]* P7 N0 `7 x
  4.   /* 先去初始化 */: }" p5 x( o  T0 d. a+ S
  5.   if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)1 C# D; M, V5 l# D# L( r: w* Z5 |
  6.   {
    ' b2 \4 \% O8 {+ G4 z1 B  e
  7.     printf("HAL_CRYP_DeInit error\r\n");9 ]3 W+ C5 Y$ W; L$ Q8 F$ N
  8.     Error_Handler();
    5 f9 {6 |3 E% Y1 a. y
  9.   }
    , G  K0 ]0 l2 s6 Q  x# M
  10. 8 Q+ H! x/ M3 @  H
  11.   /* 修改为CBC模式 */  r* F- T; l! z& s- l2 y# g
  12.   hcryp.Init.Algorithm = CRYP_AES_CBC;: n* H$ ?( N* u2 S& Z7 E) i1 l8 w
  13.   /* 设置IV */
    1 ^. s* b& z& i+ [* @8 O7 u
  14.   hcryp.Init.pInitVect  = AES_CBC_IV;3 N5 \& c5 y2 \

  15.   G& i8 [4 x7 i$ j0 D, x6 E
  16.   /* 再次初始化 */+ Y4 r$ J, K" i7 q1 n
  17.   if (HAL_CRYP_Init(&hcryp) != HAL_OK)+ o3 K4 z: q5 g6 |" ]2 e
  18.   {
    5 G4 x: ?6 O/ O
  19.     printf("HAL_CRYP_Init error\r\n");; T0 b1 H* D2 l: D6 G
  20.     Error_Handler();, X8 N. }3 ~* p9 l+ o
  21.   }
    ) v3 h( O7 I' b
  22.   printf("\r\n");% X! v3 C' ^5 W: H! `+ W1 u+ `+ c
  23. }
复制代码
20.png
在main中调用切换函数,然后进行CBC加解密测试
  1.   change_to_aes_cbc_mode();
    9 I4 V$ S3 _  S" K3 q% k
  2. 8 ]: ], n  W1 A: B0 @" p# b0 w
  3.   printf("AES CBC use user defined key 128Bit encrypt test\r\n");7 P2 |2 H. V  W9 O
  4.   AES_encrypt_test(&AES_plainText[0]);
    5 q8 q$ Y% Q1 ?& ~
  5.   printf("AES CBC use user defined key 128Bit dencrypt test\r\n");
    # k' T. Y; Z5 ?& U" I5 d
  6.   AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码
21.png
编译下载,结果如下
22.png
和在线工具对比一下,结果一致
23.png
三、总结
今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。
; S/ b( J# y0 n: V1 U) L
本次工程代码: STM32U0_AES_test.rar (5.21 MB, 下载次数: 5)
1 收藏 评论2 发布时间:2024-5-10 22:52

举报

2个回答
STMCU-管管 回答时间:2024-5-11 09:03:52
赞,用心了9 c9 T3 h" o  w* J1 g  B8 l2 _$ y
Yude 回答时间:2024-5-22 16:55:14

好详细啊👍

所属标签

相似技术帖

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