STM32U08是带硬件AES加解密模块的,硬件加解密的最大优势就是快。
2 p4 H2 w7 \' m* I7 p& b6 m" z一、cube配置 首先需要在cube中开启AES模块(工程就是上一篇中创建的模板工程)
( Q; u9 U1 a+ y( N; X参数这一块主要关注的是加密模式(Data encryption type)、秘钥长度(KeySize)、秘钥(Encryption/Decryption key),其他参数保持默认就可以 其中加密模式支持如下 秘钥长度支持128位、256位 秘钥的值可以在cube中配置,也可以这里保持默认值,回头在代码中重新配置(当然上述的这些参数都可以通过代码再次配置,这个待会实战部分会有介绍) & W, P; G+ [. G
最后点击右上角生成代码
6 v) N, C0 l( e二、实战 2.1 AES时钟初始化及函数介绍 先来看一下CUBE自动生成的代码 首先是变量 - CRYP_HandleTypeDef hcryp;' j9 x J6 V' w2 {% {) c0 S
- uint32_t pKeyAES[4] = {0x00000000,0x00000000,0x00000000,0x00000000};
复制代码这边的pKeyAES就是秘钥,和之前cube中设置的一致(下面的测试中我会尝试更换秘钥) 然后就是AES模块的初始化函数
, T3 z& F- F7 t- I) s- m
0 F5 y% S& Y; P3 F% m在初始化函数中可以看到,配置了各个参数,和cube中的一致。然后就是调用了初始化,秘钥、加密模式等就是在init时配置进去的,如果需要更换,那就要调用HAL_CRYP_DeInit(),修改配置参数,然后再调用HAL_CRYP_Init()(这个待会儿我也会尝试一下) ( }3 v; V. K( b# L4 n
在使用加密前,需要在main函数的最一开始就开启AES的时钟 - __HAL_RCC_AES_CLK_ENABLE();
复制代码
) h3 k$ U& i& |2 l( D: ~加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密 具体函数如下 - HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
% Z4 l9 Q1 t7 S% @" W - uint32_t Timeout);! ~+ [) G3 v( o8 \4 K [7 f. q
- HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
! n1 y. R" x/ \- ] - uint32_t Timeout);
- j) V6 X+ b. k8 U( Y - HAL_StatusTypeDef HAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
: b t4 K2 C+ n. a7 B$ D) f5 F - HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
/ m r0 c. T" D9 D9 ]' L; z9 c7 _ - HAL_StatusTypeDef HAL_CRYP_Encrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
# q6 Y6 Y6 f5 f0 Z5 D - HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码
& s' i$ x3 Q. |" M* E这里我再插一嘴,AES是需要加解密数据为16字节的倍数才可以运行,如果你的不是16字节的倍数,那么就需要做一下填充,加解密接口是不提供填充的,需要自己实现
. u) Z# m( B( h( h今天我们的测试的是最基础的阻塞加解密函数
3 ~" U3 `! ^8 o! D$ n2 J2.2 AES ECB 128bit加解密测试 我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试 先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上 - /* 计算得到的秘文 */3 Q" U0 q1 E |5 t- |
- uint32_t Computed_Ciphertext[AES_DATA_SIZE];
1 z0 t$ W$ A5 G8 d) F, U& | - /* 计算得到的明文 */" t5 ~- u/ S+ }# q8 A6 Q6 B! g
- uint32_t Computed_plainText[AES_DATA_SIZE];
) Q' c7 U0 m" [; H - 0 v% n/ R7 r, ~. w0 c% e
- /* 用户自定义128bit秘钥 */6 e- M. ~% a3 |
- uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =
7 s8 D# L+ p4 Z" a - {) h4 B9 u) E- a" A# O. C
- 0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff/ R* W$ n f* ~( q
- };# d8 C" x9 Z; c# _3 Y G2 U
- /* 加密前的明文 */: V9 |. \& R1 ^ q# n7 x/ Z
- uint32_t AES_plainText[AES_DATA_SIZE] =( E1 u0 n5 u( P9 O3 M' @' Z# e
- {3 k8 {, p1 T" J' x C
- 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f1 u0 P% e9 J0 `' Y S' Y6 K
- };1 r4 [5 Y# |+ K: b P
8 I( j" |$ }5 @* ^- C- /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */% J) }7 ^' |( e8 r. a% I7 x
- uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
8 I% q2 R4 L9 v, X% L# `( Z! j1 @ - {, i5 y$ F8 W6 W# \8 T: R
- 0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE0039 U. Z2 D& l8 o0 w/ }
- };4 p# |5 _, O B5 v; \
- /* AES ECB使用cube默认128bit秘钥加密后的秘文 */
' K" {* k( i/ L$ C6 c, a9 `8 B3 P - uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =7 `- W$ P. N5 U4 P2 G7 f! {/ @5 A) ]
- {- f* R% {/ u* C7 Q4 s
- 0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A2826 o" Z% Q q+ a- @
- };
复制代码
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的 % ? |5 A# a8 B, n2 y
然后在加一下宏定义 - /* AES加解密阻塞式函数超时时间 */' c1 H- r( T( ~7 w" S
- #define AES_TIMEOUT_VALUE 0xFF //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说( M0 v. A3 V* H2 F( @; d* A
- /* AES加解密数据的长度(byte) */& ]% \" a; O8 c; T
- #define AES_DATA_SIZE_BYTE 161 @3 [2 h8 a6 b$ Y
- /* AES加解密数据的长度(uint32_t) */
/ u: {0 f+ t1 S - #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4). e* v9 j4 @, b9 q/ T8 r
- /* AES加解密秘钥的长度(bit) */7 n7 I% X( d" c
- #define AES_KEY_SIZE_BIT 1283 c* ~- {4 y% d/ }6 [7 T U
- /* AES加解密数据的长度(uint32_t) */; c+ \/ p' M f' F0 n
- #define AES_KEY_SIZE (AES_KEY_SIZE_BIT / 4)
复制代码然后写一下AES ECB 128bit秘钥的加解密测试函数以及dump函数 - void dump_data(uint32_t *pData, uint8_t Size)
; u5 v2 _8 L( l$ k - {
( [) U6 |* R) c7 n9 { - for (uint8_t i = 0; i < Size; i++)5 P. a3 r6 [- ], W0 e9 G/ B* p+ y
- {- d/ B& R5 g2 @' l) D0 z" i/ E4 t
- printf("%02X ", ((*pData & 0xFF000000) >> 24));! l2 {' m# @; s; P5 b
- printf("%02X ", ((*pData & 0x00FF0000) >> 16));
5 I( n& I( `4 V - printf("%02X ", ((*pData & 0x0000FF00) >> 8));
- e+ g) ]% m& P D0 s7 t! T - printf("%02X ", ((*pData & 0x000000FF)));
) V1 u* ~. F( |* N - pData++;
0 _9 `: K* N8 d/ T3 ^+ d - }* h2 \! ]6 f" {8 W
- printf("\r\n");, P* Y& [$ y6 E$ s6 |! t& N4 d: F
- }
+ i7 a& k: X7 H; z; a& a+ g8 i
. x7 V% m7 [% E- void AES_encrypt_test(uint32_t *plainText)
- j( o9 E# U6 z3 b6 E& Y - {
/ G. n7 H9 y/ H1 m: c: ] - printf("plainText = ");/ D! C5 i4 g5 ]. @
- dump_data(plainText, AES_DATA_SIZE);6 j* g7 a+ A7 z' P
/ g8 K& q1 |1 o# K- if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK)+ M) Y2 d7 p0 i! a, S( Q y
- {- ~' l9 A4 F6 O3 d
- printf("AES encrypt success\r\n");& U3 o# U4 K5 u& G2 M5 c
- printf("Computed_Ciphertext = ");
' v5 f+ E$ }6 E: P# v - dump_data(Computed_Ciphertext, AES_DATA_SIZE);' e/ f( z2 R, }$ s6 u2 p: g, B
- }- C8 ?3 L6 \8 ^1 b) f: K
- else
% e4 F/ i" s$ P" f' S: T! ] - {
0 P9 c0 ]( L m9 X1 t8 A$ Z8 l - printf("AES encrypt error\r\n");
: f8 T% k2 `: V$ k" U* [ - Error_Handler();& v! y$ O. g4 C# R0 s. \) n3 R
- }9 M' Q" p$ @2 k( M
- printf("\r\n");6 F9 P- Y% i# t. P- P
- }) V7 p4 w" c3 C6 S- d5 A
- # j7 `: f$ D& @, r$ c7 x
- void AES_dencrypt_test(uint32_t *cipherText)
3 [8 y5 g4 n+ R- V7 f% g - {
& H6 M: c, i! L7 G5 z" d5 `" h5 X - printf("cipherText = ");) ^" V* E4 |" `6 _7 s
- dump_data(cipherText, AES_DATA_SIZE);
6 ?6 T' c9 D% j/ Q7 ]8 m
, @* O& v, F6 Y: R* k- if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK)& K0 e5 B+ T/ z4 i! s
- {' [0 w: Z9 Z+ s- N
- printf("AES dencrypt success\r\n");
- O, Z2 l$ i& t0 m: A$ x$ O5 |/ R9 E - printf("Computed_plainText = ");
' S; d- E7 x5 C7 q( u4 H - dump_data(Computed_plainText, AES_DATA_SIZE);$ \% E; n+ c5 c9 L
- }
# q$ G) _* e! r- w7 I+ o! \ - else
5 s6 U% L6 V% q2 q: P/ Z' x- F - {
" `" W' h9 O+ Z* T& Z - printf("AES dencrypt error\r\n");
1 u2 t( ?* Q, I" P9 i - Error_Handler();) z+ H5 d! R# c `3 D
- }
% O& a1 E8 X7 Y - printf("\r\n");+ r& c# W. U5 t3 G- J, B
- }
复制代码
/ w6 b5 {( L* R1 r/ t
% _) h4 a# R& \& x然后在main中调用 - printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");( S$ c+ D+ b1 n5 w
- AES_encrypt_test(&AES_plainText[0]);9 [0 J* t" ^+ L1 c7 M7 P9 j; T0 X
- printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n");
9 A& t) \" z: N# m' x3 g9 M X - AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码编译运行一下,结果如下 和在线工具对比一下,结果一致
: S5 d/ r# @; p, M/ F+ u: x接下来尝试更换一下秘钥,再运行加解密 更换秘钥有2种方案,第一是直接对MX_AES_Init中的内容修改,但是因为这里是cube自动生成的,后续cube再生成一次就又变回去了。所以我选择方案二:去初始化,修改参数,再初始化。 ! M2 a2 {0 q( R6 B9 @
改变秘钥函数 - void change_key_to_user_defined_AesKey_128bit()
, `2 w" \9 I1 [! a# G - {9 A" x$ x* e$ w/ r* h; K
- printf("change AES KEY to user_defined_AesKey_128bit\r\n");
8 J8 g% b2 F7 S% b - /* 先去初始化 */
* U4 w1 S, i$ T& T/ g - if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)( |5 p8 N7 f6 W% q4 b: e7 c
- {
, \0 v4 Q4 Z5 ]" b& {- ^ - printf("HAL_CRYP_DeInit error\r\n");' y, f) r9 s6 r9 O
- Error_Handler();
7 _" Y, K: n4 `: R5 h/ E% g L - }/ r4 `) p/ h1 G2 W5 F. z
% [& G/ H" t, i% C- f- /* 修改使用的秘钥 */
; {7 X' R9 M2 L7 Q% ] - hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;3 q- _, l- A% c/ |+ n
- ; F7 A5 n+ B; D* u% L, ]/ h9 z
- /* 再次初始化 */
" i" h2 F5 J' J: ]9 K+ N - if (HAL_CRYP_Init(&hcryp) != HAL_OK)! g* ]3 Z3 P# y' Y. s1 C# b7 t' L
- {
4 i! c8 K/ Q. T5 W2 Z" p0 g, p& { - printf("HAL_CRYP_Init error\r\n");* Q0 r& r( F1 o" f) C! Y
- Error_Handler();2 k2 k% s( d% c: x3 ~; H/ U
- }4 S. u( Q) r; z+ v& i: D: S
- printf("\r\n");
9 M: q+ \* B+ ^) o$ I4 C g - }
复制代码
- G& j! } n" a t0 a. Y ]8 D" |/ x, N0 H2 s1 ?: B7 c1 _
然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功 - change_key_to_user_defined_AesKey_128bit();( }1 n( y$ q1 N# N9 G
9 N/ b; v5 u3 g( v- printf("AES ECB use user defined key 128Bit encrypt test\r\n");
+ h/ g+ V5 X$ a" s2 o9 d9 T - AES_encrypt_test(&AES_plainText[0]);) Y/ X f- S- x2 c0 i6 U7 O8 x
- printf("AES ECB use user defined key 128Bit dencrypt test\r\n");2 S" L! O* [2 ]" M9 @+ D9 g1 [
- AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码 编译下载运行效果如下 和在线工具对比一下,结果一致 2 v$ L9 w& s. y1 H) V
2.2 AES CBC 128bit加解密测试 然后我们把AES模式切换至CBC模式,来进行测试 CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下 然后准备一下CBC加密后的结果的数组,回头给解密时使用 - /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */
: y( v% a' P; x - uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] = ?7 ?& g+ L8 j0 G
- {& m+ O8 ?+ o& v/ s* b1 v; w+ \: [
- 0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E783
( F$ b6 H* o$ p - };
复制代码写一下切换至CBC模式的函数 - void change_to_aes_cbc_mode()
! y( x$ _. X% L y - {
: O% c0 v* Z2 K1 R7 E5 K - printf("change to AES CBC mode\r\n");4 F1 I' a/ ]! V* [' }$ G
- /* 先去初始化 */
5 t2 l6 W4 d" E$ M# D9 p - if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)
8 {! X1 S* I$ `; Q N1 g4 G: T! [, T) Y - {
* d4 S( ]' g4 h) t' q+ c - printf("HAL_CRYP_DeInit error\r\n");( @) W# Q; B& L+ |. ]; ]( W
- Error_Handler();
1 N) Z# i" l( w" j* v- G1 ^$ W- x - }8 Y X% j, m2 D; d5 J
6 @1 b/ b O p% S' ]% M; T! \! T- /* 修改为CBC模式 */
5 P. z3 [+ d2 y% \% V7 K f+ J - hcryp.Init.Algorithm = CRYP_AES_CBC;
# C1 C$ I# |0 u9 i. P: R; ^3 q - /* 设置IV */
6 Q+ f6 R% q: ` - hcryp.Init.pInitVect = AES_CBC_IV;+ Z7 W# |, y5 ~6 \+ \% ?
- ' h5 G% h9 F6 @: c$ @# N
- /* 再次初始化 */
9 R8 [, N3 h6 `+ C - if (HAL_CRYP_Init(&hcryp) != HAL_OK)4 `3 K% z0 N; N: ?' K
- {/ y3 [; H" N1 k& k+ k2 U
- printf("HAL_CRYP_Init error\r\n");% U- Z. q+ H% H' ?9 z! [
- Error_Handler();
% B1 l! P; c2 q& _9 G! N U% p" x6 e - }
6 Y9 J1 b! e3 G) r& h! B" I6 ^ - printf("\r\n");
; F$ d$ |) Q7 b% Y+ ] - }
复制代码在main中调用切换函数,然后进行CBC加解密测试 - change_to_aes_cbc_mode();
; B- {& ?# M- r
( y0 ~. L5 K' M: E) z* |- printf("AES CBC use user defined key 128Bit encrypt test\r\n");9 {: y$ ~+ H+ N* c. o; [5 Q5 i
- AES_encrypt_test(&AES_plainText[0]);( [- f0 y0 M3 r* J" j+ [; z4 _
- printf("AES CBC use user defined key 128Bit dencrypt test\r\n");
5 V' g! N3 ^: I* w' Q - AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码编译下载,结果如下 和在线工具对比一下,结果一致 三、总结 今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。
& B% m, E) m N+ S8 R5 G本次工程代码:
STM32U0_AES_test.rar
(5.21 MB, 下载次数: 3)
|
好详细啊👍