请选择 进入手机版 | 继续访问电脑版

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

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

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

3 ]0 ]8 r! S2 E8 j
一、cube配置
首先需要在cube中开启AES模块(工程就是上一篇中创建的模板工程)
- o; M/ S. a( e: W. R( {
参数这一块主要关注的是加密模式(Data encryption type)、秘钥长度(KeySize)、秘钥(Encryption/Decryption key),其他参数保持默认就可以
1.png
其中加密模式支持如下
2.png
秘钥长度支持128位、256
秘钥的值可以在cube中配置,也可以这里保持默认值,回头在代码中重新配置(当然上述的这些参数都可以通过代码再次配置,这个待会实战部分会有介绍)
1 U0 b# T4 D, Y! t- X4 j( x
最后点击右上角生成代码
3.png

, _) d+ Y% g- a2 I4 H& I7 y: u
二、实战
2.1 AES时钟初始化及函数介绍
先来看一下CUBE自动生成的代码
首先是变量
  1. CRYP_HandleTypeDef hcryp;) _4 v% Z" P3 A" _0 k
  2. uint32_t pKeyAES[4] = {0x00000000,0x00000000,0x00000000,0x00000000};
复制代码
6.png
这边的pKeyAES就是秘钥,和之前cube中设置的一致(下面的测试中我会尝试更换秘钥)
然后就是AES模块的初始化函数
  1. MX_AES_Init();
复制代码
7.png
4 V5 e) h; t/ i- h  q
8.png

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

0 q, A# Z, m  r" S5 v
在使用加密前,需要在main函数的最一开始就开启AES的时钟
  1. __HAL_RCC_AES_CLK_ENABLE();
复制代码
4.png

