STM32U08是带硬件AES加解密模块的,硬件加解密的最大优势就是快。
& l6 X) l5 z; e6 l# |; h) X! z一、cube配置 首先需要在cube中开启AES模块(工程就是上一篇中创建的模板工程) ) J( A, Q: ]& {( \& R+ n
参数这一块主要关注的是加密模式(Data encryption type)、秘钥长度(KeySize)、秘钥(Encryption/Decryption key),其他参数保持默认就可以 其中加密模式支持如下 秘钥长度支持128位、256位 秘钥的值可以在cube中配置,也可以这里保持默认值,回头在代码中重新配置(当然上述的这些参数都可以通过代码再次配置,这个待会实战部分会有介绍)
* C' \1 `/ {; U9 T最后点击右上角生成代码 $ ^1 B t1 Z, a( Y* K/ }" T
二、实战 2.1 AES时钟初始化及函数介绍 先来看一下CUBE自动生成的代码 首先是变量 - CRYP_HandleTypeDef hcryp;
. J- g) b& N2 K4 `" z9 X - uint32_t pKeyAES[4] = {0x00000000,0x00000000,0x00000000,0x00000000};
复制代码这边的pKeyAES就是秘钥,和之前cube中设置的一致(下面的测试中我会尝试更换秘钥) 然后就是AES模块的初始化函数 2 x( J2 @6 A; a, t
& q; e M: c7 R; G# N& F在初始化函数中可以看到,配置了各个参数,和cube中的一致。然后就是调用了初始化,秘钥、加密模式等就是在init时配置进去的,如果需要更换,那就要调用HAL_CRYP_DeInit(),修改配置参数,然后再调用HAL_CRYP_Init()(这个待会儿我也会尝试一下) ) y% {7 G( v$ Z+ t |
在使用加密前,需要在main函数的最一开始就开启AES的时钟 - __HAL_RCC_AES_CLK_ENABLE();
复制代码 ' r) |4 N3 S1 }3 h1 z( }) n" @
加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密 具体函数如下 - HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
5 M% V- V6 Y9 j$ @" Y1 b - uint32_t Timeout);
* |, A* y2 Q' F. |% x - HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,1 B" S- Q, d2 F1 Q1 ]5 z
- uint32_t Timeout);5 i) ] K1 n+ |6 N: f
- HAL_StatusTypeDef HAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
6 P+ y; k3 y$ I6 T& E - HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
9 Q- |7 l4 u, ~+ L- c* d: p - HAL_StatusTypeDef HAL_CRYP_Encrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
* x# ? k# H3 X5 T3 } - HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码
+ j2 p$ y" _- m2 X( |: O这里我再插一嘴,AES是需要加解密数据为16字节的倍数才可以运行,如果你的不是16字节的倍数,那么就需要做一下填充,加解密接口是不提供填充的,需要自己实现 8 n3 G) {3 ^' }
今天我们的测试的是最基础的阻塞加解密函数
5 T$ @- F. D: W/ S. e' f2.2 AES ECB 128bit加解密测试 我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试 先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上 - /* 计算得到的秘文 */
" Q* T7 m4 F5 Q - uint32_t Computed_Ciphertext[AES_DATA_SIZE];- f, q5 n! _2 k4 L7 b _7 g0 y& ~0 O
- /* 计算得到的明文 */
& [$ D) h3 l+ h+ P+ j - uint32_t Computed_plainText[AES_DATA_SIZE];" b: Q6 t% q0 f7 i3 k
4 s4 m8 |( F' K8 e) G+ s x1 @$ Q- /* 用户自定义128bit秘钥 */9 M, F5 X, K# H/ U2 v2 `
- uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =* O2 k3 X! P) y2 r. F8 @ r/ z
- {' e. V0 |. K% L. f
- 0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff
' ~3 q! y2 L+ B0 ?8 H8 Q4 H8 z& C( l/ I - };7 N$ q# q( A* I% _6 l2 O' |4 y
- /* 加密前的明文 */& x7 r$ f* [- Q0 Y+ ^5 F: f. _
- uint32_t AES_plainText[AES_DATA_SIZE] =
( p( {# j: s& @9 m - {
1 A# y, S% | A5 n - 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f: X) y' |: s8 g4 g9 J
- };/ h: q G" C; S( T) y, N
- * ?2 N9 T$ N I* d' E/ `
- /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */
9 V+ K! |2 o0 H. g - uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =$ P6 `( G3 z- `$ r( a: H6 A$ h
- {
) o0 i) V! m: @0 G- ~ - 0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE0036 h; k9 \! s5 g8 A! G5 D$ c( Q0 C
- };
4 F" G3 N. B+ }. j# p - /* AES ECB使用cube默认128bit秘钥加密后的秘文 */
& S x, j9 K# Q, T( W1 H - uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =0 @' P" K5 B! e* d) x
- {0 D, X& B ]1 {# Z& ?& l4 J. @
- 0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A282
& ?. Z* _; ^5 x9 M1 \6 r - };
复制代码
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的
# M+ G0 X+ n+ y" \& Y u然后在加一下宏定义 - /* AES加解密阻塞式函数超时时间 */) \8 }' n8 c4 C
- #define AES_TIMEOUT_VALUE 0xFF //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说
- Q# D( x9 i" J: t l6 |% ?' d - /* AES加解密数据的长度(byte) */6 Y3 |1 e J r! D2 C, M/ S+ z7 {9 Q5 W
- #define AES_DATA_SIZE_BYTE 168 c$ A) J' f" f7 q
- /* AES加解密数据的长度(uint32_t) */( w( m1 c4 z4 p+ H, z# n( M. F
- #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4)! g& e o" p" Y% Y T1 p- w
- /* AES加解密秘钥的长度(bit) */
& w) @' A" S8 s6 G0 j$ ? m - #define AES_KEY_SIZE_BIT 128
8 o O1 L$ ^1 N# v( @, {( @ - /* AES加解密数据的长度(uint32_t) */; v$ S+ o" {) G; }; i1 J6 G; F
- #define AES_KEY_SIZE (AES_KEY_SIZE_BIT / 4)
复制代码然后写一下AES ECB 128bit秘钥的加解密测试函数以及dump函数 - void dump_data(uint32_t *pData, uint8_t Size)
1 j& P* Z, y+ s" o2 V0 \/ a - {
4 E+ z) G0 h2 D4 q+ |9 ? - for (uint8_t i = 0; i < Size; i++)
4 x `! g4 L/ o* h* R3 {- v - {
, v5 Z# @0 K/ p2 g - printf("%02X ", ((*pData & 0xFF000000) >> 24));+ S7 O0 _2 J( [4 ^$ T5 o
- printf("%02X ", ((*pData & 0x00FF0000) >> 16));6 f+ O! W# |6 Z& a
- printf("%02X ", ((*pData & 0x0000FF00) >> 8));
) G1 \! D' A( D3 |! ^ - printf("%02X ", ((*pData & 0x000000FF)));
; A3 `) z( [3 D) i. K* L" @ - pData++;; K( b w7 q& o
- }
+ ?+ G5 O% @1 ]) A) M3 {$ k9 ^ - printf("\r\n");' f2 V) b: T+ \8 O6 T4 }! U
- }
( {" l" d0 Y1 ~+ Z( n7 i. o3 T! H
4 B" K; s- j* G0 z2 a8 j- void AES_encrypt_test(uint32_t *plainText)
3 f8 m( B- M2 G0 Y# z e! o - {
9 L2 K$ ]: `) F - printf("plainText = ");
/ J% |3 H. A! P7 C7 p: X) J2 E - dump_data(plainText, AES_DATA_SIZE);
1 |+ N( U$ m# j, ?
) @8 K( O" V/ u1 k$ E- if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK)
' p4 u% z1 d0 R w3 q3 v - {
O( p; Y2 P1 S' S! T - printf("AES encrypt success\r\n");: j: S; B6 a, d1 O7 N3 g
- printf("Computed_Ciphertext = ");4 ?5 x5 G/ \9 S h
- dump_data(Computed_Ciphertext, AES_DATA_SIZE); _8 _( {( k& }1 a
- }- h, x0 n: r G7 {! S! ]- j' h
- else
; R. L c+ Z' u4 u: o - {
3 a# {" ~. r8 I% G) [7 X - printf("AES encrypt error\r\n");
: g( }" M8 z6 s: ^* L: Z& R! ^ - Error_Handler();
- S3 t! v# m. L - }- z+ |% h2 @2 b: S6 P/ k8 f; Z
- printf("\r\n");% j( D$ D- e( J% Z& c4 N# g( A
- }/ O8 j% v7 N9 x8 T
( p* d( j. V4 p4 f# Y `4 C- void AES_dencrypt_test(uint32_t *cipherText)
2 K) W" D$ s" H6 S - {+ m/ n& } L6 j. q
- printf("cipherText = ");, ], `& e0 _5 q ]/ O- H8 U
- dump_data(cipherText, AES_DATA_SIZE);; K6 [# ^8 x) e
- / I; q( q$ B2 r. Z- C- U5 `
- if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK)' P6 W+ B( n9 G8 l2 T# l7 q
- {7 x. L8 w, M, u, e, _
- printf("AES dencrypt success\r\n");* w0 o8 ?. q8 p' ^; W- p
- printf("Computed_plainText = ");
- o/ k- H1 e' R1 o) c, @ - dump_data(Computed_plainText, AES_DATA_SIZE);% F ^2 Z" T9 d3 O3 V# @& u
- }/ }! W9 H. ~! Z) X0 \! L# E
- else
4 R& K+ m8 `! X! u' r# H; j# P - {+ z, L1 k/ f) g' g1 ? X
- printf("AES dencrypt error\r\n");
* j' m5 ?6 L6 M4 [ - Error_Handler();
4 P A' f; Z( x8 ~" N - }
5 S3 @! K' P! [# I2 d- s - printf("\r\n");
1 f! n# U+ D2 Y0 |5 x1 K - }
复制代码
2 O8 `# Y/ u: u7 q1 }# K
8 c$ t! Y; ]0 ~: f( B, g3 J然后在main中调用 - printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");9 S9 J: o6 A+ e) X# w
- AES_encrypt_test(&AES_plainText[0]);6 h6 p0 i+ \5 U; m* ~
- printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n"); d, D! [ f& p& b
- AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码编译运行一下,结果如下 和在线工具对比一下,结果一致
3 V7 |/ H( j9 m, K3 [4 y! ~' G) r% A接下来尝试更换一下秘钥,再运行加解密 更换秘钥有2种方案,第一是直接对MX_AES_Init中的内容修改,但是因为这里是cube自动生成的,后续cube再生成一次就又变回去了。所以我选择方案二:去初始化,修改参数,再初始化。 2 u" E; L o+ X G
改变秘钥函数 - void change_key_to_user_defined_AesKey_128bit()
( k8 m: F9 r1 L, _( X& v" x - {
9 B" `$ U; L& L7 A& [% ~ - printf("change AES KEY to user_defined_AesKey_128bit\r\n");- l0 j. K9 M6 l, U8 V
- /* 先去初始化 */
/ H9 [8 t6 A+ M2 A+ g - if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)
( s* M1 [" x" |! u2 [% I5 T - {, u$ q4 p/ K+ R1 M! T
- printf("HAL_CRYP_DeInit error\r\n");* ?: O* v& z+ v3 e0 c: g/ y; D
- Error_Handler();0 W3 s; w" T: C* L- f' @: n
- }
9 {( L3 }9 c; Y: S0 @' O* D* M! q/ |
0 b" {5 `4 D) ~% d' G9 _1 O& n- /* 修改使用的秘钥 */5 [% m; M( j' h* t4 [
- hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;5 H1 s6 G1 s W
. J* ~6 G) y7 @- /* 再次初始化 */, E4 z& f, n/ N2 c/ Z5 D
- if (HAL_CRYP_Init(&hcryp) != HAL_OK)4 E: L% t p& t/ x$ o2 X) A2 W- y2 `
- {
$ c6 p3 i. X' c* @' I1 h4 C - printf("HAL_CRYP_Init error\r\n");
o0 F2 m( p" B4 K - Error_Handler();
3 q4 l$ ]( T0 s& P7 ^: w - }2 L6 b* I8 \, d1 ~
- printf("\r\n");' _- r7 _ Y& x
- }
复制代码 0 p9 B1 i9 B6 u: z
% I; Z, [. A: `; n& Z7 h3 S: b
然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功 - change_key_to_user_defined_AesKey_128bit();
* X- P+ Q& f% h* u" q6 N6 I5 S - ! V5 N0 k6 G+ @+ |9 a) F% H$ |2 ~
- printf("AES ECB use user defined key 128Bit encrypt test\r\n");, ^4 j) ^# K8 X. l% C
- AES_encrypt_test(&AES_plainText[0]);
+ o3 M+ f9 w4 u% k' N. A. h - printf("AES ECB use user defined key 128Bit dencrypt test\r\n");
" h7 n9 z8 x) G; k: T - AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码 编译下载运行效果如下 和在线工具对比一下,结果一致
1 f, }1 `: a2 p0 Z m4 |8 d2.2 AES CBC 128bit加解密测试 然后我们把AES模式切换至CBC模式,来进行测试 CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下 然后准备一下CBC加密后的结果的数组,回头给解密时使用 - /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */7 \5 k9 k" e- |
- uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =2 Q. Y0 Q! M+ f1 ~9 I, ~
- {# r5 F) _1 Q" I3 d& m; ]
- 0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E7838 P3 ~. G+ p3 Y- m. P# f
- };
复制代码写一下切换至CBC模式的函数 - void change_to_aes_cbc_mode(), `9 s3 t8 Q! h. m) G* d! b% p
- {+ t$ [8 ?: X- D
- printf("change to AES CBC mode\r\n");
0 i3 v; y1 g8 V+ Q6 e - /* 先去初始化 */
. j$ U0 Z1 X* h" t/ \ f - if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)$ q9 T8 G0 I$ q7 Q h# |
- {3 |: j8 n+ g) H0 a" i% G# s6 R
- printf("HAL_CRYP_DeInit error\r\n");
3 u( S) r- s* c5 M, Z+ C- z, G; S - Error_Handler();6 `" [2 u# P' ?
- }) A& o* w @7 \# L
% @) w6 h$ g5 ^4 J5 D$ z, }- /* 修改为CBC模式 *// p/ |7 C# r. B" q! B0 v2 B
- hcryp.Init.Algorithm = CRYP_AES_CBC;# ^ A" G" w9 J! n
- /* 设置IV */
2 b! D$ b7 J& E0 o7 a ] - hcryp.Init.pInitVect = AES_CBC_IV;
6 n* ^; t! S- Z9 M Y0 m4 P - * @. Z: ^! Q6 W
- /* 再次初始化 */
9 y: e7 t+ w2 n* b- \% T9 \ - if (HAL_CRYP_Init(&hcryp) != HAL_OK)/ E3 ~: o2 `# @, d4 q" B
- {
. B, z1 ~, o/ b, ?$ a - printf("HAL_CRYP_Init error\r\n");
) M4 F8 X4 Q$ y4 K8 u' U% s2 a0 L - Error_Handler();$ v% Y8 F" s6 a0 y& V
- }' _* `8 g8 U5 e
- printf("\r\n");7 @2 u2 N& {6 C; s6 L" A& e4 E
- }
复制代码在main中调用切换函数,然后进行CBC加解密测试 - change_to_aes_cbc_mode();
3 e" }; s3 a6 V6 D3 ^) m - 8 V& G! R( M& e' i; S: D
- printf("AES CBC use user defined key 128Bit encrypt test\r\n");
n7 y& \* e" h4 H3 g' D - AES_encrypt_test(&AES_plainText[0]);& U3 b$ f+ |0 n, x& V) w2 ^
- printf("AES CBC use user defined key 128Bit dencrypt test\r\n");; B+ x, V4 P. @/ Z d
- AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码编译下载,结果如下 和在线工具对比一下,结果一致 三、总结 今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。
* ?7 U( o1 i$ U9 T9 Y& ~$ _本次工程代码:
STM32U0_AES_test.rar
(5.21 MB, 下载次数: 1)
|
好详细啊👍