|
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),其他参数保持默认就可以 其中加密模式支持如下 秘钥长度支持128位、256位 秘钥的值可以在cube中配置,也可以这里保持默认值,回头在代码中重新配置(当然上述的这些参数都可以通过代码再次配置,这个待会实战部分会有介绍) * F ^* M% v% L, o0 y- Z/ p+ h
最后点击右上角生成代码 0 b; y8 [9 [7 o: U6 g6 q8 `
二、实战 2.1 AES时钟初始化及函数介绍 先来看一下CUBE自动生成的代码 首先是变量 - CRYP_HandleTypeDef hcryp;
7 ]+ A! G n. y4 g5 V$ k+ x) |% Y% P7 b: I - uint32_t pKeyAES[4] = {0x00000000,0x00000000,0x00000000,0x00000000};
复制代码这边的pKeyAES就是秘钥,和之前cube中设置的一致(下面的测试中我会尝试更换秘钥) 然后就是AES模块的初始化函数 3 W8 x8 b) F6 Z3 T! q
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的时钟 - __HAL_RCC_AES_CLK_ENABLE();
复制代码 , j0 r4 ]* V* _4 P/ x% r4 \ w
加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密 具体函数如下 - HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,( N3 \6 {7 f/ u9 D' K
- uint32_t Timeout);* `( ~$ @! _; M0 _' q k% K
- HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,4 c! x$ P, R: q# E
- uint32_t Timeout);* ]% R7 H6 r7 {: g
- HAL_StatusTypeDef HAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);# s3 P- ?8 d1 J, J
- HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);- w, w" x) S# W9 v
- 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
- HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码 ( S6 M, q7 y/ C) d' i4 V5 D
这里我再插一嘴,AES是需要加解密数据为16字节的倍数才可以运行,如果你的不是16字节的倍数,那么就需要做一下填充,加解密接口是不提供填充的,需要自己实现
+ w+ _$ g% ^) F, i" _+ ]今天我们的测试的是最基础的阻塞加解密函数
1 T( h! I4 P H* c2.2 AES ECB 128bit加解密测试 我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试 先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上 - /* 计算得到的秘文 */3 L6 ?3 J* p$ H: X( @
- uint32_t Computed_Ciphertext[AES_DATA_SIZE];$ B4 W% J5 K8 s/ `+ [: R1 M
- /* 计算得到的明文 */! j( t$ X5 @' Y% H! g& {& u
- uint32_t Computed_plainText[AES_DATA_SIZE];- n& _6 B0 G, E/ M# B" j0 n% i
' P' C; [; ?+ ]- /* 用户自定义128bit秘钥 */; Y' ^; \3 {$ G: U3 p
- uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =
1 p. |3 h6 l* @, ^/ d' Q0 g" E - {
! Q; z" ?. L7 h" E5 y. V/ g6 E, z - 0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff
, J* P* G& J, N' m2 J( s - }; X' z! m) w: E& Y# q
- /* 加密前的明文 */8 }2 N: d9 h, G- Q
- uint32_t AES_plainText[AES_DATA_SIZE] =
3 a) B p4 h o: g3 D6 j% {+ s - {
; D. U% O7 A/ [ - 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f' t7 Q* U M/ C3 f9 a% `, K% J/ c+ p
- };
7 s5 J2 G9 M: }' t+ L
! v; k8 x. F4 ?- /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */
9 O- J) B U/ X5 p: R! |: _3 M - uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =4 B, E/ J3 w; e1 l5 e0 n
- {& E5 C/ a& s( v
- 0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE003 {; h& ^8 Y$ V+ W, \4 N
- };
5 r" }* q t3 f! H8 O; Z - /* AES ECB使用cube默认128bit秘钥加密后的秘文 */+ ~$ ~/ B: V4 ~
- uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =* n' ~5 Y# u: L" @$ J' P D8 O4 P
- {- ?9 l( ?9 U/ Q, I, z/ N0 Z
- 0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A2827 |/ L# y6 {# P3 V5 U U0 L
- };
复制代码
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的 6 L+ S' p, J+ B
然后在加一下宏定义 - /* AES加解密阻塞式函数超时时间 */
( `/ ]$ u6 L) ]% V3 G - #define AES_TIMEOUT_VALUE 0xFF //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说: X; w8 d/ T, Z' q; B2 ~7 p
- /* AES加解密数据的长度(byte) */& w+ ]8 l/ [( l( \( a+ f$ c8 J
- #define AES_DATA_SIZE_BYTE 16( E: c# A3 O! L' w7 g$ g" o
- /* AES加解密数据的长度(uint32_t) */
$ z, W X8 S+ Z. t9 M3 [ - #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4)+ L- Y/ Q0 M" t) X
- /* AES加解密秘钥的长度(bit) */
7 [2 m9 v# J. ?: i' Y - #define AES_KEY_SIZE_BIT 128
! }- b. D `) @ - /* AES加解密数据的长度(uint32_t) */
$ [# N M) m% Y% Z. m - #define AES_KEY_SIZE (AES_KEY_SIZE_BIT / 4)
复制代码然后写一下AES ECB 128bit秘钥的加解密测试函数以及dump函数 - void dump_data(uint32_t *pData, uint8_t Size)
9 U+ q3 {% k7 X$ Q; E' [1 }9 ^ - {$ a/ g5 T* m5 x) d/ W0 \
- for (uint8_t i = 0; i < Size; i++)
3 O6 [ ?* B) z - {0 b( r2 }2 C1 x& _& T9 o
- printf("%02X ", ((*pData & 0xFF000000) >> 24));
2 ?" @% r/ t; i" z7 q - printf("%02X ", ((*pData & 0x00FF0000) >> 16));0 A* V0 J2 r4 h
- printf("%02X ", ((*pData & 0x0000FF00) >> 8));
+ r# O) G- d1 Y7 f6 k5 ~7 ?% j7 m% o - printf("%02X ", ((*pData & 0x000000FF)));
7 C3 B P8 e: Y9 T! D" P - pData++;( |; _9 ^" n! u
- }
' |8 j9 q! `/ L. D: W4 ?! A$ l' ] - printf("\r\n");
0 y! p" q! S# z) [4 A- D - }- V/ e% j2 e& `: @7 S
- , o# b M0 C: g/ l& W- O3 M
- void AES_encrypt_test(uint32_t *plainText)8 f# R+ G+ n8 L. \# m5 r
- {
4 H7 ? H, O, V) J" h4 u( O - printf("plainText = ");
0 v' H) N# R- `( C% M - dump_data(plainText, AES_DATA_SIZE);
) J# E( L k, [9 E9 j. X
2 X; _. _: b; [# _% c& |- if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK). f5 `4 b- A9 V. j, O
- {
/ W$ s% \" A! N3 {/ [. ?6 B; a - printf("AES encrypt success\r\n"); t1 W9 U1 r; u! [7 _- T+ Z
- printf("Computed_Ciphertext = ");% b! d+ q( c, ~* R; t
- dump_data(Computed_Ciphertext, AES_DATA_SIZE);
8 x/ M( G- A1 L" l" w - }
4 n) J+ D1 b$ ?2 g, { - else/ `+ O" p" ?, E* k p) S
- {+ ^$ K# }3 W. r2 \
- printf("AES encrypt error\r\n");% N5 N j& E) w6 y. O
- Error_Handler();
' g% g, j8 n' d5 z! @ - }# X4 U8 \; L* c& \
- printf("\r\n");; X) P9 X# I# X$ [
- }4 ` ?. @9 Z" Y- J- ^5 O# r4 R
" L/ R- v! b; D3 u/ {3 C! [# H7 n- void AES_dencrypt_test(uint32_t *cipherText)! J. a, _" V8 ^8 A c
- {
; X& H7 n$ D" b: Z$ T- E$ T! a - printf("cipherText = ");6 v( [* x' x) i- h
- dump_data(cipherText, AES_DATA_SIZE);
& s+ b, i% r! d1 c3 r' t( b - 8 P4 k* H$ ]& h/ N
- if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK)4 }8 c* g2 }7 K
- {
1 e/ }& p, l8 ~% w' J: L - printf("AES dencrypt success\r\n");
+ ? e$ Z+ @' @ - printf("Computed_plainText = ");
' {+ t1 g& {( Y5 j - dump_data(Computed_plainText, AES_DATA_SIZE);* F! q& o5 X* D5 l% ]4 T
- }# M0 X: P; F1 A5 t9 S
- else; Q- T+ B% S! l* V* d
- { D/ T+ u) L* f
- printf("AES dencrypt error\r\n");
+ F5 B- F& }1 J2 W$ ? - Error_Handler();
2 k$ _" N+ E: P3 G, H% g( u" y - }$ B# o9 f! {+ G8 E, c5 _& Z
- printf("\r\n");
- s% U/ K' n( r, Z: R$ g - }
复制代码
- \ G8 D2 \( S1 O1 i! B+ k+ l6 ~6 t4 d' T6 K. Z: b" T2 ~
然后在main中调用 - printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");2 u# W0 W( J$ i' |, y
- AES_encrypt_test(&AES_plainText[0]);
) D$ A) {- R$ B - printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n");
+ c( f1 y1 Z+ E; a$ V# e' e - AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码编译运行一下,结果如下 和在线工具对比一下,结果一致 1 Y9 [# \8 f" p2 Y( E: c: d
接下来尝试更换一下秘钥,再运行加解密 更换秘钥有2种方案,第一是直接对MX_AES_Init中的内容修改,但是因为这里是cube自动生成的,后续cube再生成一次就又变回去了。所以我选择方案二:去初始化,修改参数,再初始化。 1 p% m1 {7 x' `0 ], L+ f& u
改变秘钥函数 - void change_key_to_user_defined_AesKey_128bit()' V g0 p, A; d5 V' K
- {; S0 @% m# a' X
- printf("change AES KEY to user_defined_AesKey_128bit\r\n");6 R+ c) o' s: Q3 f7 ? y# K
- /* 先去初始化 */
3 O2 k( N* r5 Y$ Y* f - if (HAL_CRYP_DeInit(&hcryp) != HAL_OK): C8 {- {) R% w9 t
- {
1 ~5 w- i! c* m/ s - printf("HAL_CRYP_DeInit error\r\n");/ f; k' q. H2 N5 a$ h
- Error_Handler();
. J+ F6 L; f5 p& ]; ? - }3 Y4 A, K7 c0 C" H+ m6 }
- , M# E v$ v4 z9 r" Z- b# C+ l( h
- /* 修改使用的秘钥 */
+ V5 _0 G1 D% D! h& M7 Z - hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;
7 v& i$ ^* C" P7 z
. E# L. R. L5 e9 G! p- @. S6 O- /* 再次初始化 */
( N! n1 Z& T! O* { W - if (HAL_CRYP_Init(&hcryp) != HAL_OK)
6 P. I& J3 ] K8 Z s: X - {9 y x" ~6 J+ Y2 \9 n
- printf("HAL_CRYP_Init error\r\n");
/ W; A7 b+ x+ x2 M, Q" d - Error_Handler();
6 x$ a5 e: J( W - }% R6 R7 `9 c" p0 e
- printf("\r\n");. n6 m6 \- A8 j
- }
复制代码 % `$ e) D( s5 `
1 S9 j, k1 ^3 X6 }( k5 ^
然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功 - change_key_to_user_defined_AesKey_128bit();
! S6 G7 W. m. V - 7 c B, |/ ?- V# A' E
- printf("AES ECB use user defined key 128Bit encrypt test\r\n");
9 W) `$ g: |: C - AES_encrypt_test(&AES_plainText[0]);1 U5 q# Y6 D4 I: j
- printf("AES ECB use user defined key 128Bit dencrypt test\r\n");
$ k; p% U3 P2 h& h; S7 I* p9 s* ? - AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码 编译下载运行效果如下 和在线工具对比一下,结果一致 $ ?8 i" ?% I h, p. j( q
2.2 AES CBC 128bit加解密测试 然后我们把AES模式切换至CBC模式,来进行测试 CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下 然后准备一下CBC加密后的结果的数组,回头给解密时使用 - /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */
4 b8 m3 Z6 t( O2 d( Y - uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =/ Y. `& n' j) @+ w$ V
- {
* S3 ^" a" _: t - 0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E783/ m/ |" [8 \( V: l6 L# J
- };
复制代码写一下切换至CBC模式的函数 - void change_to_aes_cbc_mode()
/ J9 C" \0 u. T c, n `9 j - {
0 U. O& j/ z4 M* T' ]- @ - printf("change to AES CBC mode\r\n");
, e5 }* s& c% H% |( e8 ]* P7 N0 `7 x - /* 先去初始化 */: }" p5 x( o T0 d. a+ S
- if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)1 C# D; M, V5 l# D# L( r: w* Z5 |
- {
' b2 \4 \% O8 {+ G4 z1 B e - printf("HAL_CRYP_DeInit error\r\n");9 ]3 W+ C5 Y$ W; L$ Q8 F$ N
- Error_Handler();
5 f9 {6 |3 E% Y1 a. y - }
, G K0 ]0 l2 s6 Q x# M - 8 Q+ H! x/ M3 @ H
- /* 修改为CBC模式 */ r* F- T; l! z& s- l2 y# g
- hcryp.Init.Algorithm = CRYP_AES_CBC;: n* H$ ?( N* u2 S& Z7 E) i1 l8 w
- /* 设置IV */
1 ^. s* b& z& i+ [* @8 O7 u - hcryp.Init.pInitVect = AES_CBC_IV;3 N5 \& c5 y2 \
G& i8 [4 x7 i$ j0 D, x6 E- /* 再次初始化 */+ Y4 r$ J, K" i7 q1 n
- if (HAL_CRYP_Init(&hcryp) != HAL_OK)+ o3 K4 z: q5 g6 |" ]2 e
- {
5 G4 x: ?6 O/ O - printf("HAL_CRYP_Init error\r\n");; T0 b1 H* D2 l: D6 G
- Error_Handler();, X8 N. }3 ~* p9 l+ o
- }
) v3 h( O7 I' b - printf("\r\n");% X! v3 C' ^5 W: H! `+ W1 u+ `+ c
- }
复制代码在main中调用切换函数,然后进行CBC加解密测试 - change_to_aes_cbc_mode();
9 I4 V$ S3 _ S" K3 q% k - 8 ]: ], n W1 A: B0 @" p# b0 w
- printf("AES CBC use user defined key 128Bit encrypt test\r\n");7 P2 |2 H. V W9 O
- AES_encrypt_test(&AES_plainText[0]);
5 q8 q$ Y% Q1 ?& ~ - printf("AES CBC use user defined key 128Bit dencrypt test\r\n");
# k' T. Y; Z5 ?& U" I5 d - AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码编译下载,结果如下 和在线工具对比一下,结果一致 三、总结 今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。 ; S/ b( J# y0 n: V1 U) L
本次工程代码:
STM32U0_AES_test.rar
(5.21 MB, 下载次数: 5)
|
好详细啊👍