STM32U08是带硬件AES加解密模块的,硬件加解密的最大优势就是快。
6 z5 S5 c' S" j3 @ e一、cube配置 首先需要在cube中开启AES模块(工程就是上一篇中创建的模板工程)
1 @# h% n1 q6 ?" ~+ Q* u参数这一块主要关注的是加密模式(Data encryption type)、秘钥长度(KeySize)、秘钥(Encryption/Decryption key),其他参数保持默认就可以 其中加密模式支持如下 秘钥长度支持128位、256位 秘钥的值可以在cube中配置,也可以这里保持默认值,回头在代码中重新配置(当然上述的这些参数都可以通过代码再次配置,这个待会实战部分会有介绍)
1 Q/ B0 S/ R2 \5 B最后点击右上角生成代码 . R: J9 F+ c+ R" d* l: r
二、实战 2.1 AES时钟初始化及函数介绍 先来看一下CUBE自动生成的代码 首先是变量 - CRYP_HandleTypeDef hcryp;% I. s5 C4 L* Y3 m+ g- ^
- uint32_t pKeyAES[4] = {0x00000000,0x00000000,0x00000000,0x00000000};
复制代码这边的pKeyAES就是秘钥,和之前cube中设置的一致(下面的测试中我会尝试更换秘钥) 然后就是AES模块的初始化函数 * G4 @4 N! l r& o4 e
3 x: J% q& s( w3 A2 x' g% \在初始化函数中可以看到,配置了各个参数,和cube中的一致。然后就是调用了初始化,秘钥、加密模式等就是在init时配置进去的,如果需要更换,那就要调用HAL_CRYP_DeInit(),修改配置参数,然后再调用HAL_CRYP_Init()(这个待会儿我也会尝试一下)
! S- i1 I* {. u/ T在使用加密前,需要在main函数的最一开始就开启AES的时钟 - __HAL_RCC_AES_CLK_ENABLE();
复制代码 % \ p2 v: `9 h
加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密 具体函数如下 - HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,- q0 |; {" _3 F" x
- uint32_t Timeout);, s( C1 I3 K# V& x2 _
- HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,( K0 v- D% W* R7 A- u
- uint32_t Timeout);
6 ^' C5 L2 S* _. T6 a# ~ - HAL_StatusTypeDef HAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);4 ]" f7 h, i1 j7 c5 F
- HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);9 Q# M- @2 [$ b* S! U) t' D: A
- HAL_StatusTypeDef HAL_CRYP_Encrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
( M1 b" U9 |1 y - HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码
; M5 q/ W- A3 J0 a. k这里我再插一嘴,AES是需要加解密数据为16字节的倍数才可以运行,如果你的不是16字节的倍数,那么就需要做一下填充,加解密接口是不提供填充的,需要自己实现
; f- N2 X/ @$ U. S, [, ~, m今天我们的测试的是最基础的阻塞加解密函数
: ]- k* B" w. E/ W5 r- V7 X2.2 AES ECB 128bit加解密测试 我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试 先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上 - /* 计算得到的秘文 */
& i3 s3 ]7 I# \! ]8 n! F1 e s - uint32_t Computed_Ciphertext[AES_DATA_SIZE];
5 m3 p _- |& Q; f1 b4 ~# V" g6 ? - /* 计算得到的明文 */1 l/ ]' |. Z) ~1 Q( P8 |
- uint32_t Computed_plainText[AES_DATA_SIZE];
& P! D1 i+ Z6 X1 h; a - ( F+ }' I& J& l! j: p
- /* 用户自定义128bit秘钥 */# X& A+ H3 Z, o, Q+ H
- uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =
0 y& l' q: D; \+ ^; r - {
' j! c. ?1 J7 P1 h0 h4 G - 0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff
) r6 M c4 X0 A. _" {6 v - };- e; H c$ D' M0 v: a1 m
- /* 加密前的明文 */
; S- ~" {2 p8 m* t( _: O( I, T) p - uint32_t AES_plainText[AES_DATA_SIZE] =+ u6 w( v, t/ ]% D, T
- {
9 I( J% \$ u R4 Q - 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f; ?1 `8 t/ Y7 a) Y3 i8 G
- };
$ {) f' T/ p% K1 a' b* D* \
' P* a( W; Q9 R+ B" _" g! [* S! o- /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */
) ~& z/ f$ Q) d$ b/ S - uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =# k% F6 b- }$ v# d1 G
- {/ h, D* t7 u, j
- 0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE003
' z# g) @, X1 q6 y3 ?% \4 E, A - };
H! o' b& ^6 ?: W! _ - /* AES ECB使用cube默认128bit秘钥加密后的秘文 */
2 u1 e9 J5 s$ f$ S5 \ - uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =
; W1 v, o6 D/ A& \0 | - {
4 V' ~( ^4 x: I" e - 0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A282. x1 l, Z; v- l A2 w5 F# N# {
- };
复制代码
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的 5 N9 q0 f$ [) J( _7 b. E+ C
然后在加一下宏定义 - /* AES加解密阻塞式函数超时时间 */
+ a8 l7 }0 h' @ - #define AES_TIMEOUT_VALUE 0xFF //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说- \- H0 H5 j7 B/ S" ?
- /* AES加解密数据的长度(byte) */
4 P0 U" q' j, L3 w* {! A - #define AES_DATA_SIZE_BYTE 16
/ B9 p9 Z9 x& c - /* AES加解密数据的长度(uint32_t) */
* w+ c& o; Q% V x- j) Q - #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4)$ u( T! Q/ n) T$ N
- /* AES加解密秘钥的长度(bit) */
/ s6 O6 O, @4 Y; }/ G0 Y - #define AES_KEY_SIZE_BIT 128
w% o; d: F! F* v# c% o - /* AES加解密数据的长度(uint32_t) */
& K% J& w8 w z l - #define AES_KEY_SIZE (AES_KEY_SIZE_BIT / 4)
复制代码然后写一下AES ECB 128bit秘钥的加解密测试函数以及dump函数 - void dump_data(uint32_t *pData, uint8_t Size)
" g) O. B6 Z2 S' W0 ` - {6 K& W* c7 a$ P: Q$ E. m! P
- for (uint8_t i = 0; i < Size; i++)5 @4 R% J# W# ~# g, ?5 w2 b8 R
- {
& a- [5 w4 }; U+ J* Q - printf("%02X ", ((*pData & 0xFF000000) >> 24));
9 q( ?4 H! B/ N0 s0 K; }) l0 q$ ? - printf("%02X ", ((*pData & 0x00FF0000) >> 16));! r+ G% v+ l' p* b9 @( A4 w9 @, Y
- printf("%02X ", ((*pData & 0x0000FF00) >> 8));
' k# s) c7 I9 n) B - printf("%02X ", ((*pData & 0x000000FF)));1 D J' S" I* z- q' J
- pData++;
7 y- ]1 D& Z5 U {( _7 |% [2 h - }
: q8 c/ R4 ]6 F7 A- E - printf("\r\n");
) t6 o7 k ^; o D) \$ _ - }) Z( Y8 X5 A! Z2 q3 |
- 0 g/ }( Z) M! a$ V0 B; {
- void AES_encrypt_test(uint32_t *plainText)' b% l' F; t7 h; d; c C
- {4 f/ [: m/ H; S1 I
- printf("plainText = ");
+ n1 T6 b# R* Y/ R - dump_data(plainText, AES_DATA_SIZE);
4 \ l0 Y, G+ A* W: l - 9 u6 L. i0 m1 O" Y b6 [- H
- if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK)
, ^7 D; H, H& S$ K* \ - {
- b! h! l# W$ j# s/ X - printf("AES encrypt success\r\n");
! f( A% A& d9 Y2 [' z: a; f w - printf("Computed_Ciphertext = ");
+ F" @6 l* A8 m; [ i& L - dump_data(Computed_Ciphertext, AES_DATA_SIZE);- r$ a& r" t6 G. s8 k: H+ M; s
- }6 j' V g) p/ k% Q; s9 R0 E
- else6 m2 h3 W7 m! _- w5 ~. y( G
- {! Z0 m( r" V5 H$ |: ~) h! n! r2 m
- printf("AES encrypt error\r\n");5 k/ n% _0 L+ h$ H1 k
- Error_Handler();* |! z* l: [8 a- A8 ?2 T
- }5 x1 Z1 n0 \' r, a3 y \' G
- printf("\r\n");
% Z) o0 | a; c- O! L1 K2 ~ - }5 y9 Q' J: A2 a' b
! b+ a4 x' s s! x3 |' w- void AES_dencrypt_test(uint32_t *cipherText)
* _( \1 B5 A, m - {
! }8 {/ v' b* K; J' c8 [4 ] - printf("cipherText = ");3 y( ?8 R1 z2 o7 _/ s4 _; x% f, z
- dump_data(cipherText, AES_DATA_SIZE);- [5 @+ u) k# A) _* v2 r6 K1 r
: W# [% T5 L' r3 e6 p- if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK)# F1 M5 z4 A0 G) n7 p2 l3 r2 M% j) q) J
- {' P% H' K& [: | i# W+ \+ P
- printf("AES dencrypt success\r\n");) n' f) e* x! Y# w! B! ]# W
- printf("Computed_plainText = ");1 y$ y# ^$ |: d, K* M6 @
- dump_data(Computed_plainText, AES_DATA_SIZE);
7 b1 [- g, }' B( V - }
2 n2 Y. t) y' U: Y - else; @0 M. g6 h, |! f
- {
! D/ J" `, A7 z6 U; d6 F0 d - printf("AES dencrypt error\r\n");
+ t9 }# B3 X6 a) ?: v, t; J - Error_Handler();
- Z; A$ z& C) C' O( _0 N. w' l - }: @* D( Y& w* k
- printf("\r\n"); J( |- i0 |+ ^2 J0 `1 F- M% t
- }
复制代码
4 h' H- b0 ]( ?* e+ g e/ \, ^1 ?) d5 h9 _
然后在main中调用 - printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");
( [; H) _5 q) @1 C9 ?1 p - AES_encrypt_test(&AES_plainText[0]);
; ]( h) X; m! D' O0 [6 m - printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n");
: U+ r V+ u! G, P: s5 G6 f& Y - AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码编译运行一下,结果如下 和在线工具对比一下,结果一致 7 U7 Y9 j) c# N5 q1 Y
接下来尝试更换一下秘钥,再运行加解密 更换秘钥有2种方案,第一是直接对MX_AES_Init中的内容修改,但是因为这里是cube自动生成的,后续cube再生成一次就又变回去了。所以我选择方案二:去初始化,修改参数,再初始化。
) b. z: S3 X5 a2 e改变秘钥函数 - void change_key_to_user_defined_AesKey_128bit()2 F, M4 p, B; S
- {8 G9 B% x' Q- Q6 X4 n
- printf("change AES KEY to user_defined_AesKey_128bit\r\n");
( Y+ H$ P h$ E: K5 T: }8 g - /* 先去初始化 */
/ [! r. `$ n) F( x9 U7 L+ V - if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)
) U5 l" V. `" F8 O4 J4 Y8 M0 C - {: V$ B- R* P* i
- printf("HAL_CRYP_DeInit error\r\n");8 a4 ?4 r4 ?1 z) P. k
- Error_Handler();7 d7 X; r" Z! Q# w
- }
! x4 p$ r2 m+ F - / t6 I3 d9 S2 Z% F4 t
- /* 修改使用的秘钥 */* i7 z4 @% \3 x; P# P3 \
- hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;/ X7 p4 v; t- X E/ _; v$ o2 d
- 4 Z( m, \ G# \
- /* 再次初始化 */
1 |% D, o+ h9 C$ @1 I - if (HAL_CRYP_Init(&hcryp) != HAL_OK)
6 e4 s( o- Y# [2 b2 |' N" B - {
+ A7 Z, V& F( h" _+ g/ e: B - printf("HAL_CRYP_Init error\r\n");
7 A8 y2 l! m, t2 _" i% S% k$ q - Error_Handler();+ o' e$ {8 S u6 r( R
- }8 {" U/ y+ `& ~( R
- printf("\r\n");
# U! o( @. y. {$ b) J/ y. T - }
复制代码 6 q; h( f) ?8 D
& m5 D4 b7 Q3 q
然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功 - change_key_to_user_defined_AesKey_128bit();' C4 o4 V' m& l7 t" Q0 P8 }/ E
& S* S* \+ _8 @5 D- l- printf("AES ECB use user defined key 128Bit encrypt test\r\n");- Z3 w' K1 C) W1 X) j+ Y% r q6 ~
- AES_encrypt_test(&AES_plainText[0]);
' {' z) L- j; p - printf("AES ECB use user defined key 128Bit dencrypt test\r\n");, x5 J& J; f8 u
- AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码 编译下载运行效果如下 和在线工具对比一下,结果一致
# o0 I5 O! F% s/ y7 U2.2 AES CBC 128bit加解密测试 然后我们把AES模式切换至CBC模式,来进行测试 CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下 然后准备一下CBC加密后的结果的数组,回头给解密时使用 - /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */0 N- `+ G4 X5 O" x! P x3 o
- uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =2 S5 z: [1 O2 a# y! q# s
- {' q8 X$ L' z5 C' A' |7 B3 W
- 0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E783( Z# L+ S8 f; }: J& H; ~0 s
- };
复制代码写一下切换至CBC模式的函数 - void change_to_aes_cbc_mode()
- p) O+ r3 `8 D: m - {; R' l4 u5 } M4 D8 t) ~8 W" W$ T
- printf("change to AES CBC mode\r\n");3 n$ ], S$ |1 o) w( I% j
- /* 先去初始化 *// h5 a% a8 \" Q1 V8 e) X
- if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)
0 A: e* q f+ \- a; x' z - {) B5 n. [7 ?1 w! M, E" Q
- printf("HAL_CRYP_DeInit error\r\n");
3 x- Y, W# P6 C$ ? - Error_Handler();
+ y0 C- e/ w0 l) \: A - }/ q- G& C5 h9 Q! o8 j; T4 E
" ?9 o# \# R- N$ G/ I# ~2 x- /* 修改为CBC模式 */$ b& I6 C" s2 F' O" O# ^
- hcryp.Init.Algorithm = CRYP_AES_CBC;
/ E" l& N6 w+ I) v8 S - /* 设置IV */
, T. ]) r; c C+ R - hcryp.Init.pInitVect = AES_CBC_IV;
+ a$ W" r$ w) p1 E- w. k
+ i3 N- ]/ h( R1 Q- /* 再次初始化 */$ L, C) a) X0 K: P; |
- if (HAL_CRYP_Init(&hcryp) != HAL_OK)
, h$ u. E% C$ h* _7 \ - {
( l, R8 z* U- j, y/ T$ z. z) h - printf("HAL_CRYP_Init error\r\n");+ B3 P, q# t. K
- Error_Handler();8 l5 _; P _, }* j# o
- }
$ _: r, w7 N; z6 Q6 V6 M - printf("\r\n");* p3 J8 I* J; g, k( ~8 x3 ?
- }
复制代码在main中调用切换函数,然后进行CBC加解密测试 - change_to_aes_cbc_mode();9 n0 V% ?* D" M2 e( Y! ?3 b
- + G. M7 U9 r5 t, M0 }8 K' @4 y3 }
- printf("AES CBC use user defined key 128Bit encrypt test\r\n");
7 Q6 m! S2 a7 r4 [5 e - AES_encrypt_test(&AES_plainText[0]);; }( Q8 t: E- w$ C
- printf("AES CBC use user defined key 128Bit dencrypt test\r\n");/ _7 N$ b8 F9 O m! \* ^
- AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码编译下载,结果如下 和在线工具对比一下,结果一致 三、总结 今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。
/ C! c* W3 m' a: l- d' D本次工程代码:
STM32U0_AES_test.rar
(5.21 MB, 下载次数: 1)
|
好详细啊👍