STM32U08是带硬件AES加解密模块的,硬件加解密的最大优势就是快。 2 j- D4 o) [, R+ f2 p
一、cube配置 首先需要在cube中开启AES模块(工程就是上一篇中创建的模板工程) 4 F+ d: h: m, P2 V- p
参数这一块主要关注的是加密模式(Data encryption type)、秘钥长度(KeySize)、秘钥(Encryption/Decryption key),其他参数保持默认就可以 其中加密模式支持如下 秘钥长度支持128位、256位 秘钥的值可以在cube中配置,也可以这里保持默认值,回头在代码中重新配置(当然上述的这些参数都可以通过代码再次配置,这个待会实战部分会有介绍) 0 F5 Y! p: d" L' f% s0 O
最后点击右上角生成代码 # t+ ^% f' b8 o% T. U# V
二、实战 2.1 AES时钟初始化及函数介绍 先来看一下CUBE自动生成的代码 首先是变量 - CRYP_HandleTypeDef hcryp;
# l: n% i# `- v" A3 t( v! ` - uint32_t pKeyAES[4] = {0x00000000,0x00000000,0x00000000,0x00000000};
复制代码这边的pKeyAES就是秘钥,和之前cube中设置的一致(下面的测试中我会尝试更换秘钥) 然后就是AES模块的初始化函数
+ J$ ]9 n$ r+ i; w- O& {
8 {5 _8 N5 X e" Q8 E! I, e, a1 Z在初始化函数中可以看到,配置了各个参数,和cube中的一致。然后就是调用了初始化,秘钥、加密模式等就是在init时配置进去的,如果需要更换,那就要调用HAL_CRYP_DeInit(),修改配置参数,然后再调用HAL_CRYP_Init()(这个待会儿我也会尝试一下) , S7 p. i6 [7 D5 a; ^
在使用加密前,需要在main函数的最一开始就开启AES的时钟 - __HAL_RCC_AES_CLK_ENABLE();
复制代码 4 g. e, _7 @2 K; h; w0 R; M% E
加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密 具体函数如下 - HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,8 Y$ r0 s2 e8 X* k
- uint32_t Timeout);3 I, w4 D% N1 Q' E/ Q' Z1 ]
- HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,1 v5 S2 g1 V" u T
- uint32_t Timeout);
) M" F& F" k8 S3 b9 L - HAL_StatusTypeDef HAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
7 D) b5 j$ F% A) O - HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);) z9 }! J5 y" Q7 i
- HAL_StatusTypeDef HAL_CRYP_Encrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);% h4 R @9 I6 t& Q
- HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码 " B/ Q# R; v& E: F* C7 z# A* I
这里我再插一嘴,AES是需要加解密数据为16字节的倍数才可以运行,如果你的不是16字节的倍数,那么就需要做一下填充,加解密接口是不提供填充的,需要自己实现
2 t' L0 z c2 @0 R今天我们的测试的是最基础的阻塞加解密函数
& G1 Q% F8 `( _; U8 E3 i% N1 v3 O2.2 AES ECB 128bit加解密测试 我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试 先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上 - /* 计算得到的秘文 */- U4 r; z$ N# k7 K, K
- uint32_t Computed_Ciphertext[AES_DATA_SIZE];
: }' R# u! d! f8 B$ f - /* 计算得到的明文 */
+ M8 ]" ?) Q4 _2 w) T* T - uint32_t Computed_plainText[AES_DATA_SIZE];
) ]# ^& b% D$ V: p1 G% k0 Z - ( E. F8 l L4 K O" ~4 m! [+ z
- /* 用户自定义128bit秘钥 */9 Y; A: \6 F; \. B9 Q5 h3 Y- E. ?
- uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =1 G6 n$ h* |7 p3 E' ]3 s
- {3 |7 f$ \9 C3 h! H! ^
- 0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff) o* A4 E0 h( y l& q9 ^
- };
5 i6 w7 m3 e. h - /* 加密前的明文 */
* Z) h! K( g, P8 h - uint32_t AES_plainText[AES_DATA_SIZE] =! n& J5 P1 C9 _5 ^
- {
n2 F0 D8 j) y- S2 y; J8 _. J) } - 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f7 Q" h. R8 { O5 f6 E% z: p2 @
- };# [" s+ ^; Q! L, b- T. ?! P
9 H( l$ C) E, @- /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */( z6 \6 T) N4 h2 x
- uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
- u8 f3 f4 f0 V* t& ` - {( w2 I8 _2 y, M
- 0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE003( K% c3 Z {+ [
- };+ I$ l! @* v- e( D' l
- /* AES ECB使用cube默认128bit秘钥加密后的秘文 */: j" U; `$ P) o; P
- uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =
+ _$ y; f& W, V$ g1 R( u - {) R2 B C# V" A: U* o( X+ n: l
- 0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A2827 s% ?& X3 ?$ i/ i
- };
复制代码
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的
$ P1 I B+ q* a w) U8 @然后在加一下宏定义 - /* AES加解密阻塞式函数超时时间 */
& N0 n0 G/ v; e* p - #define AES_TIMEOUT_VALUE 0xFF //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说- n D$ ~. f3 f6 x
- /* AES加解密数据的长度(byte) */6 {, D. a3 s6 o. r0 b: n: o* S
- #define AES_DATA_SIZE_BYTE 165 L. p0 N+ S% l t% Z
- /* AES加解密数据的长度(uint32_t) */
+ Q2 b5 X% L( M; l - #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4)
3 j( n6 L+ I/ h - /* AES加解密秘钥的长度(bit) */
q, P1 d$ B, Q5 v - #define AES_KEY_SIZE_BIT 128
* {8 K5 ?* D) F+ B - /* AES加解密数据的长度(uint32_t) */
1 L' q" ^ e+ N6 [; ]: Q" Y - #define AES_KEY_SIZE (AES_KEY_SIZE_BIT / 4)
复制代码然后写一下AES ECB 128bit秘钥的加解密测试函数以及dump函数 - void dump_data(uint32_t *pData, uint8_t Size)
6 ]6 {6 v6 h% L& I - {
* v& r/ }7 B0 p3 o% z! u - for (uint8_t i = 0; i < Size; i++)2 O1 I$ f* s Q! r$ ^) O/ T
- {/ j' H$ @2 k0 V) v6 |% E
- printf("%02X ", ((*pData & 0xFF000000) >> 24));# D: r4 p( u2 Y1 C9 w; F
- printf("%02X ", ((*pData & 0x00FF0000) >> 16));4 m/ V' A) L# N+ c1 ?% r& r
- printf("%02X ", ((*pData & 0x0000FF00) >> 8));
; }1 K/ ~- D( T' \, z/ x# X# y - printf("%02X ", ((*pData & 0x000000FF)));
! I2 F: }* A& _/ n; x2 a5 g - pData++;
) F. p4 g' G0 Y0 H+ ` - }1 ^5 C( j! z X0 i
- printf("\r\n");
8 B& G$ P0 G' H! I4 l. Y( u - }
& H) l9 ? ^, H5 N - ' h! Q7 v9 x0 b7 i0 P. d1 i
- void AES_encrypt_test(uint32_t *plainText)
; x+ T, j9 D6 @ o$ a - {
2 z! u& `9 |0 O: r$ `3 O - printf("plainText = ");
! C/ Z4 w \! C2 R& O( b4 m - dump_data(plainText, AES_DATA_SIZE);
' [+ W# s8 z ~8 N8 w8 U% a
: ^- @1 A/ q) c/ @; A& O6 Q" B- if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK)
8 `* E6 R9 v" o u9 n6 \ - {
$ I# `# X2 o/ B+ A5 Q' @ - printf("AES encrypt success\r\n");2 {& w, L6 z5 ~( s1 n
- printf("Computed_Ciphertext = ");
8 X1 R6 F2 x& O1 s" m - dump_data(Computed_Ciphertext, AES_DATA_SIZE);
1 N' _ f; o; r) F7 { - }, M% l" ~! @7 N0 I0 O5 b- p$ S
- else
$ J/ G4 s# c0 f+ M s2 x8 k* I( | - {
% L( s; n; v, {8 S- q. g - printf("AES encrypt error\r\n");. R% i( O+ f9 ?- h/ p7 E4 e: O/ W& a6 g
- Error_Handler();
& k6 T# ]; E( i) I5 E& Q( o - }
3 ?3 D% U5 w1 j& K2 Z - printf("\r\n");! k' `8 C( S0 Y/ d0 }
- }
0 j# d6 F- e; h$ Z/ Q5 Y; R - % L: [3 d* {# \/ E& Q+ K
- void AES_dencrypt_test(uint32_t *cipherText)1 }$ V* N Q% {7 q2 _$ C0 X
- {: V8 e+ K+ E4 W3 v' S+ q4 L
- printf("cipherText = ");9 ]6 ^$ r8 D3 W9 p. n* p
- dump_data(cipherText, AES_DATA_SIZE);7 K7 q; {5 y; R0 z3 z P) \8 Q
% K7 Y$ j% W1 W- if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK)
8 O5 [" V0 v3 J% W3 I! T0 g - {
& P2 B2 C7 u+ S: l* H - printf("AES dencrypt success\r\n");+ g6 j2 A2 d* K; s& R: v
- printf("Computed_plainText = ");0 A4 M2 w/ C" m* K
- dump_data(Computed_plainText, AES_DATA_SIZE);& r7 T) W# I; E' U- O. J# |, O
- }4 T3 E/ M+ i& m! Y1 D
- else* V& ^7 A7 o$ q% H
- {
& K" m" s- c m6 r: M3 |* `0 r - printf("AES dencrypt error\r\n");6 I9 \& D$ n" ^- F& O" B: Y
- Error_Handler();
- R' _. U* r! `$ Q$ r- F - }
) X, Z1 L9 _6 M" i# s. ~ - printf("\r\n");
$ ?3 c3 e' i7 I0 f: ` - }
复制代码
4 P: ~+ ~4 X! v) l
& c/ |2 `& K% ]1 N$ Q. i* a2 V然后在main中调用 - printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");
# D+ g/ }) W* U - AES_encrypt_test(&AES_plainText[0]);- f9 m: B2 K& X% w' R5 S2 E9 W
- printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n");
7 J- t9 r4 G" J* f - AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码编译运行一下,结果如下 和在线工具对比一下,结果一致
! E l) A3 x" A2 X0 y8 [接下来尝试更换一下秘钥,再运行加解密 更换秘钥有2种方案,第一是直接对MX_AES_Init中的内容修改,但是因为这里是cube自动生成的,后续cube再生成一次就又变回去了。所以我选择方案二:去初始化,修改参数,再初始化。 - E- J Z" M1 C1 Q- O$ h
改变秘钥函数 - void change_key_to_user_defined_AesKey_128bit()
S" `6 T4 [2 p9 i3 B" q3 _# T - {, a1 |' Z! S* f' z( G- W' N
- printf("change AES KEY to user_defined_AesKey_128bit\r\n");7 |9 T4 C5 y1 c8 e1 Z5 _
- /* 先去初始化 */( s* ]3 _% Z* J8 w7 |7 ^
- if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)% ~, A2 x9 I6 f. p* d5 U
- {6 ^- Z" f h F" j
- printf("HAL_CRYP_DeInit error\r\n");
c) h. v* a! v5 R& @! Q - Error_Handler();
% X1 J8 `1 ]4 T) r; ]3 U - }# y# X& P. o. f, w
o- Y& ?4 i* w2 ^- /* 修改使用的秘钥 */
1 a9 G1 ~8 ?4 P8 U - hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;
n/ `& A; h6 W4 V* G1 g" m
% H* Z0 \' x- a$ ~7 J- /* 再次初始化 *// X* k, [4 C( B/ P
- if (HAL_CRYP_Init(&hcryp) != HAL_OK)
' h+ N/ `- `6 A; g6 p - {, D" M1 ]5 z- N
- printf("HAL_CRYP_Init error\r\n");% y5 M8 M# r! G# X/ F( W& Y8 M
- Error_Handler();
: e- Y" f* ?% ~& v; j% _+ a* d - }
- P2 y: E( R: b. e - printf("\r\n");
/ w2 w9 |, h& |+ T+ l' k) z6 ? - }
复制代码
. Z$ ? `4 f% a- L
2 q, K3 s8 F# i7 E( ]8 \然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功 - change_key_to_user_defined_AesKey_128bit();
0 b; _8 w+ z5 r - , K$ X( K U& x# e I3 H4 R% i+ [
- printf("AES ECB use user defined key 128Bit encrypt test\r\n");
0 H+ }6 n$ S `" z% p" h - AES_encrypt_test(&AES_plainText[0]);
+ C* d2 A, q, z0 _6 K. Z - printf("AES ECB use user defined key 128Bit dencrypt test\r\n");
2 r$ v- D( W! y2 \1 g# s - AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码 编译下载运行效果如下 和在线工具对比一下,结果一致 9 N: ]' N6 C% d; S: x9 K
2.2 AES CBC 128bit加解密测试 然后我们把AES模式切换至CBC模式,来进行测试 CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下 然后准备一下CBC加密后的结果的数组,回头给解密时使用 - /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */' m& @; M' f9 u G
- uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =: ^" m9 K- K: a* [
- {4 S% g p- t! G4 X& @& w% |# e
- 0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E783
) L; ]6 f# c* |$ n# n1 r+ ]! s - };
复制代码写一下切换至CBC模式的函数 - void change_to_aes_cbc_mode()7 d4 i" C9 Q/ K& Q! Z
- {
* u u& m( A% H, {7 Z. @ - printf("change to AES CBC mode\r\n"); {& S" |0 [! v) O; K% K
- /* 先去初始化 */
& H$ c4 m) g9 @' Z, A: @/ O - if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)) q; P" B! _# a1 w3 t2 O
- {1 Y9 A- @# }* t: p' U# y7 D& d
- printf("HAL_CRYP_DeInit error\r\n");
3 I- r. O3 E% b! J- l* }; W - Error_Handler();. l7 U4 w3 A" X5 x
- }. X8 J S9 N/ e- i" \
- 4 w ^- o: \2 L* g0 B2 q% \
- /* 修改为CBC模式 */, K# E7 _( p" z% F) g/ q! c
- hcryp.Init.Algorithm = CRYP_AES_CBC;
0 u; G# i( `4 g; j5 H - /* 设置IV */( S3 m* h# C! r8 B) E
- hcryp.Init.pInitVect = AES_CBC_IV;
^$ l g9 u' `
) E( N( m+ |& g: a# h5 d% f: A/ N- /* 再次初始化 */
& q' f9 D# u2 k - if (HAL_CRYP_Init(&hcryp) != HAL_OK)
4 X4 l# ~ k* ~) W: _$ Q5 R - {
4 o: [) E5 W" B( }5 b - printf("HAL_CRYP_Init error\r\n");0 L6 z; J! a" `$ j5 V" K
- Error_Handler();$ @, i: `4 E5 I8 U P# E$ H9 P @
- }
f) o$ s1 o# n$ P ^ - printf("\r\n");9 `, Q9 P$ O. @* X1 Y' \
- }
复制代码在main中调用切换函数,然后进行CBC加解密测试 - change_to_aes_cbc_mode();
/ T0 _& b1 m9 N, n- c1 H" u. y - * W; y& ^) ?9 ]/ q
- printf("AES CBC use user defined key 128Bit encrypt test\r\n");
/ v& p8 v- O' B2 {) w9 F0 o0 @ - AES_encrypt_test(&AES_plainText[0]);5 H# Q4 g: d! f6 J6 L( b3 ~
- printf("AES CBC use user defined key 128Bit dencrypt test\r\n");
8 m6 u L1 m+ U1 H - AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码编译下载,结果如下 和在线工具对比一下,结果一致 三、总结 今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。 8 D. k# B; c+ R* L
本次工程代码:
STM32U0_AES_test.rar
(5.21 MB, 下载次数: 3)
|
好详细啊👍