|
STM32U08是带硬件AES加解密模块的,硬件加解密的最大优势就是快。
; |, ~" m% d& p一、cube配置 首先需要在cube中开启AES模块(工程就是上一篇中创建的模板工程)
1 ^/ p1 f& R8 @3 K+ `- J参数这一块主要关注的是加密模式(Data encryption type)、秘钥长度(KeySize)、秘钥(Encryption/Decryption key),其他参数保持默认就可以 其中加密模式支持如下 秘钥长度支持128位、256位 秘钥的值可以在cube中配置,也可以这里保持默认值,回头在代码中重新配置(当然上述的这些参数都可以通过代码再次配置,这个待会实战部分会有介绍)
6 m& L2 l0 R& {, N q最后点击右上角生成代码
" u9 j2 Y" K( E* I, p+ g- X二、实战 2.1 AES时钟初始化及函数介绍 先来看一下CUBE自动生成的代码 首先是变量 - CRYP_HandleTypeDef hcryp;) H( l5 l: F. m/ t9 o& T
- uint32_t pKeyAES[4] = {0x00000000,0x00000000,0x00000000,0x00000000};
复制代码这边的pKeyAES就是秘钥,和之前cube中设置的一致(下面的测试中我会尝试更换秘钥) 然后就是AES模块的初始化函数
& c5 G% V! Z; x5 ]+ F- k
# z! J' Z. P1 U- O" }在初始化函数中可以看到,配置了各个参数,和cube中的一致。然后就是调用了初始化,秘钥、加密模式等就是在init时配置进去的,如果需要更换,那就要调用HAL_CRYP_DeInit(),修改配置参数,然后再调用HAL_CRYP_Init()(这个待会儿我也会尝试一下) , L; d# y/ ^. P2 w) t+ x
在使用加密前,需要在main函数的最一开始就开启AES的时钟 - __HAL_RCC_AES_CLK_ENABLE();
复制代码
8 R2 R: b/ N( o1 E& v加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密 具体函数如下 - HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
+ A( H) B, p' v - uint32_t Timeout);. b+ E0 Z" _2 @# u# W, ~) ~1 d
- HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
8 ?, R" _ y1 b2 t0 R0 n& F' h0 m - uint32_t Timeout);
, Y" Q+ X$ t! y - HAL_StatusTypeDef HAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);: n4 d9 o2 G4 |8 R% Y3 [! t
- HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);$ V$ R; i+ f: L' K
- HAL_StatusTypeDef HAL_CRYP_Encrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
! r4 h7 Z6 O# @9 v - HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码 . K: @- }6 F( t6 ^
这里我再插一嘴,AES是需要加解密数据为16字节的倍数才可以运行,如果你的不是16字节的倍数,那么就需要做一下填充,加解密接口是不提供填充的,需要自己实现 ! Z& H% A) d! M
今天我们的测试的是最基础的阻塞加解密函数 7 t0 b2 e% }! _) d6 A
2.2 AES ECB 128bit加解密测试 我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试 先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上 - /* 计算得到的秘文 */6 V( R/ X b+ H: @7 k, E3 e
- uint32_t Computed_Ciphertext[AES_DATA_SIZE];9 q) y7 j- O: g+ L
- /* 计算得到的明文 */
! D/ o, w$ j `# b H - uint32_t Computed_plainText[AES_DATA_SIZE];
/ m4 V8 a9 K H0 C. E
' @/ _3 _# d) U' h- /* 用户自定义128bit秘钥 */
4 o" h4 |# ^0 c' o - uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =. L2 a: n2 l$ Y, K& _) H
- {! S7 I, D; y' |+ |& Y+ W
- 0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff i7 A9 s: {, T7 N& G+ e
- };
9 ^3 r1 p' L, O! j - /* 加密前的明文 */
. f$ E0 ]( L% `8 @; y% R - uint32_t AES_plainText[AES_DATA_SIZE] =% V1 A0 v$ x3 _
- {" v7 I2 v h0 w6 i& d
- 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f9 u2 k* B; T8 `
- };, g0 r% H1 F- s7 Y. b
+ _7 ?0 i# a$ r9 {* v- /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */8 L9 E! f- ]. G B+ w a% T5 G8 K
- uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
3 U5 u2 k8 ?7 U( Y( S" p! d9 B - {3 z: b# G. A# }8 R2 S
- 0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE0036 m" D9 e* _" l! F* t
- };; N1 ? e3 y" z+ _; a: ]% Z
- /* AES ECB使用cube默认128bit秘钥加密后的秘文 */
) u9 P7 s7 L7 a* F8 ^$ E$ [3 f - uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =5 j& \7 v8 F) W$ a% X
- {# r% k" K- M1 ~3 v+ G1 f! K1 p
- 0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A282
7 o& x' s$ _9 M; x, E* g - };
复制代码
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的
( b8 \: p5 z: B) N然后在加一下宏定义 - /* AES加解密阻塞式函数超时时间 */- }( H3 E% I* C4 c2 |9 b
- #define AES_TIMEOUT_VALUE 0xFF //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说- S3 y& \0 ^% t0 L2 Q
- /* AES加解密数据的长度(byte) */$ v/ V% I6 ?& J8 Q) E% _* }9 C q0 R
- #define AES_DATA_SIZE_BYTE 16. L7 s) H' H! V8 h0 M9 c! o) u; a
- /* AES加解密数据的长度(uint32_t) */$ v4 `2 ^2 B4 h, l) O5 f! J6 U7 X
- #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4)4 a6 p) j, }8 ?7 D; [6 W8 G$ ^: W* g
- /* AES加解密秘钥的长度(bit) */7 k. y# P4 r6 D4 _; P1 k
- #define AES_KEY_SIZE_BIT 128. C+ b0 B3 }) e2 G$ [# C
- /* AES加解密数据的长度(uint32_t) */
( d0 K$ L* r; ~& d8 \ - #define AES_KEY_SIZE (AES_KEY_SIZE_BIT / 4)
复制代码然后写一下AES ECB 128bit秘钥的加解密测试函数以及dump函数 - void dump_data(uint32_t *pData, uint8_t Size)
4 P v3 d3 h7 Z# ? - {
! m; e% y0 j# }3 ^ - for (uint8_t i = 0; i < Size; i++)
" s1 H3 t. u7 ^+ u; H$ d7 C - {
5 Z' U2 o$ d$ l z) u b0 S9 g - printf("%02X ", ((*pData & 0xFF000000) >> 24));
1 ^8 T6 v0 i% G! A4 w/ F& e1 ` - printf("%02X ", ((*pData & 0x00FF0000) >> 16));
. J* \" ]( y/ V2 O% o - printf("%02X ", ((*pData & 0x0000FF00) >> 8));, N0 y9 q0 R. C6 B2 \
- printf("%02X ", ((*pData & 0x000000FF)));3 d4 O- i, V0 `& X' Z! h. \$ g8 q
- pData++;
0 f; l# a0 Q2 \/ X' x9 ` - }- d+ `% v) g: ] a
- printf("\r\n");
9 e @% v+ X- m. D% A% W - }9 s6 ]& W. S& k1 G
- - \* W u1 n- b. E; L
- void AES_encrypt_test(uint32_t *plainText)
4 r% z! A1 Z& l/ S% ?& W4 P) H - {. |0 V+ l, U3 O, d3 Y
- printf("plainText = ");
7 x+ \# B9 _+ c1 e; A, s4 A - dump_data(plainText, AES_DATA_SIZE);
8 [) e9 M* D8 f$ l$ ?0 C - " }, l5 K' y- ]: U: |1 B
- if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK)2 ]! I! |' [$ ?5 ^! u8 q
- {& ?7 \& @: ?- w/ o( e
- printf("AES encrypt success\r\n");# ]( b5 \( z7 ^4 o( L
- printf("Computed_Ciphertext = ");
! r2 U, P6 M- V% ]# @3 g - dump_data(Computed_Ciphertext, AES_DATA_SIZE);
5 s8 N6 P$ D) w2 D( E d - }
1 Y* M8 ?! ]/ a1 M3 ^0 i - else. N J) O' o. Y# u9 _% g5 g3 z0 Z' p
- {
3 w0 o# N1 p/ O2 t& A6 T - printf("AES encrypt error\r\n");& o* ^6 J \# P. B
- Error_Handler();
. i+ `) N# Q7 {) j - }' G' L7 B1 V3 t C
- printf("\r\n");" ^5 N& F$ Y1 ^. a$ y
- }
1 G$ t$ x) ]; [* e) p - ) f0 W; S0 W1 a3 t p
- void AES_dencrypt_test(uint32_t *cipherText)
: R" z& G: _9 z. u8 E, e3 [ - {1 T6 D3 l- M, O: e
- printf("cipherText = ");
2 A; h4 K9 @! d2 c5 k - dump_data(cipherText, AES_DATA_SIZE);
# b: S. H2 Q8 B - ; z. k: S, o7 P: r+ Z5 J( q& L
- if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK) ]; z$ X( u5 p8 ]5 b7 l: o
- {
3 M8 l7 ?3 P' G* a. F - printf("AES dencrypt success\r\n");
% h/ v# |; h( O+ r( o, G9 p& k/ t - printf("Computed_plainText = ");
8 {9 D" ?& Z7 X" ]0 O - dump_data(Computed_plainText, AES_DATA_SIZE);
/ `! h7 G/ I! v - }* v. r0 D& m7 A: c6 w4 L
- else! G7 j! T0 u* q; A& ~. Y
- {
. }. H% X$ Z! Z# f3 s0 Q - printf("AES dencrypt error\r\n");, l2 b4 z8 N: i# ]( u
- Error_Handler();
& C+ q) J! ]2 D" L2 P( }7 q - }2 s+ n& I2 S$ _- S( p5 j
- printf("\r\n");% ^* g0 Z. x1 Q; O v- n5 g2 O9 W
- }
复制代码
2 h) U6 d0 Y U6 H4 ]8 `6 Y+ Y T2 U# k! h' w% O
然后在main中调用 - printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");8 C, F, c9 V9 f+ g' C7 m
- AES_encrypt_test(&AES_plainText[0]);4 @1 E: J; m+ Q
- printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n");% n' N9 S# h7 ~# n
- AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码编译运行一下,结果如下 和在线工具对比一下,结果一致
1 m: P; Z5 O: Y4 b/ c" Y接下来尝试更换一下秘钥,再运行加解密 更换秘钥有2种方案,第一是直接对MX_AES_Init中的内容修改,但是因为这里是cube自动生成的,后续cube再生成一次就又变回去了。所以我选择方案二:去初始化,修改参数,再初始化。
2 v9 l2 z: o1 }. P0 g改变秘钥函数 - void change_key_to_user_defined_AesKey_128bit()
V! O8 C: G* s0 K& h& J% Z - {
0 e( I3 H% E0 C - printf("change AES KEY to user_defined_AesKey_128bit\r\n"); S1 d& C; G8 V" W/ a7 }9 T6 O
- /* 先去初始化 */
3 K& ~0 [" j3 D - if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)# D1 s2 D7 ?( ~3 D
- {
; d1 B8 y `% | - printf("HAL_CRYP_DeInit error\r\n");
7 H! W* J% j: g4 [2 ~ - Error_Handler();
/ A- M: R# ^& T: V - }
1 A# y; e% r! w- m8 z- n - 3 L7 c0 N7 f2 Z4 |1 c$ {
- /* 修改使用的秘钥 */" M4 [' o9 P8 j1 l6 x7 h
- hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;
1 ~6 g# u. m0 X! ?, @+ n! g
. E: p' C5 T* [1 ^- /* 再次初始化 */
! T& j4 u V: @ - if (HAL_CRYP_Init(&hcryp) != HAL_OK)
6 U) ]& i( d% W6 ^5 E3 | - {7 `6 e; h, E0 N" A# W9 o& e5 S
- printf("HAL_CRYP_Init error\r\n");
, L7 C6 C2 `3 I6 s0 W ^( P3 g - Error_Handler();
0 j3 l, c; X4 E% A& e, w9 k( u - }, u) D# D. Z+ \' ~
- printf("\r\n");' w5 b C4 ~, [9 z* y
- }
复制代码
. r3 } q5 V* ?( X+ }8 H8 O4 `2 B, r/ M6 H3 K
然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功 - change_key_to_user_defined_AesKey_128bit();
1 A1 \: F) L% A! b! b
) I4 k* X( {: V- M- printf("AES ECB use user defined key 128Bit encrypt test\r\n");+ b0 u" O: |7 H, ?5 N$ {/ E
- AES_encrypt_test(&AES_plainText[0]);/ T; D, P2 X/ C- m" }
- printf("AES ECB use user defined key 128Bit dencrypt test\r\n");5 t+ ^5 q: s* z J+ T3 _
- AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码 编译下载运行效果如下 和在线工具对比一下,结果一致
: {5 ], s5 Z. ]8 B2.2 AES CBC 128bit加解密测试 然后我们把AES模式切换至CBC模式,来进行测试 CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下 然后准备一下CBC加密后的结果的数组,回头给解密时使用 - /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */
, j- ]2 a9 V5 _. B9 k - uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
6 O* R% r1 q2 t5 ~# S( b - {, w; b0 r8 ^* h7 ~- A
- 0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E783- O# H5 W: Y1 T
- };
复制代码写一下切换至CBC模式的函数 - void change_to_aes_cbc_mode(). j0 s ^2 V2 o5 d$ Y( C
- {
2 T' s4 H. l8 W9 {/ b( i+ D; h0 K - printf("change to AES CBC mode\r\n");
* p5 F- V- f, ?# V - /* 先去初始化 */
) o5 G1 l6 b$ c6 p# ? - if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)
! H( q; {; H0 @ - {
4 f# d2 N0 M! G$ K! v7 f) X# _ - printf("HAL_CRYP_DeInit error\r\n");& N# E j$ g: @& _
- Error_Handler();" I' |& b4 t* b0 L* {$ C
- }
" L5 b7 r' Q- U; }8 f - 1 H, `8 m) S ~. L3 L5 p
- /* 修改为CBC模式 */
6 `, B' L2 w6 f( Z - hcryp.Init.Algorithm = CRYP_AES_CBC;$ D5 X( t$ Y3 V! I" s5 G' O
- /* 设置IV */: k. I: A4 @& `
- hcryp.Init.pInitVect = AES_CBC_IV;1 r7 f2 G( T# I
- 3 m; ?/ V$ |/ ]7 J
- /* 再次初始化 */" } b; a/ T n+ t3 ? c/ m K9 J
- if (HAL_CRYP_Init(&hcryp) != HAL_OK)
4 X4 H# m W: T7 c- O2 O7 t# i& C0 r - {4 a! _. T0 n. W& n" |7 b
- printf("HAL_CRYP_Init error\r\n");
9 [9 k1 p% _: z7 N9 k+ S - Error_Handler();* F0 y/ r: w' j. }9 X- v$ p
- }/ P/ A' T) u% `. e
- printf("\r\n");) K* L, G2 t+ b
- }
复制代码在main中调用切换函数,然后进行CBC加解密测试 - change_to_aes_cbc_mode();8 U. z/ ?' \2 _6 r. j% B$ e" f
- / }& Y4 r8 B; n. W
- printf("AES CBC use user defined key 128Bit encrypt test\r\n");
( X" Q( P1 i2 x1 I. ` g - AES_encrypt_test(&AES_plainText[0]);
2 H# X5 x: r) I( |! G - printf("AES CBC use user defined key 128Bit dencrypt test\r\n");/ F5 A" X T: s/ z0 P) z
- AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码编译下载,结果如下 和在线工具对比一下,结果一致 三、总结 今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。
* p0 o, i; B; A$ t J* S本次工程代码:
STM32U0_AES_test.rar
(5.21 MB, 下载次数: 5)
|
好详细啊👍