STM32U08是带硬件AES加解密模块的,硬件加解密的最大优势就是快。 8 M, N4 ~( @, w. o
一、cube配置 首先需要在cube中开启AES模块(工程就是上一篇中创建的模板工程)
( `2 t0 C/ a2 m* Y1 ?- v+ Z) |% Y参数这一块主要关注的是加密模式(Data encryption type)、秘钥长度(KeySize)、秘钥(Encryption/Decryption key),其他参数保持默认就可以 其中加密模式支持如下 秘钥长度支持128位、256位 秘钥的值可以在cube中配置,也可以这里保持默认值,回头在代码中重新配置(当然上述的这些参数都可以通过代码再次配置,这个待会实战部分会有介绍)
0 @- [0 f+ U1 I最后点击右上角生成代码 2 i" I! Q. S1 z: r
二、实战 2.1 AES时钟初始化及函数介绍 先来看一下CUBE自动生成的代码 首先是变量 - CRYP_HandleTypeDef hcryp;- L" _( k, Q8 U' C+ b4 t, W7 V
- uint32_t pKeyAES[4] = {0x00000000,0x00000000,0x00000000,0x00000000};
复制代码这边的pKeyAES就是秘钥,和之前cube中设置的一致(下面的测试中我会尝试更换秘钥) 然后就是AES模块的初始化函数
* G6 K$ d4 l* _* e" A( d1 m w
- W0 T# o' w U4 H4 Z" u在初始化函数中可以看到,配置了各个参数,和cube中的一致。然后就是调用了初始化,秘钥、加密模式等就是在init时配置进去的,如果需要更换,那就要调用HAL_CRYP_DeInit(),修改配置参数,然后再调用HAL_CRYP_Init()(这个待会儿我也会尝试一下) , M: A# o; w6 f% G! F
在使用加密前,需要在main函数的最一开始就开启AES的时钟 - __HAL_RCC_AES_CLK_ENABLE();
复制代码
5 w9 {( J1 U$ Y( W" q+ n; \加解密函数只提供了HAL库,对应的有三种方式:阻塞加解密、异步加解密、DMA传输的加解密 具体函数如下 - HAL_StatusTypeDef HAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
9 S( F3 h+ f9 w5 t0 p - uint32_t Timeout);! U- i9 f: f+ b% `" b3 c x+ k, w4 y
- HAL_StatusTypeDef HAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
1 U) y, w0 _' F$ `" Y1 Y/ {5 g - uint32_t Timeout);2 r8 G+ N x& @# {3 p
- HAL_StatusTypeDef HAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);: i& N. U/ k9 y* j
- HAL_StatusTypeDef HAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
% q$ J/ b1 F8 j4 j - HAL_StatusTypeDef HAL_CRYP_Encrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);+ `2 J4 [( b- l' T
- HAL_StatusTypeDef HAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output);
复制代码 ! B" f" V3 l6 o! F3 n3 k! i# I
这里我再插一嘴,AES是需要加解密数据为16字节的倍数才可以运行,如果你的不是16字节的倍数,那么就需要做一下填充,加解密接口是不提供填充的,需要自己实现 : c" K& y% h' A7 y
今天我们的测试的是最基础的阻塞加解密函数
, K$ x/ F: E2 d3 w5 r+ H2.2 AES ECB 128bit加解密测试 我们刚才在cube中默认配置的就是AES ECB,那就可以直接进行加解密的测试 先准备一下明文和对应加密后的秘文,以及存储加解密后结果的数组。待会儿我还有尝试更改秘钥,那么这里就把自定义秘钥相关的也写上 - /* 计算得到的秘文 */4 Y: F G( ]2 A/ Y4 s. Y, k
- uint32_t Computed_Ciphertext[AES_DATA_SIZE];" H( T' @. \" @
- /* 计算得到的明文 */( d/ e. |% G5 |1 @" L! \- K5 b
- uint32_t Computed_plainText[AES_DATA_SIZE];
# z7 w7 ]" x) _" p* o6 c! U - v/ `& p6 s/ Y) e
- /* 用户自定义128bit秘钥 */( w! q! R, F/ A8 q' g- s Q% v
- uint32_t user_defined_AesKey_128bit[AES_KEY_SIZE] =
3 x( B) U0 f r4 N' w# Z& @& ] - {: F1 {4 |* f# S: f9 |0 K& O+ @
- 0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff5 C( u5 d9 n8 f) j5 ?- l
- };
' ~$ ?, e8 S1 b3 d( u( z - /* 加密前的明文 */* [3 P: y9 W- M& [. }% K0 U
- uint32_t AES_plainText[AES_DATA_SIZE] =
: w! w2 F. N. \2 |0 `/ A - {% p5 s: T0 V5 X- f5 O
- 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f
. m& H p/ i8 ?) J. c - };$ O+ k4 O. M; f, q' ?4 W
/ b9 i' i2 G: U% t, V$ B( ^" e0 }- /* AES ECB使用用户自定义128bit秘钥加密后的秘文 */
5 W. v, p* y0 p3 W, z0 D' | - uint32_t AES_ECB_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =- w( G b0 Y) ^1 s
- {
( w9 D9 t' [9 h0 { - 0x279FB74A, 0x7572135E, 0x8F9B8EF6, 0xD1EEE003
9 f) U, k: i( V( |. x: S - };
# @# H, o9 Q/ I5 Z5 S8 m - /* AES ECB使用cube默认128bit秘钥加密后的秘文 */; g' Z8 y) q" r3 O6 I8 c7 v5 e1 [
- uint32_t AES_ECB_Ciphertext_cubeDefault_128bitKey[AES_DATA_SIZE] =: j1 z# |7 C U+ c7 j/ T/ ], v
- {$ o6 f1 ]0 E+ `1 N. ?% c5 y/ g& h+ h7 r" n
- 0x7ACA0FD9, 0xBCD6EC7C, 0x9F974666, 0x16E6A282
5 U. P0 S4 S0 q/ }/ }! { - };
复制代码
这里创建数组时要注意,一定要是uint32_t类型的,不然和加解密接口的入参类型不一致,不要尝试使用uint8_t再忽略编译警告,别问我是咋知道的
1 p r# i6 }0 P! g+ O* j% B然后在加一下宏定义 - /* AES加解密阻塞式函数超时时间 */
, A! d" D4 L/ n+ {0 D) h* ^+ _. { - #define AES_TIMEOUT_VALUE 0xFF //0xFF按以往经验应该是永不超时,但是没测试过。也不清楚小于ff的值与时间的关系。就先这么设置着再说3 D! z J2 j$ v2 F: C$ Y
- /* AES加解密数据的长度(byte) */
) X; N% {& @8 ?4 \3 W! m: u9 x - #define AES_DATA_SIZE_BYTE 16: r' a& E! T% M: d" x0 ^5 d2 g
- /* AES加解密数据的长度(uint32_t) */
6 i# ]( r! X: c( X- W) ~+ ^4 s - #define AES_DATA_SIZE (AES_DATA_SIZE_BYTE / 4)3 a" i% v3 |8 ~' Y s
- /* AES加解密秘钥的长度(bit) */
% o8 c) t; T3 s( s/ M$ ~+ x - #define AES_KEY_SIZE_BIT 128
$ u- f) A- |5 N8 m6 l; V; c - /* AES加解密数据的长度(uint32_t) */
0 W( F9 Q9 E0 e2 e - #define AES_KEY_SIZE (AES_KEY_SIZE_BIT / 4)
复制代码然后写一下AES ECB 128bit秘钥的加解密测试函数以及dump函数 - void dump_data(uint32_t *pData, uint8_t Size)
( m Y! K) M5 V4 ]$ W( E - {+ K2 E; s( T+ R7 G. R% |$ F6 m, s
- for (uint8_t i = 0; i < Size; i++)
6 |* M- b! j9 Z - {& s3 X/ D# |9 C, }+ D; L( D- C
- printf("%02X ", ((*pData & 0xFF000000) >> 24));5 a/ u m- \5 b3 i+ b3 I
- printf("%02X ", ((*pData & 0x00FF0000) >> 16));
( P& G5 f; {, ` - printf("%02X ", ((*pData & 0x0000FF00) >> 8));9 R! F6 a% i* u9 y8 c+ u
- printf("%02X ", ((*pData & 0x000000FF)));
# x6 s; B: V6 _7 m# u4 g; | - pData++;3 Q# ~6 Y7 p A
- }
3 h+ l9 k5 [& P. ? - printf("\r\n");/ O1 }& P% l/ z4 c
- }1 c) p* U1 X7 {8 `- |
: ] D9 }& g6 n- ~- void AES_encrypt_test(uint32_t *plainText)
9 @! n; @5 Y1 w4 S& f - {1 K# P2 d4 V2 N! n
- printf("plainText = ");2 C& r5 }) S8 S8 A0 [ O6 f* m
- dump_data(plainText, AES_DATA_SIZE);9 @$ s4 m* E' U8 `
/ }! K2 r1 M; d, g, n3 G- if (HAL_CRYP_Encrypt(&hcryp, plainText, AES_DATA_SIZE, Computed_Ciphertext, AES_TIMEOUT_VALUE) == HAL_OK)
) u7 f* |, t" K4 k$ S/ m& b2 Y) J - {: @! \0 }! G3 Z. Y' |1 f2 h
- printf("AES encrypt success\r\n");# _& b6 r1 N# ?6 L9 S
- printf("Computed_Ciphertext = ");
2 C4 M% B! N4 q - dump_data(Computed_Ciphertext, AES_DATA_SIZE);" x( ^8 R- s0 f) Z
- }
6 A2 K- |. H& P% L$ Y! k7 j - else
* F9 C8 c( ~" Q$ {3 O - {
/ X0 \7 G5 Q# C$ r1 N+ N& r& \* b - printf("AES encrypt error\r\n");
" \. z. o5 R. t7 {" J& @& a - Error_Handler();
' }2 c# ~, Q. e* i - }
3 M- }% f @- ~% R0 Y3 ~ - printf("\r\n");
: R j; {( [6 i: N+ r - }$ r: t: r; r9 d4 @3 ]9 n
( F4 f- h4 a) b4 \- void AES_dencrypt_test(uint32_t *cipherText)
# a; C0 W& ^8 p. T/ e- P% a M9 r - {1 f- R* L' X1 i- Q
- printf("cipherText = ");
+ @% d3 X$ d( V* K" f9 |3 h - dump_data(cipherText, AES_DATA_SIZE);
! p, e/ L" Z5 z' `* b
' Z. M( o1 j+ I. y E$ o+ J, {9 X3 ~! i- if (HAL_CRYP_Decrypt(&hcryp, cipherText, AES_DATA_SIZE, Computed_plainText, AES_TIMEOUT_VALUE) == HAL_OK)
M; ^' |, k2 p: T - {' N$ O7 V9 W9 p5 R- V6 v: P
- printf("AES dencrypt success\r\n");
2 l1 T, n6 V/ h9 x/ E - printf("Computed_plainText = ");
' O/ w: J; r0 L( s+ s& U2 K8 o1 d6 M - dump_data(Computed_plainText, AES_DATA_SIZE);
* _$ ^7 k' e6 \3 k( `9 {/ p - }
* T9 M( j2 \( ` - else4 ] ?! M" @3 L: T9 t! m, @
- {2 [2 W) ?; M8 v/ ^" g7 N2 M
- printf("AES dencrypt error\r\n");; j# V& Z* n; ~
- Error_Handler();+ x5 @9 }+ s! t- D7 R
- }
% Q1 O8 F. ?3 w3 G1 n - printf("\r\n");
9 [. `2 m& N! d. l% S - }
复制代码
+ f% w. T/ ?# ~. V; u
8 a- h0 a+ W: T5 l! N
然后在main中调用 - printf("AES ECB use cubeDefault key 128Bit encrypt test\r\n");9 y$ G ^$ k! }6 i( S* o& M
- AES_encrypt_test(&AES_plainText[0]);
0 I+ }; [+ [! p0 B9 R - printf("AES ECB use cubeDefault key 128Bit dencrypt test\r\n");6 H) R8 F- \! _! y# m, ?2 j
- AES_dencrypt_test(&AES_ECB_Ciphertext_cubeDefault_128bitKey[0]);
复制代码编译运行一下,结果如下 和在线工具对比一下,结果一致
" h$ ~4 }2 I6 f- u/ I: G接下来尝试更换一下秘钥,再运行加解密 更换秘钥有2种方案,第一是直接对MX_AES_Init中的内容修改,但是因为这里是cube自动生成的,后续cube再生成一次就又变回去了。所以我选择方案二:去初始化,修改参数,再初始化。 3 g7 v3 C/ m9 M; E0 G+ Q7 U
改变秘钥函数 - void change_key_to_user_defined_AesKey_128bit()! Y+ R0 R( h( n/ b! K* }
- {
$ T; q- ?& w8 ~4 V% D9 R& A - printf("change AES KEY to user_defined_AesKey_128bit\r\n");
1 A/ z& `" |& J. ?& ] - /* 先去初始化 */
0 F0 O s6 } s7 W - if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)! O+ U9 U& w- ]( v" x+ E' n* J B
- {' {+ @! O( |1 j9 l
- printf("HAL_CRYP_DeInit error\r\n");
/ F7 L3 b# ?- |. W/ Q9 | - Error_Handler(); W( d- z7 f0 |. V& c% Z1 d
- }
% m; K: g9 _- q" U - * p! z( s- K8 W0 l
- /* 修改使用的秘钥 */* U& F- ~1 j1 M1 p, D0 Z
- hcryp.Init.pKey = (uint32_t *)user_defined_AesKey_128bit;
- A' O- \2 |$ a9 o6 L' f
& k. H7 |+ j: u! h) T: E. k' b* w% ^. v- /* 再次初始化 */
& v4 M- X7 \& @" f1 E+ Y2 s - if (HAL_CRYP_Init(&hcryp) != HAL_OK)/ D4 |" F) K& m. V, j
- { [4 F$ s: |4 t! g$ k
- printf("HAL_CRYP_Init error\r\n");+ B1 y3 p Q# b4 h
- Error_Handler();
$ ~4 s& {) G3 j1 q$ j3 `* q% D1 z - }4 U5 |. s; G6 C' y
- printf("\r\n");
# E5 J% U0 R4 |0 o+ J - }
复制代码
" N0 n4 M, M4 v6 m( a: x" v q9 ^" }% m+ m* A& N' f
然后在main中调用切换函数,并且再次进行加解密,测试一下更换秘钥是否成功 - change_key_to_user_defined_AesKey_128bit();
; K# s- @5 a5 p+ S/ ?" [ - 8 K" x( D: i# P* v( z
- printf("AES ECB use user defined key 128Bit encrypt test\r\n");6 A) d/ z5 c0 w
- AES_encrypt_test(&AES_plainText[0]);/ Y0 ?: G' }1 _8 U% m& q9 e: V) v
- printf("AES ECB use user defined key 128Bit dencrypt test\r\n");
" K5 K, A1 x# }! Q3 V - AES_dencrypt_test(&AES_ECB_Ciphertext_user_defined_128bitKey[0]);
复制代码 编译下载运行效果如下 和在线工具对比一下,结果一致
8 f8 Z& Z( ]4 ^6 z6 |: S2.2 AES CBC 128bit加解密测试 然后我们把AES模式切换至CBC模式,来进行测试 CBC相比ECB多了一个IV参数,所以我们先把IV的数组准备一下 然后准备一下CBC加密后的结果的数组,回头给解密时使用 - /* AES CBC使用用户自定义128bit秘钥加密后的秘文 */
6 X8 R. z; ^) \1 _6 W - uint32_t AES_CBC_Ciphertext_user_defined_128bitKey[AES_DATA_SIZE] =3 P% y0 u8 [4 q' I7 a0 Q
- {
- Z& N( x/ A- q, i4 P* v* z& S% b$ g8 k - 0xFCDBC004, 0xEB4CA8BB, 0x60F4C4A8, 0xC2B9E783
7 G! @9 ]# N# U6 E$ k: o - };
复制代码写一下切换至CBC模式的函数 - void change_to_aes_cbc_mode(); ?2 M# z) x% l
- {5 y8 X9 ?7 W6 V4 w* \
- printf("change to AES CBC mode\r\n");" M& ]+ o6 h+ n# Z& K
- /* 先去初始化 */
( D( d' L# [ w: A( L - if (HAL_CRYP_DeInit(&hcryp) != HAL_OK)
( o6 Z m/ J; U6 u8 B7 _ - {9 T/ L) G0 ~( j# S: R
- printf("HAL_CRYP_DeInit error\r\n");/ t+ d0 h E0 P' y" t' \/ w/ Q
- Error_Handler();& X8 D: d) _' |6 K: d8 S; N
- } T2 ?5 w" |9 o- E% C( U
6 E' }4 b* O* C% K- /* 修改为CBC模式 */
* t+ C# }* f4 Z$ b; m - hcryp.Init.Algorithm = CRYP_AES_CBC;
/ T7 ~* a* B1 r$ N - /* 设置IV */4 k) O! s% u2 N# u/ E
- hcryp.Init.pInitVect = AES_CBC_IV;. w/ T( M1 _: ^7 P# }* n6 o
- / X1 B8 i/ r# v0 N
- /* 再次初始化 */
. U8 E Q& f$ W5 j n - if (HAL_CRYP_Init(&hcryp) != HAL_OK)
, y$ N/ O5 p/ j3 P5 J5 Y - {
- E5 l+ |$ E) t! `; J - printf("HAL_CRYP_Init error\r\n");
2 ?" x. ~6 [* d2 y - Error_Handler();! ~0 E. S( |! z8 F3 R
- }: y" P$ ?$ K. I- Q# o u# x( p# A
- printf("\r\n");; [5 n3 j* _9 ]; @3 o
- }
复制代码在main中调用切换函数,然后进行CBC加解密测试 - change_to_aes_cbc_mode();+ v: C+ O9 S* `0 {' [3 H
# [( M: H0 E; r3 U" _- printf("AES CBC use user defined key 128Bit encrypt test\r\n");
: G% d9 O1 H% x0 i* A, F - AES_encrypt_test(&AES_plainText[0]);. K$ M4 c ^, r# T
- printf("AES CBC use user defined key 128Bit dencrypt test\r\n");6 b8 S( P6 u' [+ s6 q& f2 W% ~
- AES_dencrypt_test(&AES_CBC_Ciphertext_user_defined_128bitKey[0]);
复制代码编译下载,结果如下 和在线工具对比一下,结果一致 三、总结 今天的测试非常成功,都与在线工具结果一致。AES其实还有很多东西,例如使用256bit秘钥、CTR、GCM_GMAC、CCM加解密方式等,由于时间关系我就不一一进行测试了,基本上与就今天的改变秘钥、改变加密方式大同小异,大家可以自行研究。
& X S. J$ z4 {本次工程代码:
STM32U0_AES_test.rar
(5.21 MB, 下载次数: 3)
|
好详细啊👍