|
STM32U08是带硬件AES加解密模块的,硬件加解密的最大优势就是快。 6 i: m' ?* r7 n' I& ~
一、cube配置 首先需要在cube中开启AES模块(工程就是上一篇中创建的模板工程)
+ o3 c4 x- k4 ?' n, V7 C参数这一块主要关注的是加密模式(Data encryption type)、秘钥长度(KeySize)、秘钥(Encryption/Decryption key),其他参数保持默认就可以 其中加密模式支持如下 秘钥长度支持128位、256位 秘钥的值可以在cube中配置,也可以这里保持默认值,回头在代码中重新配置(当然上述的这些参数都可以通过代码再次配置,这个待会实战部分会有介绍) + V8 ? t9 I* y* c7 X+ a+ }3 m
最后点击右上角生成代码
5 G0 b% G' S8 m/ |. j0 @$ Q8 q! b二、实战 2.1 AES时钟初始化及函数介绍 先来看一下CUBE自动生成的代码 首先是变量 - CRYP_HandleTypeDef hcryp;
9 j N5 x( S0 Y# P, V% f - uint32_t pKeyAES[4] = {0x00000000,0x00000000,0x00000000,0x00000000};
复制代码这边的pKeyAES就是秘钥,和之前cube中设置的一致(下面的测试中我会尝试更换秘钥) 然后就是AES模块的初始化函数
: H1 Q, O3 `& h& r5 w* g2 p' j; ~. a, L6 o
在初始化函数中可以看到,配置了各个参数,和cube中的一致。然后就是调用了初始化,秘钥、加密模式等就是在init时配置进去的,如果需要更换,那就要调用HAL_CRYP_DeInit(),修改配置参数,然后再调用HAL_CRYP_Init()(这个待会儿我也会尝试一下)
7 _0 `4 W% d0 l在使用加密前,需要在main函数的最一开始就开启AES的时钟 - __HAL_RCC_AES_CLK_ENABLE();
复制代码
% H( w3 Z8 Y- t0 O/ | l% {( c0 j加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密 具体函数如下 - HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
1 [4 O1 B% p4 w6 T. {# X8 G/ p5 P - uint32_t Timeout);
5 m, c% y7 E+ C( u5 A6 p - HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
0 Y! X- z% V; e2 F - uint32_t Timeout);
/ R# q J7 c# ?; `- n - HAL_StatusTypeDef HAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
6 L+ A5 G% r' l5 N9 r0 C- q - HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
* ^% l7 A! r! w - HAL_StatusTypeDef HAL_CRYP_Encrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
, Y0 c& S( C1 E" }6 f9 M$ @& A - HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码
2 u& u% Z; u5 V- {9 J& m这里我再插一嘴,AES是需要加解密数据为16字节的倍数才可以运行,如果你的不是16字节的倍数,那么就需要做一下填充,加解密接口是不提供填充的,需要自己实现 % i3 U4 p5 q, N9 [7 T
今天我们的测试的是最基础的阻塞加解密函数
7 {$ f9 {) _5 E, t2.2 AES ECB 128bit加解密测试 我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试 先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上 - /* 计算得到的秘文 */1 H9 f9 t- `* |; O
- uint32_t Computed_Ciphertext[AES_DATA_SIZE];+ t f9 e& V/ W, J
- /* 计算得到的明文 */% O1 f3 J" r6 C' t! C
- uint32_t Computed_plainText[AES_DATA_SIZE];* v, y$ { @' u' m, S
* F a% k( i' T8 d1 z( s& w- /* 用户自定义128bit秘钥 *// g Q, d' D6 e4 p9 o; z4 g5 } [
- uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =5 L# W0 j$ x. F- y
- {# j+ x* N$ s! M& j. \, e8 X5 N
- 0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff% a; U5 I0 ~/ y# B
- };
6 @4 a( \0 e8 Q* h% x4 ~7 e - /* 加密前的明文 */9 J. u a, S) E/ K) j) M
- uint32_t AES_plainText[AES_DATA_SIZE] =- A) N# B* h1 u, | b8 C6 p
- {
* x# T; J" N' l: ^' O9 T+ O s - 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f0 K* Y4 \2 f6 C3 K* |4 N. p# X& `
- };
2 r& t5 S9 j F h3 y, W) N - & z9 ^8 z6 B5 ^. e; }: x
- /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */
% r; b3 {* T, S: x1 K - uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
4 G8 W# Q$ b. u$ ?3 b - {
& Z! l" n* c7 r3 ~$ R - 0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE003
" W# t! O4 L' ?; T8 k/ x$ k - };
, B/ p' ` f1 C5 {9 z - /* AES ECB使用cube默认128bit秘钥加密后的秘文 */
* g. N6 Q$ ~6 U7 e: Z1 s - uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =, e) G, H$ R! W; `, c
- {
( e" |. n7 p2 V' o - 0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A282
, `( \9 M+ S/ T7 {+ x( Q" h - };
复制代码
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的 2 c% f5 K4 O f3 M
然后在加一下宏定义 - /* AES加解密阻塞式函数超时时间 */- f: O7 A0 [# n* k1 y2 w0 r
- #define AES_TIMEOUT_VALUE 0xFF //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说$ K" F6 W/ `1 X; s( f4 [
- /* AES加解密数据的长度(byte) */, s2 i- q3 L( ~; Z- [. ^/ _
- #define AES_DATA_SIZE_BYTE 16, _5 F* I& N% }4 v) c& G! C1 [# l
- /* AES加解密数据的长度(uint32_t) */" h# G0 E% Z9 \) q
- #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4)
+ L+ X( a5 o( W$ {/ a w: P6 c - /* AES加解密秘钥的长度(bit) */& {' p/ z# g# @
- #define AES_KEY_SIZE_BIT 1281 u' T9 r1 L# ?( Z* y
- /* AES加解密数据的长度(uint32_t) */ u" a; ^. L* v+ F- k, X3 Z
- #define AES_KEY_SIZE (AES_KEY_SIZE_BIT / 4)
复制代码然后写一下AES ECB 128bit秘钥的加解密测试函数以及dump函数 - void dump_data(uint32_t *pData, uint8_t Size)0 a; v, |' t& l& h" @: n
- {2 M4 Y& x! u! z: M- Q. |' g
- for (uint8_t i = 0; i < Size; i++)
1 K/ D8 o! o1 I9 R3 z$ N" w7 _ - {
% G: e& ^' C* w6 V7 F/ t" P5 O/ { - printf("%02X ", ((*pData & 0xFF000000) >> 24));+ r# V; n7 i) r/ v
- printf("%02X ", ((*pData & 0x00FF0000) >> 16));
$ N O1 e5 Q L$ Q6 U" {% s - printf("%02X ", ((*pData & 0x0000FF00) >> 8));
! Q6 P" q) m1 W$ U - printf("%02X ", ((*pData & 0x000000FF)));
% r0 F6 u/ ~ T, |0 b+ t" d - pData++;
- v# L3 h1 w$ v% j& x+ T* | - }
/ o" ?0 e% f H4 H7 Q7 t' P5 d - printf("\r\n");3 z- t" }% p( F" F3 m
- }# A( ~. I V0 E: z+ z& X/ `1 P4 ?. K
+ ]* w5 k, k( V- void AES_encrypt_test(uint32_t *plainText)
. f+ k8 R& S6 F+ G, g - {0 E3 o6 }* _4 s, f
- printf("plainText = ");" z3 O( J6 S9 P$ u6 c; y6 ^
- dump_data(plainText, AES_DATA_SIZE);
0 d a+ z( ~. w! }3 f6 S' i+ `; \
3 ?4 j% v5 y% b* v- if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK)
4 P# B* L8 f% Y3 |" Z2 e( ~% X - {8 D- o" j( `' k1 ?# u
- printf("AES encrypt success\r\n");
1 V" F* g0 `" R6 C1 W' @. l - printf("Computed_Ciphertext = ");: N- d5 ~" x8 o
- dump_data(Computed_Ciphertext, AES_DATA_SIZE);
( L2 @ L- a, ^ - }
( Y M O1 D- R" W* k( B$ s a z - else
& B; H* U6 \. R - {
2 h9 b6 x$ } r! Z% M7 M - printf("AES encrypt error\r\n");! t& c; A2 u/ l
- Error_Handler();
: Y% f' Y Z& B - }, Y3 X z; W# R; j4 b m; T
- printf("\r\n");2 ?3 N* U; m8 n7 z. |& J
- }. t- {, p- B" y e. {# t b
- 5 q: f. J2 Z! L5 W9 B, O
- void AES_dencrypt_test(uint32_t *cipherText)* S0 h& O7 t6 @( }
- {
9 G7 b( _4 ]* `$ m+ F - printf("cipherText = ");: P" L' t5 k+ U* u1 ^
- dump_data(cipherText, AES_DATA_SIZE);
' s* X8 d7 x- q - ; d: w/ y S, W. ~1 |' i, b
- if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK)% y0 c! Z" J6 N1 D |& B
- {0 D9 z5 { g8 n7 ~ j
- printf("AES dencrypt success\r\n");
+ s3 y4 A- t0 U) r& ~" A - printf("Computed_plainText = ");
) x/ }: D* ~8 `9 m5 [ - dump_data(Computed_plainText, AES_DATA_SIZE);; a$ L8 w4 Z' T5 i$ a
- }
& {) c7 M4 X6 N g+ I9 P - else
8 G, F7 L4 j) G; g+ o5 |7 ]1 u; { - {; N" h9 D0 L$ l9 R6 |
- printf("AES dencrypt error\r\n");
: s4 ~7 c8 U$ V" o& x - Error_Handler();
0 o! n3 v: }, `9 L - }
. i, Q$ o' X! s8 \2 x7 @; h. v - printf("\r\n");
9 R) b( E" r" l6 D" w0 w- ]/ l - }
复制代码
& F8 ~% U& W) c2 G- u
8 H# T* J/ o# n" Y# I) W; w# W
然后在main中调用 - printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");: y% ?& R* i' K; N/ v% ^3 W
- AES_encrypt_test(&AES_plainText[0]);
- _- G* ]6 x7 K0 ^3 B - printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n");5 V9 w. X* |4 P" D! Y
- AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码编译运行一下,结果如下 和在线工具对比一下,结果一致 ) X1 G3 J1 ^3 H) A9 C. ?
接下来尝试更换一下秘钥,再运行加解密 更换秘钥有2种方案,第一是直接对MX_AES_Init中的内容修改,但是因为这里是cube自动生成的,后续cube再生成一次就又变回去了。所以我选择方案二:去初始化,修改参数,再初始化。 9 [9 T; `" q+ f1 o' y4 s j+ J! b
改变秘钥函数 - void change_key_to_user_defined_AesKey_128bit()0 W1 c4 n b: }( ~* ]7 t1 q
- {6 Y6 f/ |" h% B+ C
- printf("change AES KEY to user_defined_AesKey_128bit\r\n");5 w7 k. Q: t: S9 @9 H
- /* 先去初始化 */5 {: S7 u- K; R7 p0 p$ m
- if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)
1 V1 q n+ @ v+ h ~0 U - {
& a* c! G/ t( @. S; z1 S2 R - printf("HAL_CRYP_DeInit error\r\n"); C+ m5 N1 U% E) h; W8 Y3 d
- Error_Handler();
! i- x. t+ o; ~5 Y - }
8 r9 C4 X- R$ m* T2 h: {& s9 S - ( N) `1 o; S n2 `/ V0 E
- /* 修改使用的秘钥 */0 |9 K, @# y5 M
- hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;
0 N+ s3 F6 U+ p4 I( }9 c" B' D - + M3 B/ v. z9 g' @. |3 c* `
- /* 再次初始化 */
1 d3 i' d5 z+ J0 t - if (HAL_CRYP_Init(&hcryp) != HAL_OK)7 A, E& L( `4 g) C9 o4 y% m
- {
( Z: I5 D# A4 q. p! p - printf("HAL_CRYP_Init error\r\n");5 d* M- \+ v9 D; b2 V
- Error_Handler();
, \! M! S! N3 A+ Q8 ^1 z - }: n( B7 {8 i+ n/ G5 J& Z( M8 L' x& v
- printf("\r\n");
* \, j3 Y; E. c - }
复制代码 4 J% I- d1 o6 _. n
0 F0 w8 ?: q1 R& n& A然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功 - change_key_to_user_defined_AesKey_128bit();7 O, j' \# z4 B8 n* R' m
- / N. A) O3 w; e8 P6 W
- printf("AES ECB use user defined key 128Bit encrypt test\r\n");
% `: J$ G5 |0 m" y - AES_encrypt_test(&AES_plainText[0]);9 D1 S o6 \ M& d# C
- printf("AES ECB use user defined key 128Bit dencrypt test\r\n");
1 c/ N" U8 O/ M - AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码 编译下载运行效果如下 和在线工具对比一下,结果一致
4 C- T5 g4 ~8 O L+ e2.2 AES CBC 128bit加解密测试 然后我们把AES模式切换至CBC模式,来进行测试 CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下 然后准备一下CBC加密后的结果的数组,回头给解密时使用 - /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */- W/ v$ D- m6 g9 q& ~3 w
- uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =; y! t9 G" `0 Q7 n @" |
- {7 P" L. y b+ @+ d
- 0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E783
: F% F9 X: c& y1 T; C( }' u$ b - };
复制代码写一下切换至CBC模式的函数 - void change_to_aes_cbc_mode()8 G) W6 n* s: V" c
- {# N2 c! d* n7 X0 d% q
- printf("change to AES CBC mode\r\n");
4 G7 l3 ^% ^9 L8 q4 u2 f A& p - /* 先去初始化 */- U, g$ O, h8 H8 g
- if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)$ N1 l9 ~' U5 A3 A6 }# s* w
- {/ |2 O) Q ]& h& @5 d+ j
- printf("HAL_CRYP_DeInit error\r\n");* b# U$ u1 E9 n- q1 c
- Error_Handler();
( }* \, t6 w; s. f/ o - }
2 u7 R* W+ E+ ^1 {! g& G! d% ~ - + z% Z7 L6 ?2 ]. z
- /* 修改为CBC模式 */
" F2 R, K1 v/ `$ s# D - hcryp.Init.Algorithm = CRYP_AES_CBC;
" O( G( W# C: W e - /* 设置IV */+ [9 W4 n9 m6 ]2 B6 C* _
- hcryp.Init.pInitVect = AES_CBC_IV;
8 A. o$ z; z N6 G/ X
& W- l1 n, J+ E# {7 [5 g- /* 再次初始化 */- J, z' m* E# j9 M9 @& l
- if (HAL_CRYP_Init(&hcryp) != HAL_OK)" E5 ]+ P H$ y2 K0 I9 q" Y
- {
, c6 q% A& S A1 T$ a - printf("HAL_CRYP_Init error\r\n");
- \5 M9 i* D! }! P) T! w/ L9 M - Error_Handler();
. N. G$ }4 }7 t# ?/ g. Y - }6 C; j4 G( j9 ~9 `+ F
- printf("\r\n");
5 z9 n1 C" f, ~2 S4 b& S9 m, f* K - }
复制代码在main中调用切换函数,然后进行CBC加解密测试 - change_to_aes_cbc_mode();' P5 S* p+ f* @; O! ^
; ^$ s1 y0 _( X+ o7 G. I r- printf("AES CBC use user defined key 128Bit encrypt test\r\n");
5 T2 W9 Y5 w; ]& w. b( |' E - AES_encrypt_test(&AES_plainText[0]);7 Y* O& S7 G9 k# r4 ^
- printf("AES CBC use user defined key 128Bit dencrypt test\r\n");; B) ?% G# E O- o4 R4 E+ ]
- AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码编译下载,结果如下 和在线工具对比一下,结果一致 三、总结 今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。
- \9 J* a" D: c" q本次工程代码:
STM32U0_AES_test.rar
(5.21 MB, 下载次数: 5)
|
好详细啊👍