STM32U08是带硬件AES加解密模块的,硬件加解密的最大优势就是快。
; f. {5 _- P5 }一、cube配置 首先需要在cube中开启AES模块(工程就是上一篇中创建的模板工程) ) s/ I5 V0 ]6 D3 e( N5 L) h6 V& U
参数这一块主要关注的是加密模式(Data encryption type)、秘钥长度(KeySize)、秘钥(Encryption/Decryption key),其他参数保持默认就可以 其中加密模式支持如下 秘钥长度支持128位、256位 秘钥的值可以在cube中配置,也可以这里保持默认值,回头在代码中重新配置(当然上述的这些参数都可以通过代码再次配置,这个待会实战部分会有介绍)
! `2 k* U% f9 U ^3 h+ d最后点击右上角生成代码 . R, N* a' ~4 ~
二、实战 2.1 AES时钟初始化及函数介绍 先来看一下CUBE自动生成的代码 首先是变量 - CRYP_HandleTypeDef hcryp;7 Q2 D( z$ t x( i$ P/ h
- uint32_t pKeyAES[4] = {0x00000000,0x00000000,0x00000000,0x00000000};
复制代码这边的pKeyAES就是秘钥,和之前cube中设置的一致(下面的测试中我会尝试更换秘钥) 然后就是AES模块的初始化函数 ; R: z( ^" H+ K) o
' s5 @- I+ C. Y" V, d- p. I在初始化函数中可以看到,配置了各个参数,和cube中的一致。然后就是调用了初始化,秘钥、加密模式等就是在init时配置进去的,如果需要更换,那就要调用HAL_CRYP_DeInit(),修改配置参数,然后再调用HAL_CRYP_Init()(这个待会儿我也会尝试一下)
2 y* g7 S, u) A: J8 f: F0 }4 s在使用加密前,需要在main函数的最一开始就开启AES的时钟 - __HAL_RCC_AES_CLK_ENABLE();
复制代码 % g2 r# m( }. W# ]/ y
加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密 具体函数如下 - HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
# }% t9 c6 ~4 m/ `. S - uint32_t Timeout);
|2 d; Y. Z$ x5 e* s - HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
T/ z, u% `2 F$ |* | - uint32_t Timeout);
7 ^( B; c* s9 }5 x' w - HAL_StatusTypeDef HAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);* C0 N2 M; `8 r( G; K& L+ h9 R
- HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);. B: U3 ]# v3 a- l# N0 E2 W
- HAL_StatusTypeDef HAL_CRYP_Encrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
7 X% m: N2 [# O5 p7 i - HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码
3 V% Q# f2 }& N: `这里我再插一嘴,AES是需要加解密数据为16字节的倍数才可以运行,如果你的不是16字节的倍数,那么就需要做一下填充,加解密接口是不提供填充的,需要自己实现 ! b) w/ E8 K2 A' Y8 H
今天我们的测试的是最基础的阻塞加解密函数
; S0 X) W0 Y6 O6 A+ T5 \& J2.2 AES ECB 128bit加解密测试 我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试 先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上 - /* 计算得到的秘文 */
, H2 x6 ?% i0 u - uint32_t Computed_Ciphertext[AES_DATA_SIZE];
0 S2 e( D- P" D" [& B$ ] - /* 计算得到的明文 */
/ \& D/ W' q% j1 n6 G7 D# f& C8 A4 z - uint32_t Computed_plainText[AES_DATA_SIZE];3 J0 a+ c. }( i4 s( U5 s# W! a7 F
- ) n" d& j* ?2 M; x7 M9 B, s5 P
- /* 用户自定义128bit秘钥 */
0 t; B6 q, i1 ?- D% `; C9 N - uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =8 a$ r( H* E) v" U% D& T; U
- {
, s& \2 v% A# o - 0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff
2 P& H' i: v! ^% J - };
" [' W: V; G X9 a - /* 加密前的明文 */+ ^+ k+ Q6 S) q, k% N# ^/ Y! [
- uint32_t AES_plainText[AES_DATA_SIZE] = n5 t# d% g8 C$ ?+ R; E
- {6 o9 q% k/ \5 o4 Q2 i% S
- 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f
/ I8 o7 R. x1 G6 v! H" x1 c0 B - };# ^2 x. ^% t U$ r6 {
# ^+ Y: j# I* ]8 V; P# A- /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */
0 t3 g! i" G2 l' J! e% H - uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
4 O/ [: @! @4 W" _ h- y - {) d4 x$ [/ M3 W5 Z8 [
- 0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE003$ I1 z( w3 T# M* @
- };
! H3 G! w. h3 u& ?9 N+ r- S - /* AES ECB使用cube默认128bit秘钥加密后的秘文 */
) i- O% j: I0 }/ n8 h - uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =, | d9 Y# G7 L6 Z
- {$ N7 h3 j2 g8 |( k: H: r
- 0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A282" P. p# Z, h# ~3 h! L
- };
复制代码
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的
* ^6 \: L- `+ L9 ^1 ?# c9 z1 K9 g4 e然后在加一下宏定义 - /* AES加解密阻塞式函数超时时间 */
2 n$ V8 R7 q0 T% B/ x - #define AES_TIMEOUT_VALUE 0xFF //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说
0 O6 j( I# _0 K - /* AES加解密数据的长度(byte) */$ ~! `% k9 D, x$ X. N
- #define AES_DATA_SIZE_BYTE 16% s* f8 D5 G' [$ ~+ S$ e4 J
- /* AES加解密数据的长度(uint32_t) */ s, n6 ]/ d7 B$ w
- #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4)
" G$ [9 d2 r8 z - /* AES加解密秘钥的长度(bit) *// G R. y( r* z4 w
- #define AES_KEY_SIZE_BIT 1282 ]3 u) M# y( k" g+ R9 G
- /* AES加解密数据的长度(uint32_t) */% H6 s7 k" x" {; Q: @1 ?/ `
- #define AES_KEY_SIZE (AES_KEY_SIZE_BIT / 4)
复制代码然后写一下AES ECB 128bit秘钥的加解密测试函数以及dump函数 - void dump_data(uint32_t *pData, uint8_t Size)* w7 p2 e7 P+ n
- {, z* U6 t# P5 `& `8 x, Z0 t/ ^) K
- for (uint8_t i = 0; i < Size; i++)* n; F# E2 D4 \3 l% i$ t9 F
- {, @+ B0 F8 h: h. m, D: ^
- printf("%02X ", ((*pData & 0xFF000000) >> 24));
/ b1 i+ _. @# B9 t - printf("%02X ", ((*pData & 0x00FF0000) >> 16));/ M0 A& Z. v5 C( y- B* q2 K6 I
- printf("%02X ", ((*pData & 0x0000FF00) >> 8));
6 L2 N1 c2 j! h M2 k1 s - printf("%02X ", ((*pData & 0x000000FF)));
7 C% g* F8 m7 G7 l+ M- v {/ o0 P - pData++;
( O! g4 k8 q f- S, { [& a - }
& n6 ?/ @$ I, t0 `' f - printf("\r\n");/ f: l1 e4 @3 f2 H
- }! W9 W8 f; V) u* S) ~5 j! h
; D* H7 o5 T$ N; F. d- void AES_encrypt_test(uint32_t *plainText)
$ H5 }: @$ F3 q0 ] - {
8 q, U* @ e$ X" Q, _0 H5 U - printf("plainText = ");
/ I( g) L3 W$ ^# @# K7 O - dump_data(plainText, AES_DATA_SIZE);+ ]4 l8 f' ]/ m+ A
- ' T( n9 d, @* c, F" {1 }6 c
- if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK)# D0 k( ?0 j. B: Q. k
- {
7 v% o: D% @. {- E, R0 M4 S! K* ] - printf("AES encrypt success\r\n");+ A5 g$ }" P% ?- P! O, j" l3 R
- printf("Computed_Ciphertext = ");: L1 W6 f9 \ T% l) z. z
- dump_data(Computed_Ciphertext, AES_DATA_SIZE);! I" A6 `0 d& N& \
- }
0 k2 H7 [' a6 D7 x - else: @. [! t( q0 G4 N% s. ^
- {* V; v4 c0 i& r3 z
- printf("AES encrypt error\r\n");
$ v6 c2 `" J6 P' _+ c - Error_Handler();
& i6 y, T6 T5 p6 d5 q S - }
2 _8 e* x5 |9 ^, T7 i3 o - printf("\r\n");
* L" l0 b5 R; ?* A4 j" y - }
8 E7 R, V9 n/ C* [% T3 f' s" e+ [7 B
5 z ^' l2 {. X: _8 ]0 b- void AES_dencrypt_test(uint32_t *cipherText)
* a6 ^5 r8 N% \6 @' c; S - {4 S5 ]4 o: S6 D2 p5 k
- printf("cipherText = ");
) y" w, ~+ s) t9 `5 n, O4 d& G - dump_data(cipherText, AES_DATA_SIZE);
- J2 t! [7 S$ [& M3 A4 Z1 P
$ v1 C1 X0 b2 v1 ^+ T9 E- if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK), y3 ~8 _ P% K: |
- {/ q; D; F) A7 G5 t5 X2 M
- printf("AES dencrypt success\r\n");) r# m+ j: P' i) Y+ W3 x* z
- printf("Computed_plainText = ");6 u3 X0 I9 Q1 v
- dump_data(Computed_plainText, AES_DATA_SIZE);- O8 |0 V! Y- E" `
- }' G8 F6 B9 f" B6 f7 O4 v" i; ~
- else0 `. j, Y& G' b% _# u+ x
- {
" U4 p q: l" b! j1 g5 N - printf("AES dencrypt error\r\n");
9 n2 B# a' r' r/ H0 n& y - Error_Handler();9 u3 Y8 m) X9 G2 ?0 N( q e
- }, c! d* [) Q% M. S& |# U8 c+ `' {
- printf("\r\n");
1 g1 ?. @5 X5 E* p+ [* G - }
复制代码
6 C' z, c( b' T4 A1 S, F
1 y3 o0 o+ B0 M1 i. ?: {, E( o然后在main中调用 - printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");/ A1 g9 y8 ?. o) s+ V6 T
- AES_encrypt_test(&AES_plainText[0]);$ F. R7 ^/ r+ R2 O0 P9 G9 M
- printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n");+ f- D1 U1 T+ D
- AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码编译运行一下,结果如下 和在线工具对比一下,结果一致 ! e o9 }% Z8 R! Y1 U( F6 t' v
接下来尝试更换一下秘钥,再运行加解密 更换秘钥有2种方案,第一是直接对MX_AES_Init中的内容修改,但是因为这里是cube自动生成的,后续cube再生成一次就又变回去了。所以我选择方案二:去初始化,修改参数,再初始化。 9 c) x7 \- M3 L
改变秘钥函数 - void change_key_to_user_defined_AesKey_128bit()6 W1 G$ _4 R* N6 ^4 _
- {* e# t6 [/ U5 b. N1 W
- printf("change AES KEY to user_defined_AesKey_128bit\r\n");: s9 V* G! w* I
- /* 先去初始化 */8 ^% q% l$ J1 n5 I4 a
- if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)
% {" v6 J5 z- r - {1 Q% n2 M- x. `# e1 a* B
- printf("HAL_CRYP_DeInit error\r\n");! F9 }4 x% `, T3 Y
- Error_Handler();6 T4 ]) P" o H2 V2 I3 N
- }' o2 u( @4 _, X
- 8 E) a! p" d+ i/ G; G, @
- /* 修改使用的秘钥 */+ @& K6 [1 k5 O2 _ g
- hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;2 b3 l. Z Y/ f/ x' l7 u' R6 a
- " L7 q$ f" u3 O# d( K7 f- N
- /* 再次初始化 */
0 d- i1 M ], F2 N& `) f - if (HAL_CRYP_Init(&hcryp) != HAL_OK), P8 f. Y- U/ ?6 L/ C* _7 o7 J
- {
5 r3 f. u% E7 ^. f k: J - printf("HAL_CRYP_Init error\r\n"); \# ^0 p- Y' J* h- B2 N& p3 c
- Error_Handler();; ^$ m! o2 y$ j" E% O* B
- } G. X+ o2 r: r
- printf("\r\n");- D9 \7 W: S* G) [1 Z! U& ]' I
- }
复制代码
1 N% v: `4 n6 M0 y9 D, C; @. t% Q4 n; t: G$ V
然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功 - change_key_to_user_defined_AesKey_128bit();/ X3 S, h7 A, u* x' p* i5 s
- ! |9 K+ K8 f* W0 F! S
- printf("AES ECB use user defined key 128Bit encrypt test\r\n");9 m$ k A/ y9 w$ B; A% A( |
- AES_encrypt_test(&AES_plainText[0]);
; g3 ?. M' v: X, E3 n) R - printf("AES ECB use user defined key 128Bit dencrypt test\r\n");: h7 G& Q+ G2 W
- AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码 编译下载运行效果如下 和在线工具对比一下,结果一致 ; u) ?6 {5 a+ A- L5 X. C% M3 w, W
2.2 AES CBC 128bit加解密测试 然后我们把AES模式切换至CBC模式,来进行测试 CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下 然后准备一下CBC加密后的结果的数组,回头给解密时使用 - /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */
. D! a+ ]+ P) l3 e: O - uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =
- y( N- R# @$ q2 B, N - {
+ e, V( @' C T! u' {. T - 0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E783/ H6 b3 w1 ?) f$ X7 f; @7 T$ o/ |
- };
复制代码写一下切换至CBC模式的函数 - void change_to_aes_cbc_mode()8 S4 F$ m+ q! B# ~% J2 O. J) n
- {
5 @% e( i+ |6 J - printf("change to AES CBC mode\r\n");0 b1 }) ^! {% Z ^. I9 s" x+ D* @
- /* 先去初始化 */
5 [6 e; n+ p, s& @/ w6 e - if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)
4 ]# _) l/ x% X3 B/ Z - { \5 G8 a) h, ]0 N, J X
- printf("HAL_CRYP_DeInit error\r\n"); z8 a/ J9 C5 A8 { ` B
- Error_Handler();3 \( L/ |8 K- r% S; V
- }% h! |* Y. M2 ]2 F) c4 g
. H6 q- {0 @. X& H6 p4 R, Z. I- /* 修改为CBC模式 */
" V+ |/ M# u3 c: J0 O; L0 C, h' A( ]9 O - hcryp.Init.Algorithm = CRYP_AES_CBC;
3 ]4 o% Y" G: w" c. \ - /* 设置IV */2 t& f5 N! k" ~' j5 p
- hcryp.Init.pInitVect = AES_CBC_IV;
8 `# ?0 d/ h0 {8 c8 E - 6 s, |! A: \0 s+ B) P
- /* 再次初始化 */0 q! h( g% ]' x) [
- if (HAL_CRYP_Init(&hcryp) != HAL_OK)
; s3 c$ X, p3 G4 n0 g3 E - {( a, ^6 \9 g; s8 J: ^6 i. r* E- k
- printf("HAL_CRYP_Init error\r\n");: c" p& ~! Z( L& }, D2 g# I
- Error_Handler(); E2 B/ | T( y m1 o
- }
0 Y5 G# R! h# D - printf("\r\n"); J% j' j6 X) r) C
- }
复制代码在main中调用切换函数,然后进行CBC加解密测试 - change_to_aes_cbc_mode();
/ L6 L( g0 g G5 B& k3 Y - & z: {, l) ~, f7 `, H1 L
- printf("AES CBC use user defined key 128Bit encrypt test\r\n");- N. I7 N& N8 K
- AES_encrypt_test(&AES_plainText[0]);( L3 y; a+ M6 i- E3 N
- printf("AES CBC use user defined key 128Bit dencrypt test\r\n");' x. j# I2 s( M! ~7 g. U
- AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码编译下载,结果如下 和在线工具对比一下,结果一致 三、总结 今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。
! B0 r2 w) B. @2 D7 s7 y3 `' q: e本次工程代码:
STM32U0_AES_test.rar
(5.21 MB, 下载次数: 1)
|