STM32U08是带硬件AES加解密模块的,硬件加解密的最大优势就是快。
3 D$ ~3 o! q( ~* K8 J$ p一、cube配置 首先需要在cube中开启AES模块(工程就是上一篇中创建的模板工程) + L a4 `/ Z, P- H0 R
参数这一块主要关注的是加密模式(Data encryption type)、秘钥长度(KeySize)、秘钥(Encryption/Decryption key),其他参数保持默认就可以 其中加密模式支持如下 秘钥长度支持128位、256位 秘钥的值可以在cube中配置,也可以这里保持默认值,回头在代码中重新配置(当然上述的这些参数都可以通过代码再次配置,这个待会实战部分会有介绍)
8 J0 E l: |/ F) f) Z1 Y! s最后点击右上角生成代码
) g9 }( P% @% b! E5 u* ?二、实战 2.1 AES时钟初始化及函数介绍 先来看一下CUBE自动生成的代码 首先是变量 - CRYP_HandleTypeDef hcryp;: `! H# M4 |+ \7 J
- uint32_t pKeyAES[4] = {0x00000000,0x00000000,0x00000000,0x00000000};
复制代码这边的pKeyAES就是秘钥,和之前cube中设置的一致(下面的测试中我会尝试更换秘钥) 然后就是AES模块的初始化函数 . L% x9 }! h/ q, m) x4 P
" A0 ?7 y) t; P* ~' A- N在初始化函数中可以看到,配置了各个参数,和cube中的一致。然后就是调用了初始化,秘钥、加密模式等就是在init时配置进去的,如果需要更换,那就要调用HAL_CRYP_DeInit(),修改配置参数,然后再调用HAL_CRYP_Init()(这个待会儿我也会尝试一下)
2 e! H: F1 h6 R6 b* R r+ _( q在使用加密前,需要在main函数的最一开始就开启AES的时钟 - __HAL_RCC_AES_CLK_ENABLE();
复制代码 % A, a/ q$ I6 [0 |4 @5 L
加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密 具体函数如下 - HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,1 Z* i' v2 b0 ]' l7 k
- uint32_t Timeout);% k9 R% R: \: v" P; z! a7 a
- HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
+ M8 P- V$ \+ ~8 l3 s - uint32_t Timeout);
; l+ h6 a. ?! J" K* @! s0 ? - HAL_StatusTypeDef HAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
0 _7 K: i$ r/ \% x - HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
2 W) a$ v, A' ?! J - HAL_StatusTypeDef HAL_CRYP_Encrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);3 U3 H4 e9 X2 V, ]) I
- HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码
1 t1 F4 |3 k: ?这里我再插一嘴,AES是需要加解密数据为16字节的倍数才可以运行,如果你的不是16字节的倍数,那么就需要做一下填充,加解密接口是不提供填充的,需要自己实现
( R. t' [' \! M9 m今天我们的测试的是最基础的阻塞加解密函数 7 r; X* f) Q/ @& z) r
2.2 AES ECB 128bit加解密测试 我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试 先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上 - /* 计算得到的秘文 */: F8 t1 u! K9 l9 V' M7 {! Z
- uint32_t Computed_Ciphertext[AES_DATA_SIZE];, r3 l, g: q: Y
- /* 计算得到的明文 */) `: J3 g$ F+ l! v7 u. N. I, e
- uint32_t Computed_plainText[AES_DATA_SIZE];
' K- p7 K4 {1 K/ a$ X8 f - / T3 ]9 L) n7 M3 E
- /* 用户自定义128bit秘钥 */
% s3 E0 |7 c+ c) {3 ` - uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =4 e# T6 \" s" g! H8 D( n
- {' Y6 R) J+ c$ [- O
- 0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff" s4 z9 x& P* `# g# |, r/ {
- };, x$ J* p1 c3 F
- /* 加密前的明文 */) H$ Q2 i- i: {5 } f0 J
- uint32_t AES_plainText[AES_DATA_SIZE] =- Q- Y+ _9 s% ?- ~$ K
- {
: f& ~# K" R1 i5 E - 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f
# @0 l& o$ ?- H+ \ - };
: B1 y. B; D3 |4 \2 l
2 R& }3 t1 V* R& x( }! R- /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */
# P; m; ^; b2 M- `% @- N; V8 y. \ - uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =" q" a7 l. a- F! T* O+ T5 o# {
- {9 A9 R& F7 V: F9 y+ P
- 0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE003
( p5 a# a6 ]# D. Q' Z9 I - };5 H" D& c0 R' }- S; y# Q& L# A' q
- /* AES ECB使用cube默认128bit秘钥加密后的秘文 */
3 o3 P7 f' Z8 K- s Z - uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =
# n0 ]; y/ s0 w* ^2 l# U6 _" f% l - {
4 u/ N! B2 L7 L/ W - 0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A282
% l: b* S6 E7 k- t - };
复制代码
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的 # q% H8 v+ u# g* `1 c3 j
然后在加一下宏定义 - /* AES加解密阻塞式函数超时时间 */8 h, P# {: ~* [/ e! x) P* q
- #define AES_TIMEOUT_VALUE 0xFF //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说6 g# u! R. Q/ [' y
- /* AES加解密数据的长度(byte) */
% k8 ]8 K: j7 b - #define AES_DATA_SIZE_BYTE 16* z4 z* P2 u8 J/ Q
- /* AES加解密数据的长度(uint32_t) */
0 q# t& N9 p4 a0 A% K* M: _ - #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4)
. ?$ T$ A( t. P: m6 q( D7 U/ ]/ I8 S - /* AES加解密秘钥的长度(bit) */- `! u: W) c# H) g& Y) x
- #define AES_KEY_SIZE_BIT 1289 O1 z; r& w+ |6 E+ B) R, s
- /* AES加解密数据的长度(uint32_t) */
# A9 w" \! A. A - #define AES_KEY_SIZE (AES_KEY_SIZE_BIT / 4)
复制代码然后写一下AES ECB 128bit秘钥的加解密测试函数以及dump函数 - void dump_data(uint32_t *pData, uint8_t Size)
* Q$ F5 s) q1 A& H$ p8 H - {0 h9 l6 z$ X$ y6 M" A
- for (uint8_t i = 0; i < Size; i++)
+ [4 V+ W" q: n$ R - {7 O1 d% i5 }( M- |
- printf("%02X ", ((*pData & 0xFF000000) >> 24));+ o3 H* M( `3 B3 a! I% Y6 o
- printf("%02X ", ((*pData & 0x00FF0000) >> 16));6 Z6 [2 t; Y" R5 p$ o9 b
- printf("%02X ", ((*pData & 0x0000FF00) >> 8));
( N: c; R7 X, g# {* m - printf("%02X ", ((*pData & 0x000000FF)));
, ~! m# l2 J6 |2 q3 E! O( L - pData++;
( h6 k. |5 |! w6 l# Q - }% f! [8 |) Q9 s' ]; E/ z
- printf("\r\n");* {" t# Q. }1 k" W+ Z
- }. t- }3 X6 m- N% ~
- ' p! Y" z$ ~6 q3 }0 M& S* F0 F
- void AES_encrypt_test(uint32_t *plainText)
4 r. ^% c; p$ W8 c, T0 u) x+ @; g - {
( C; X& T; A) J' Z - printf("plainText = ");
9 O% x. N' @- v+ x3 T# V6 {) J* j - dump_data(plainText, AES_DATA_SIZE);
1 w# `1 @0 X7 T3 I' a
% P1 s& o( l X# p$ k- u- if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK)
* W" l# v2 S8 Q. }. M0 H$ |! R5 i( ^ - {
6 {% C3 @ ^ F/ B - printf("AES encrypt success\r\n");
* w; F- s" D9 t1 @ - printf("Computed_Ciphertext = ");# g$ V/ B# y. l! x; o# m( i3 Z+ X
- dump_data(Computed_Ciphertext, AES_DATA_SIZE);
" Z. i9 P; e& ~ m4 p) P - }
S9 |( `! W1 T2 J* w - else0 i7 j6 e! Y8 m
- {9 c; x l8 x* n1 J3 W8 }8 w( m
- printf("AES encrypt error\r\n");: |/ y, ~. P! ?7 u6 P" ~# @- r' V# h
- Error_Handler();! n* n! X0 R3 U$ c- o
- }
8 ?: _/ S9 ~4 W' H9 L0 f& k - printf("\r\n");4 \6 I" _ i3 U
- }
2 W! N' E6 b n+ ]. _ - 1 U2 V% X4 |# l7 @3 m
- void AES_dencrypt_test(uint32_t *cipherText)
; X3 q9 T1 Z/ y: R - {
3 U( z* n4 D9 G4 @# O, f0 \ - printf("cipherText = ");
& J3 d- p4 E" w7 H, @8 |5 q0 _# { - dump_data(cipherText, AES_DATA_SIZE);
" J5 `) j( |4 Z8 i" y4 n
( n% R: W& L3 X4 Q, @, k3 |7 @- if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK)/ \. l9 z, a$ b" e. _& f% P2 @0 o
- {( b- }' L0 w1 ~) o5 I3 ]$ ~
- printf("AES dencrypt success\r\n");
; T* i1 k$ B& l - printf("Computed_plainText = ");* ~% X3 S5 d7 g# P) _' E
- dump_data(Computed_plainText, AES_DATA_SIZE);
# l* V1 O( E T4 u# E2 y( L - }! R5 _# C! ?# C9 m/ C
- else
( @# _( Y0 ]0 V7 X; j - {
& ^% \' p2 y! S7 ~& H - printf("AES dencrypt error\r\n");
) x. }% ]/ _5 x. Q/ o2 [$ r: v - Error_Handler();
1 R; H( a& L4 y. }/ g - }
0 Z0 j" C/ \: L! O+ d - printf("\r\n");- z* A2 P& G/ K1 _
- }
复制代码
+ H k6 Q, w1 b! v6 P d# h! Y
) W$ s1 ^: X# b/ P
然后在main中调用 - printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");# T d/ L- O& o7 r4 G5 u
- AES_encrypt_test(&AES_plainText[0]);
0 z) U; U; h- l. e3 Z - printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n");( ]/ S9 Q8 B" ], z0 K/ a
- AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码编译运行一下,结果如下 和在线工具对比一下,结果一致
1 P. t; R4 M4 H! i; z8 f7 a接下来尝试更换一下秘钥,再运行加解密 更换秘钥有2种方案,第一是直接对MX_AES_Init中的内容修改,但是因为这里是cube自动生成的,后续cube再生成一次就又变回去了。所以我选择方案二:去初始化,修改参数,再初始化。 ) V% P0 E T+ f9 z
改变秘钥函数 - void change_key_to_user_defined_AesKey_128bit()& i( j2 Z& y3 K
- {
- L7 \! `( h, ?# _ - printf("change AES KEY to user_defined_AesKey_128bit\r\n");
& T! s1 _( s, G: ?5 ], J- Q8 M - /* 先去初始化 */+ K. {, G* K0 w/ ? ?: f
- if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)0 u( t( I* I: k8 S; N( \. ~
- {
3 Z7 S: ]) d% n' A J" P, S, s8 S |" j - printf("HAL_CRYP_DeInit error\r\n");& W, w% K7 t( W6 Y9 [1 c
- Error_Handler();
9 W; w/ W- _6 D; D- Y0 E - }
+ Z9 O: Z7 X6 Z0 s0 k& ^ - % J3 b) z0 N2 K6 Y7 C% U5 {
- /* 修改使用的秘钥 */
' x$ b: N0 @) R) u6 n. X! F- ` - hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;
5 m$ R; d. b. k5 U - / g; h/ [- y! Y) }* `, P
- /* 再次初始化 */
6 }" A4 |1 _7 S9 |2 w - if (HAL_CRYP_Init(&hcryp) != HAL_OK); z( S6 H1 O% s. S5 P6 h
- {
- Q# c# f- A5 [( N - printf("HAL_CRYP_Init error\r\n");
+ p4 I! x" E2 {& U8 T; g1 j - Error_Handler();' F$ }1 _% |7 Q; i+ n& x2 i) w+ F1 V* c$ A
- } a. }/ q* J6 F/ ^2 F. E) B" }
- printf("\r\n");
3 Z3 }3 ?5 p0 ?' A3 l% L - }
复制代码 0 K- X1 ?' |! r, a6 h6 A
# Z+ d% M+ M' T1 s0 ?
然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功 - change_key_to_user_defined_AesKey_128bit();
5 }4 _4 f8 A* B2 l, k" S - . v5 q, {1 ]/ H% V
- printf("AES ECB use user defined key 128Bit encrypt test\r\n");
/ S* P. O) _# S% d - AES_encrypt_test(&AES_plainText[0]);; E2 _! Q- y( J7 A( B. F5 F/ L; r
- printf("AES ECB use user defined key 128Bit dencrypt test\r\n");
0 `) Q2 u8 p! O3 k - AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码 编译下载运行效果如下 和在线工具对比一下,结果一致 " M! H# V- @" [" K$ n( z
2.2 AES CBC 128bit加解密测试 然后我们把AES模式切换至CBC模式,来进行测试 CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下 然后准备一下CBC加密后的结果的数组,回头给解密时使用 - /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */
$ L0 e- E& a% t# A, C1 j) g - uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =2 B* `. E8 |: y& t4 N
- {
6 a, C" p5 m2 V% A$ [+ h+ [! h - 0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E783& n5 ~, o: [* H" [
- };
复制代码写一下切换至CBC模式的函数 - void change_to_aes_cbc_mode()5 r. k2 v4 q/ n$ [1 X
- {1 n4 ?% e" S- }9 @/ a7 H. ^
- printf("change to AES CBC mode\r\n");
. M; `& a! w; o* ^& x9 e) y - /* 先去初始化 */; l/ D- ~' I$ T( I- e+ z% O
- if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)
7 M( g: y' f5 L6 E- S7 z - {2 `! j u0 T+ j. [9 A3 r. P
- printf("HAL_CRYP_DeInit error\r\n");
' x! ^; ]1 K: P* D, A' D - Error_Handler();$ A2 `9 m$ @# f7 k) R- W/ g4 K
- }9 r# D- x1 t1 ^# v
0 g4 ]* E. w2 p' O- i3 D" D+ X- /* 修改为CBC模式 */: A6 K, u$ |5 n/ h& T
- hcryp.Init.Algorithm = CRYP_AES_CBC;3 ]% Y3 r: ~, t8 j$ Y" O$ c* v
- /* 设置IV */
8 |" _$ E. G- {0 x0 w7 b6 ^" ? - hcryp.Init.pInitVect = AES_CBC_IV;
+ J4 t* q4 N+ v K/ | - ! e9 x* a! a$ u2 p$ Z
- /* 再次初始化 */
1 r! ^+ k/ w6 h - if (HAL_CRYP_Init(&hcryp) != HAL_OK)
1 t, U' C+ D% z - {2 Z# J5 `2 {4 _* E4 G6 E
- printf("HAL_CRYP_Init error\r\n");
: Z3 a }5 q$ e3 H0 z - Error_Handler();
$ N+ S0 T" {% X - }8 M3 j; ~& s7 C y) {
- printf("\r\n");) P& n% S- v/ R6 o! n- r3 l
- }
复制代码在main中调用切换函数,然后进行CBC加解密测试 - change_to_aes_cbc_mode();
/ p3 q$ V$ N; c2 c) `3 v( e h
g5 ?+ D2 W0 s7 X' z0 A8 w- printf("AES CBC use user defined key 128Bit encrypt test\r\n");
: T1 j, N- N3 Z3 m# X+ \0 h - AES_encrypt_test(&AES_plainText[0]);# Z2 Y; X7 w6 {8 s; e
- printf("AES CBC use user defined key 128Bit dencrypt test\r\n");
4 {; g4 A7 I L% `9 T1 C# C5 J - AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码编译下载,结果如下 和在线工具对比一下,结果一致 三、总结 今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。 " V" j6 |+ K. X1 U1 p7 M0 |
本次工程代码:
STM32U0_AES_test.rar
(5.21 MB, 下载次数: 1)
|
好详细啊👍