|
STM32U08是带硬件AES加解密模块的,硬件加解密的最大优势就是快。
. k8 @; T+ ^; e& G( b一、cube配置 首先需要在cube中开启AES模块(工程就是上一篇中创建的模板工程)
, L5 A' w$ ?$ b4 B: h! z参数这一块主要关注的是加密模式(Data encryption type)、秘钥长度(KeySize)、秘钥(Encryption/Decryption key),其他参数保持默认就可以 其中加密模式支持如下 秘钥长度支持128位、256位 秘钥的值可以在cube中配置,也可以这里保持默认值,回头在代码中重新配置(当然上述的这些参数都可以通过代码再次配置,这个待会实战部分会有介绍) V, m z v+ M5 J9 k& G! j# j
最后点击右上角生成代码
' Q; s! b8 b! |8 d. S! p5 _! E二、实战 2.1 AES时钟初始化及函数介绍 先来看一下CUBE自动生成的代码 首先是变量 - CRYP_HandleTypeDef hcryp;
! g" L2 m3 [, ~4 _& R; s - uint32_t pKeyAES[4] = {0x00000000,0x00000000,0x00000000,0x00000000};
复制代码这边的pKeyAES就是秘钥,和之前cube中设置的一致(下面的测试中我会尝试更换秘钥) 然后就是AES模块的初始化函数
) L# i+ K) L7 O
7 P0 m! J/ F0 ~, e2 K在初始化函数中可以看到,配置了各个参数,和cube中的一致。然后就是调用了初始化,秘钥、加密模式等就是在init时配置进去的,如果需要更换,那就要调用HAL_CRYP_DeInit(),修改配置参数,然后再调用HAL_CRYP_Init()(这个待会儿我也会尝试一下) 7 w+ o) N. {6 [- @
在使用加密前,需要在main函数的最一开始就开启AES的时钟 - __HAL_RCC_AES_CLK_ENABLE();
复制代码
: t3 k' v. B, }6 @% R加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密 具体函数如下 - HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
R. h K4 b& K" k* I0 \ - uint32_t Timeout);
" ^0 z) `- r ?7 u& a6 n# i& d. I - HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
5 G3 R) ?" D8 _ - uint32_t Timeout);
. N# q8 q9 X' G5 \ - 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
- HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);+ ~' M; K# ^2 e3 p. F
- 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 - HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码 , 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% Z2.2 AES ECB 128bit加解密测试 我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试 先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上 - /* 计算得到的秘文 */
8 s" o/ I, k8 f0 Q& m. n1 e( U1 E( d# o - uint32_t Computed_Ciphertext[AES_DATA_SIZE];
0 J: P2 R# Z! \# t - /* 计算得到的明文 */" J! Z* k- z; S3 h
- uint32_t Computed_plainText[AES_DATA_SIZE];5 d' U' j8 _$ V {: N
y% `. u6 G& Y$ ~, A0 B- /* 用户自定义128bit秘钥 */
! e. A( y Z$ d& J, I, F' {& q - uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =
! A/ ?; K2 ~6 c9 V4 m - {, ]# D1 N( o/ I+ z1 Q
- 0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff' D+ W% z/ @! I Z4 U5 B- [
- };1 n7 L9 z" w' ^/ }
- /* 加密前的明文 */1 C2 y# w) a6 W1 w% ~2 r! G
- uint32_t AES_plainText[AES_DATA_SIZE] =
, }! v2 t, m# w' K6 w" _ - {
5 H* X" A! D4 j - 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f' R1 @* v$ ^+ E0 n3 W5 i( ?
- };* u* _& K5 G( r- |) G+ S
0 ^1 K h6 f' T0 N. D8 q5 [& u- /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */3 D; ]2 J+ Q* f7 ?8 H; f% F
- uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
6 H+ {; o/ _; X6 ~2 _% L% f - {
! e* ]2 j3 ]0 O1 v" y) g8 k* ` - 0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE003
5 q6 U1 Y0 X/ G5 A# s/ s - };2 ? F6 x' ~; O x' D( G
- /* AES ECB使用cube默认128bit秘钥加密后的秘文 */
5 d- ^+ A. `5 Y t - uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =
+ B* ^4 X# G6 j - {; D- p2 a- ^& Q# f
- 0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A282
2 e% P6 j( @# P7 N5 w3 B% z - };
复制代码
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的
4 G! J( ?4 H, {: j然后在加一下宏定义 - /* AES加解密阻塞式函数超时时间 */. o h2 d$ @# k- j
- #define AES_TIMEOUT_VALUE 0xFF //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说3 u/ W' }8 ~( [2 p3 {: D5 Y8 `
- /* AES加解密数据的长度(byte) */8 h9 r/ A) |) D5 i& B
- #define AES_DATA_SIZE_BYTE 16
" M3 F9 q: l9 G$ a1 H - /* AES加解密数据的长度(uint32_t) */
1 O2 }! S( L3 o; c* P$ C6 U - #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4)) d2 p+ f% K j
- /* AES加解密秘钥的长度(bit) */4 F1 _9 a) ~ ~2 j _ s8 a
- #define AES_KEY_SIZE_BIT 128
" c; u' N! n2 S2 }( P3 H f - /* AES加解密数据的长度(uint32_t) */
0 C" v9 E+ ]) S' ]4 }' z$ d - #define AES_KEY_SIZE (AES_KEY_SIZE_BIT / 4)
复制代码然后写一下AES ECB 128bit秘钥的加解密测试函数以及dump函数 - void dump_data(uint32_t *pData, uint8_t Size)* C% e$ J( e I# i2 ?0 j" V( { M
- {
# c, T4 u0 v: j0 _8 { - for (uint8_t i = 0; i < Size; i++)
% X4 ?; @: l, {9 n9 E. D9 t% B% s - {! Q# m) C& D9 v( T0 N. l9 L
- printf("%02X ", ((*pData & 0xFF000000) >> 24));* [9 ~# ` J1 @
- printf("%02X ", ((*pData & 0x00FF0000) >> 16));
) n, [$ P9 Z% W( p5 G) M) [ - printf("%02X ", ((*pData & 0x0000FF00) >> 8));
- v& J) p/ h+ n7 J. i4 B: {; C - printf("%02X ", ((*pData & 0x000000FF)));" C j" n- i0 L% ^
- pData++;
* x/ f, S3 v' _' u! s - }
) t9 r# P7 {) c/ l0 Y - printf("\r\n");
- y: U3 }* W. T" {5 n2 {( H5 ] - }7 N. z3 f! e) s) Z* q
- - X: ~& z! s w/ ~5 A5 [/ c
- void AES_encrypt_test(uint32_t *plainText)' g; R' f% Y: y9 Y: F
- {! j" ` o7 M T+ V$ Z/ l% _) o
- printf("plainText = ");
6 C$ R3 ^8 b( ^4 B" o5 E7 R3 n - dump_data(plainText, AES_DATA_SIZE);: d0 m# t$ |# E! k. L9 B
- 1 p8 V$ |$ w, d5 i, u" k) {, v
- if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK)- p: _0 E, \2 q8 z
- {
) W% y" X, i/ H* D* ? { - printf("AES encrypt success\r\n");
/ D* Y% f1 L; u/ r; A - printf("Computed_Ciphertext = ");
0 \6 A, V" R; `/ T, @+ }6 U - dump_data(Computed_Ciphertext, AES_DATA_SIZE);
: W" g/ U# d# p- F0 J - }
' ?& z# D7 b% }7 l1 B, h% _ - else- ^* T, M4 n" N" A
- {
# W8 ]5 H; `4 {# @: K - printf("AES encrypt error\r\n");. I; f# ?, z4 c8 n V8 `- y/ M
- Error_Handler();3 I7 ?- N" _. e+ L
- }2 E5 i. y4 `) Q- z
- printf("\r\n");
( G- U9 _& F) d' n2 d) [ - }6 [0 e4 h2 L# u( @) ]. O
- ' U# M; `9 Y/ H
- void AES_dencrypt_test(uint32_t *cipherText)
7 R8 ?$ E+ J2 t - {" i) a' g( B1 P3 x' |' A$ X
- printf("cipherText = ");
+ Z' r7 Y& e4 b2 c - dump_data(cipherText, AES_DATA_SIZE);: N5 i, O) ^* y9 D _
- ' G9 g1 T0 c9 h- z/ D
- if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK); P: i J, |& {& ]% k4 {8 I$ S
- {* n2 s8 h% \6 Q R3 A4 }7 D
- printf("AES dencrypt success\r\n");
) w5 Q& J2 t2 t# Z; Q, z5 g - printf("Computed_plainText = ");
1 n8 z0 v' f, x# g, j - dump_data(Computed_plainText, AES_DATA_SIZE);. z1 S: x: ?, ~+ k$ U$ S! C
- }
/ a5 k+ u# _7 A$ n, { - else
* p6 O. P- \. P7 T - {
* X/ j% W( F! q j9 _& U - printf("AES dencrypt error\r\n");( P' Y$ S1 ^; n: g5 R. r3 Z" o5 y' d
- Error_Handler();
9 K7 m- P( p9 J/ A! A3 d4 { - }$ Z. ^, p4 W' c# C/ j
- printf("\r\n");; r* Z( e: o% _9 b& m
- }
复制代码
- V% @7 h; J5 ~$ j4 a: F, F, [% v- |. u
然后在main中调用 - printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");
( R) X6 t8 e& A% D" u. {) O - AES_encrypt_test(&AES_plainText[0]);$ \" ?. H9 Y4 p. b v
- printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n");
* B9 k% d2 {$ z- Y# s! ] - AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码编译运行一下,结果如下 和在线工具对比一下,结果一致
+ {7 V6 d$ E6 t2 ]4 Z' g接下来尝试更换一下秘钥,再运行加解密 更换秘钥有2种方案,第一是直接对MX_AES_Init中的内容修改,但是因为这里是cube自动生成的,后续cube再生成一次就又变回去了。所以我选择方案二:去初始化,修改参数,再初始化。
( A" B1 s% g. l" o改变秘钥函数 - void change_key_to_user_defined_AesKey_128bit()
! J1 G3 j* x- e' _9 T' } - {: }/ ]7 y" p4 d6 Y! C9 H: }. M4 p
- printf("change AES KEY to user_defined_AesKey_128bit\r\n");
; z4 e+ Y3 Z( X1 k+ c - /* 先去初始化 */5 M& B" l1 {* O6 I7 ?. o; [
- if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)+ q" k3 c* d5 [, d, D% F
- {3 y' ~" r6 B7 ~4 S. b
- printf("HAL_CRYP_DeInit error\r\n");
3 z z; t6 f E1 O5 m$ K' E - Error_Handler();3 J u% m; T' I- Z1 D5 I
- }8 |: A X% v- I% j
- 5 Q. {, _# i' Z& V( T1 Y( s+ H
- /* 修改使用的秘钥 */( ~4 X& B8 I( W, O6 f1 `" H
- hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;
* L" J. w; j5 H - 1 X7 _& n; s f" {
- /* 再次初始化 */
9 H' @- |, L2 j# f2 E - if (HAL_CRYP_Init(&hcryp) != HAL_OK)
& Y" q6 r/ Q2 N; S& J - {7 a+ \4 }0 M( q3 f0 d
- printf("HAL_CRYP_Init error\r\n");2 H: ^0 Z! {; c6 I3 {$ F: ]
- Error_Handler();
" d6 j7 `& K- X' ?) m' m - }
3 K( _1 h q! t$ D9 p - printf("\r\n");& _" h) L. g: z# x* G
- }
复制代码 ; e3 t4 ]8 ^4 n1 X& K5 o3 F
. i" G: `0 G+ z4 w2 w9 E
然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功 - change_key_to_user_defined_AesKey_128bit();1 m8 w( U" o7 d4 k) }+ x% x& x8 L
- 7 u9 t4 k' s4 Z! U: N' D
- printf("AES ECB use user defined key 128Bit encrypt test\r\n");
. Y+ b5 u$ ?1 q1 n8 ~ - AES_encrypt_test(&AES_plainText[0]);
* l% J& |( V( j$ e" d0 P - printf("AES ECB use user defined key 128Bit dencrypt test\r\n");/ z5 w4 L- o- ~& G' N, e9 m
- AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码 编译下载运行效果如下 和在线工具对比一下,结果一致
! K2 D' |: K1 Q$ o2 ]3 H5 X2.2 AES CBC 128bit加解密测试 然后我们把AES模式切换至CBC模式,来进行测试 CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下 然后准备一下CBC加密后的结果的数组,回头给解密时使用 - /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */- ^$ }% d) N( x3 H' [+ z5 T% A, I+ S
- uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
$ i7 E U# e: l8 `+ H* H - {
% i. y0 I2 n' J - 0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E783
+ {( N' J) b$ A) E- \ - };
复制代码写一下切换至CBC模式的函数 - void change_to_aes_cbc_mode()
V ? M S, {, O8 s1 q - {; w/ x& d+ @8 H. H! i' ?
- printf("change to AES CBC mode\r\n");
1 ?& b" L$ ~6 n& [ - /* 先去初始化 */
( O, T+ W8 B1 m c - if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)- @- H# J- ~, R: H0 o: R2 O$ R! n
- {
8 F3 F- [6 a n Q+ h1 U - printf("HAL_CRYP_DeInit error\r\n");
: c6 F# y) ?7 ]- J! }9 k! A9 }4 w - Error_Handler();
& r& X' s% w3 m% I8 V' s4 @ - }
) `/ B/ ], l( n$ b5 l& P, n
# j7 W# ]7 V5 J, l' f- /* 修改为CBC模式 */
5 d, w) e$ {! U1 Z% X4 l - hcryp.Init.Algorithm = CRYP_AES_CBC;
2 U6 F' k5 b3 i - /* 设置IV */
7 Y3 k6 z! J- h. ^% x6 {- O - hcryp.Init.pInitVect = AES_CBC_IV;
7 c: `7 i- d" G1 z3 f7 w - : G% n( R* y" R" G* X% j8 B
- /* 再次初始化 */8 Y$ J/ z; \) ?0 F/ Z3 g1 b. ]
- if (HAL_CRYP_Init(&hcryp) != HAL_OK)0 Q, e! N: y) H: J U" r
- {( L. t/ t0 m) d
- printf("HAL_CRYP_Init error\r\n");
: O2 t/ q9 B3 \( V - Error_Handler();
9 e: e) m, `" L - }
S- I" l0 y6 {6 O- v7 A9 U K - printf("\r\n");, s& S `9 M" e+ _" U
- }
复制代码在main中调用切换函数,然后进行CBC加解密测试 - change_to_aes_cbc_mode();
3 t8 U1 E$ l! g; Z6 ~3 w; [ - * }) I' j; D) y- u
- printf("AES CBC use user defined key 128Bit encrypt test\r\n");# }# Z3 r3 [+ u+ J! D
- AES_encrypt_test(&AES_plainText[0]);
. A9 Z; w, r9 g7 C0 R - printf("AES CBC use user defined key 128Bit dencrypt test\r\n");( k) k d' w5 a9 ]* G ^
- AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码编译下载,结果如下 和在线工具对比一下,结果一致 三、总结 今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。 3 L, b8 ?4 R; J5 E) P' Q0 t
本次工程代码:
STM32U0_AES_test.rar
(5.21 MB, 下载次数: 5)
|
好详细啊👍