2 h3 G0 i/ O9 y/ u( j' X; S3 \
加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密
具体函数如下
  1. HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,8 t9 [3 n7 ?4 t) n5 A$ g
  2.                                    uint32_t Timeout);
    " U8 v3 \/ P' Z# h$ m7 _: m
  3. HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
    5 Z. K$ H- s( a9 }# @1 o
  4.                                    uint32_t Timeout);# o7 U8 @( [, E4 r7 v  }. b1 F
  5. HAL_StatusTypeDef HAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);9 [. j  q' ~' J% o
  6. HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
    " `9 S0 T) z( A( A2 I
  7. HAL_StatusTypeDef HAL_CRYP_Encrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
    % s2 J7 S( g  H1 B" j
  8. HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码
5.png

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

. @9 ?% W, y+ [( _; b
今天我们的测试的是最基础的阻塞加解密函数
7 ~3 J- I1 E/ v/ i7 r
2.2 AES ECB 128bit加解密测试
我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试
先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上
  1. /* 计算得到的秘文 */
    0 m: W& g; P$ T5 \5 a0 j5 S5 ^; V
  2. uint32_t Computed_Ciphertext[AES_DATA_SIZE];/ H( W- a# q" ]- w" _/ @
  3. /* 计算得到的明文 */
    - B0 Q7 e8 o# o/ H7 k, d
  4. uint32_t Computed_plainText[AES_DATA_SIZE];
    + {* G, F3 N2 x8 f5 L
  5. 8 C8 _5 v/ N+ I( `
  6. /* 用户自定义128bit秘钥 */
    $ E) B5 Z; R9 Q* ]- \
  7. uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =& A/ t9 v6 S. n4 S: E* Y  H- z2 ~
  8. {
    - B6 Q9 h) g: }8 n& Z% h/ y
  9.   0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff$ x7 v' }1 d- s0 [, N
  10. };
    % H8 [4 i: @) g! _
  11. /* 加密前的明文 */& ^/ j) U$ v$ n# N' C5 S+ E' _
  12. uint32_t AES_plainText[AES_DATA_SIZE] =' X/ Q! i' F- V( {
  13. {
      d/ \  g- Z2 z9 i0 E
  14.   0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f: m* ]% W  k! f( B
  15. };
    & {" z4 Z; N" ~0 h- \3 X( ~
  16. - c" d( w! M+ V5 n" j/ z
  17. /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */
    9 T2 e1 q2 b. E8 q0 h8 Z2 E* A
  18. uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =" [5 _1 ~& W- s' ~6 |. O4 x8 u
  19. {9 C( H8 P5 e) z  j' F( x2 X
  20.   0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE0034 _' i1 L; T8 o! d# V4 M
  21. };3 s0 R. @& y$ B$ N# w
  22. /* AES ECB使用cube默认128bit秘钥加密后的秘文 */
    6 R' r  G4 X9 a
  23. uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =
    # f, ~) [3 U' A
  24. {) W! q$ y& N; I2 F  }" D
  25.   0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A282
    - K& c' _6 X9 M
  26. };
复制代码
9.png
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的
1 d! N9 ?# L  @8 v
然后在加一下宏定义
  1. /* AES加解密阻塞式函数超时时间 */9 p$ ?7 n2 n: D! U* D
  2. #define AES_TIMEOUT_VALUE 0xFF  //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说
    " f5 g( [: r8 R! ^; T/ L
  3. /* AES加解密数据的长度(byte) */1 e' r; L$ l- O. d5 Y
  4. #define AES_DATA_SIZE_BYTE 16
    ! V3 _& h8 Y9 [+ c
  5. /* AES加解密数据的长度(uint32_t) */
    + d3 E9 x4 P; n/ m% M9 g" P& h  e
  6. #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4)
    $ J6 C- N0 O' U
  7. /* AES加解密秘钥的长度(bit) */
    2 O7 Z2 e7 S- t
  8. #define AES_KEY_SIZE_BIT 1285 t$ S* V, b2 [3 F" {/ P: ^
  9. /* AES加解密数据的长度(uint32_t) */! U1 }- U$ K9 O% \7 ?; @) y* ~
  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)
    + v( e6 F6 v. g: d! s
  2. {9 j$ G$ W, ?; x  n; y
  3.   for (uint8_t i = 0; i < Size; i++)  ]% X: r+ M6 n& H/ ~
  4.   {. R* G$ \$ V+ D2 E2 e4 H9 I
  5.     printf("%02X ", ((*pData & 0xFF000000) >> 24));  [5 I( ^/ g& d& c6 F# |0 J/ t
  6.     printf("%02X ", ((*pData & 0x00FF0000) >> 16));6 d, x2 z4 @! u1 u4 v" ?3 l
  7.     printf("%02X ", ((*pData & 0x0000FF00) >> 8));; H1 B7 `2 I" N. W+ v& C) Q
  8.     printf("%02X ", ((*pData & 0x000000FF)));
    7 `1 Y+ w8 J% x) T- m5 F- |
  9.     pData++;/ _2 }0 }+ ~3 G
  10.   }
    % E/ I' p7 L, T, _3 H
  11.   printf("\r\n");
    7 F, }5 }8 n: F
  12. }
    9 a3 J: M0 K8 i' E6 @

  13. ) e) A& j! b8 ?! E$ d7 n9 g) C
  14. void AES_encrypt_test(uint32_t *plainText)
    ) r. L# j; A( {( b9 k8 P
  15. {
    7 k* y: R. ~9 W% e( J  M
  16.   printf("plainText = ");
    $ Z* U2 |1 E. u( d
  17.   dump_data(plainText, AES_DATA_SIZE);# y3 A1 G+ [' S
  18. # ~. V# ?$ U9 Q& f: @
  19.   if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK)
    ) I) f2 ^- J- r2 s. I7 M9 h" x" a
  20.   {5 F% M6 K# M6 ~6 `4 u
  21.     printf("AES encrypt success\r\n");, W3 z* x1 H7 i+ q: u; v
  22.     printf("Computed_Ciphertext = ");" ]( N2 k3 \0 M! p: f) S) Y3 T0 j
  23.     dump_data(Computed_Ciphertext, AES_DATA_SIZE);
    0 f* s5 P+ ?9 N( P3 A
  24.   }& m0 m$ x/ F( v( l4 s
  25.   else, d* Q9 k, a0 [) i. Q
  26.   {% J- C& q7 Z! {9 c/ o; y0 w
  27.     printf("AES encrypt error\r\n");
    ; F& D8 p) ~; {: h' i+ t: x
  28.     Error_Handler();# E0 E/ i- D0 W9 B! h1 L
  29.   }7 B# g! o7 Z1 B  P4 p7 B. C6 ~. D% h
  30.   printf("\r\n");
    ( s2 {/ I" y9 ]  V( x: G6 I- y
  31. }! I$ w2 Y4 h8 M7 o
  32. : ], X& E* j2 @. C' U: h( H: o' X0 u  b
  33. void AES_dencrypt_test(uint32_t *cipherText)
    8 r8 B9 c* v) Q' y+ t) n0 k! F, ?9 ]
  34. {: M2 @% e. V! S0 |+ I, O
  35.   printf("cipherText = ");) G7 ?; F0 v0 o2 O
  36.   dump_data(cipherText, AES_DATA_SIZE);1 M. |" R9 o/ h2 A
  37. - u; @2 w7 D( ~" f
  38.   if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK)+ R, n8 f! z- V2 @9 {2 @
  39.   {. Y" ?, y; N6 m: z( H. [
  40.     printf("AES dencrypt success\r\n");* Z. ]+ s! A8 Y' E& c$ m
  41.     printf("Computed_plainText = ");% b" Y1 z. ^! V4 J6 l1 b
  42.     dump_data(Computed_plainText, AES_DATA_SIZE);, i$ \4 Y% M" g
  43.   }) ~6 W. K6 d4 @5 }. T/ ^
  44.   else4 \5 h8 B& r) N9 ?& Z
  45.   {- c# G0 l; t4 K; e; m5 M
  46.     printf("AES dencrypt error\r\n");& B( n* K: t3 `$ k6 H( x; z6 Y. ?
  47.     Error_Handler();
      _! X( r" |% G
  48.   }1 a( Q! X1 q$ |% H# `
  49.   printf("\r\n");
    ; \; e6 \2 g9 e3 H3 C1 |. T" h
  50. }
复制代码
11.png

. c4 ?! W2 d) x* n" H2 l) T; y6 {9 c# r7 j( F  y
然后在main中调用
  1.   printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");
    7 c/ e1 y! _  H5 {
  2.   AES_encrypt_test(&AES_plainText[0]);
    / S  A0 U- E& M: e
  3.   printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n");
    6 D: R3 W2 s$ T' g% b( \( m
  4.   AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码
12.png
编译运行一下,结果如下
13.png
和在线工具对比一下,结果一致
14.png

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

6 W- R$ [( e) R; h, k
改变秘钥函数
  1. void change_key_to_user_defined_AesKey_128bit()
    9 f6 h$ A, D/ L: i
  2. {
    * f. A/ V$ n0 i6 Y9 Y, ]0 b
  3.   printf("change AES KEY to user_defined_AesKey_128bit\r\n");1 Y4 N, s# u6 d1 z0 l" ]. g' `
  4.   /* 先去初始化 */
    8 Y( z4 v, X, a. W7 |) l0 n
  5.   if (HAL_CRYP_DeInit(&hcryp) != HAL_OK): J0 ^# w6 a, O& s6 c6 l
  6.   {2 O3 K0 T) v" E, Z0 D; m
  7.     printf("HAL_CRYP_DeInit error\r\n");6 H2 r! {* Z( M8 w
  8.     Error_Handler();
    ( o* q% S  M% d4 |8 v' Z; z
  9.   }, r; ^6 T. p! E* ~" S, m7 ?
  10. ) Y  B) ~' x9 y! w: B5 o9 U2 M7 E
  11.   /* 修改使用的秘钥 */
    # f  U; Y% T4 Q$ j1 ]
  12.   hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;. @& o& Z7 c: t# z, \6 t  y

  13. 8 j: o1 x; G  {& L
  14.   /* 再次初始化 *// {# B  d' X" o% }: [
  15.   if (HAL_CRYP_Init(&hcryp) != HAL_OK)
    1 t4 Q( k! U6 a* q' e) E
  16.   {
    $ f  a  v. d% v/ S
  17.     printf("HAL_CRYP_Init error\r\n");% m2 y' |+ l5 \9 h2 _/ |
  18.     Error_Handler();
    , F* K8 k- H  z5 Q
  19.   }
    . I' i- R- D8 S% t8 I8 s
  20.   printf("\r\n");4 J  z* s, ]; Q0 O# R
  21. }
复制代码
15.png

  |( c3 ~8 L4 h7 Q: o' Z8 j! k! v% c% |& o! ?
然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功
  1.   change_key_to_user_defined_AesKey_128bit();, P# k" k# Y8 l6 {2 l
  2. + c6 Y' L# y. n3 V3 n
  3.   printf("AES ECB use user defined key 128Bit encrypt test\r\n");
    , ]% q7 G$ H# ?6 a' w
  4.   AES_encrypt_test(&AES_plainText[0]);
    . Q# @0 ^2 Y# n6 B* _. \
  5.   printf("AES ECB use user defined key 128Bit dencrypt test\r\n");4 i) g) q# A& K& n2 {4 L* e3 H
  6.   AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码
16.png
编译下载运行效果如下
17.png
和在线工具对比一下,结果一致
18.png
4 K! a2 H' q  X- J7 C
2.2 AES CBC 128bit加解密测试
然后我们把AES模式切换至CBC模式,来进行测试
CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下
  1. /* AES CBC使用的IV */
复制代码
然后准备一下CBC加密后的结果的数组,回头给解密时使用
  1. /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */
    9 H5 B/ G  k6 }5 C$ e2 F6 B9 A
  2. uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
    6 q6 q2 R& v3 j) x
  3. {
    6 e: z: H9 f) K- I$ U
  4.   0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E7831 b7 J" i- T+ q3 K
  5. };
复制代码
19.png
写一下切换至CBC模式的函数
  1. void change_to_aes_cbc_mode()! B' u$ d3 O" l; J
  2. {
    - o* W* m1 r5 Q, F, |
  3.   printf("change to AES CBC mode\r\n");
    * W. m7 ]+ E! Q2 B! E2 b
  4.   /* 先去初始化 */6 F3 Y* m% |/ g" H: f
  5.   if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)5 e! d4 ~1 O' m
  6.   {
    ; K9 E& \( b, T8 F% ]/ G! x
  7.     printf("HAL_CRYP_DeInit error\r\n");4 J* S0 F7 z3 D! t  J$ W1 {- d
  8.     Error_Handler();0 C  k( a2 X- A0 d+ P
  9.   }" G. E/ e2 R- v& `
  10. 7 ^6 b6 H( Z3 c( Q9 V2 C" i
  11.   /* 修改为CBC模式 */5 P# l* G- i( b: a) b4 R
  12.   hcryp.Init.Algorithm = CRYP_AES_CBC;
    & s, q2 T8 z2 u4 ^
  13.   /* 设置IV */) o8 `8 \7 X# g7 p" h
  14.   hcryp.Init.pInitVect  = AES_CBC_IV;5 w7 h5 K- N  a- o2 Y. v' A
  15. 7 c2 O* n6 t9 Z' _) y: \, u6 i
  16.   /* 再次初始化 */: o' c# U4 n/ W1 C# J1 m' @
  17.   if (HAL_CRYP_Init(&hcryp) != HAL_OK)
    * B" Y2 n# u5 s
  18.   {
    1 i( b# L. q. d  d5 m
  19.     printf("HAL_CRYP_Init error\r\n");
    - U7 N  p6 F0 w- j8 _0 Z9 h
  20.     Error_Handler();- c+ z5 T! t8 x8 j4 l
  21.   }
    2 D; z+ E* \8 p. D
  22.   printf("\r\n");
    4 \! e, j4 m+ J
  23. }
复制代码
20.png
在main中调用切换函数,然后进行CBC加解密测试
  1.   change_to_aes_cbc_mode();
    1 f2 [' e/ ]* U2 t* i- Z, W
  2. # `/ C/ t( L7 T" `, `- C
  3.   printf("AES CBC use user defined key 128Bit encrypt test\r\n");
    6 s) Q9 N: K( ]; l: y: f
  4.   AES_encrypt_test(&AES_plainText[0]);! I  O# x& G8 G! b2 G1 j
  5.   printf("AES CBC use user defined key 128Bit dencrypt test\r\n");
    - p1 T! s3 E; T; C
  6.   AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码
21.png
编译下载,结果如下
22.png
和在线工具对比一下,结果一致
23.png
三、总结
今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。
5 v+ U6 u- F  `! M' R7 f
本次工程代码: STM32U0_AES_test.rar (5.21 MB, 下载次数: 1)
1 收藏 评论2 发布时间:2024-5-10 22:52

举报

2个回答
STMCU-管管 回答时间:2024-5-11 09:03:52
赞,用心了
1 l1 y4 [" r( N0 q# \. ]
Yude 回答时间:5 天前

好详细啊👍

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版