Skip to main content
Associate
April 11, 2026
Solved

Unexpected Behavior of the STM32 CRYP Module

  • April 11, 2026
  • 10 replies
  • 595 views

I'm recently working on benchmarking a various implementations and configurations of cryptographic algorithms such AES-GCM on STM32. Two of these tested function are the following :

void test_aes_hardware(void)
{
 uint32_t plaintext[DATA_SIZE/4];
 uint32_t ciphertext[DATA_SIZE/4];
 uint32_t decrypted[DATA_SIZE/4];

 uint8_t key_bytes[32];
 uint8_t iv_bytes[16];

 uint32_t key[8];
 uint32_t iv[4];

 uint8_t ikm[4];
 uint8_t salt[4];
 uint8_t info1[] = "HW_AES_KEY";
 uint8_t info2[] = "HW_AES_IV";

 uint32_t rnd;

 /* RNG */
 HAL_RNG_GenerateRandomNumber(&hrng, &rnd);
 memcpy(ikm, &rnd, 4);

 HAL_RNG_GenerateRandomNumber(&hrng, &rnd);
 memcpy(salt, &rnd, 4);

 /* KDF */
 xkdfBlake(key_bytes, 32, ikm, 4, salt, 4, info1, sizeof(info1));
 xkdfBlake(iv_bytes, 16, ikm, 4, salt, 4, info2, sizeof(info2));

 memcpy(key, key_bytes, 32);
 memcpy(iv, iv_bytes, 16);

 for (int i = 0; i < DATA_SIZE / 4; i++) {
 	uint32_t w = (i*4 + 1)
 			|((i*4 + 2) << 8)
				|((i*4 + 3) << 16)
				|((i*4 + 4) << 24);
 	plaintext[i] = w;
 }


 /* Configure CRYP */
 hcryp.Instance = CRYP;
 hcryp.Init.DataType = CRYP_DATATYPE_32B;
 hcryp.Init.KeySize = CRYP_KEYSIZE_256B;
 hcryp.Init.pKey = key;
 hcryp.Init.Algorithm = CRYP_AES_GCM;
 hcryp.Init.pInitVect = iv;
 hcryp.Init.Header = NULL;
 hcryp.Init.HeaderSize = 0;

 HAL_CRYP_Init(&hcryp);

 bench_start();

 HAL_CRYP_Encrypt(&hcryp,
 plaintext,
 DATA_SIZE/4,
 ciphertext,HAL_MAX_DELAY);

 while (HAL_CRYP_GetState(&hcryp) != HAL_CRYP_STATE_READY);
 uint32_t time = bench_stop();
 HAL_CRYP_Decrypt(&hcryp,
 ciphertext,
 DATA_SIZE/4,
 decrypted,
 HAL_MAX_DELAY);
 while (HAL_CRYP_GetState(&hcryp) != HAL_CRYP_STATE_READY);
 if (memcmp(plaintext, decrypted, DATA_SIZE) != 0) {
 printf("Mismatch!\n");
 Error_Handler();;
 }

 printf("AES-GCM Hardware without DMA: %lu us\r\n", time);
}

The first one demonstarte the use of AES-GCM through CRYP module.

void test_aes_hardware_dma(void)
{
 uint32_t plaintext[DATA_SIZE/4] __attribute__((aligned(32)));
 uint32_t ciphertext[DATA_SIZE/4] __attribute__((aligned(32)));
 uint32_t decrypted[DATA_SIZE/4] __attribute__((aligned(32)));

 uint8_t key_bytes[32];
 uint8_t iv_bytes[16];

 uint32_t key[8] __attribute__((aligned(32)));
 uint32_t iv[4] __attribute__((aligned(32)));

 uint8_t ikm[4];
 uint8_t salt[4];
 uint8_t info1[] = "HW_AES_KEY";
 uint8_t info2[] = "HW_AES_IV";

 uint32_t rnd;

 /* RNG */
 HAL_RNG_GenerateRandomNumber(&hrng, &rnd);
 memcpy(ikm, &rnd, 4);

 HAL_RNG_GenerateRandomNumber(&hrng, &rnd);
 memcpy(salt, &rnd, 4);

 /* KDF */
 xkdfBlake(key_bytes, 32, ikm, 4, salt, 4, info1, sizeof(info1));
 xkdfBlake(iv_bytes, 16, ikm, 4, salt, 4, info2, sizeof(info2));

 memcpy(key, key_bytes, 32);
 memcpy(iv, iv_bytes, 16);

 for (int i = 0; i < DATA_SIZE / 4; i++) {
 uint32_t w = (i*4 + 1)
 | ((i*4 + 2) << 8)
 | ((i*4 + 3) << 16)
 | ((i*4 + 4) << 24);
 plaintext[i] = w;
 }


 SCB_CleanDCache_by_Addr((uint32_t*)plaintext, DATA_SIZE);
 SCB_CleanDCache_by_Addr((uint32_t*)key, sizeof(key));
 SCB_CleanDCache_by_Addr((uint32_t*)iv, sizeof(iv));

 /* Configure CRYP */
 hcryp.Instance = CRYP;
 hcryp.Init.DataType = CRYP_DATATYPE_32B;
 hcryp.Init.KeySize = CRYP_KEYSIZE_256B;
 hcryp.Init.pKey = key;
 hcryp.Init.Algorithm = CRYP_AES_GCM;
 hcryp.Init.pInitVect = iv;
 hcryp.Init.Header = NULL;
 hcryp.Init.HeaderSize = 0;

 HAL_CRYP_Init(&hcryp);

 CrypCompleteDetected = 0;

 bench_start();

 HAL_CRYP_Encrypt_DMA(&hcryp,
 plaintext,
 DATA_SIZE/4,
 ciphertext);

 while (!CrypCompleteDetected);

 SCB_InvalidateDCache_by_Addr((uint32_t*)ciphertext, DATA_SIZE);

 uint32_t time = bench_stop();

 CrypCompleteDetected = 0;

 HAL_CRYP_Decrypt_DMA(&hcryp,
 ciphertext,
 DATA_SIZE/4,
 decrypted);
 while (!CrypCompleteDetected);

 SCB_InvalidateDCache_by_Addr((uint32_t*)decrypted, DATA_SIZE);

 if (memcmp(plaintext, decrypted, DATA_SIZE) != 0) {
 printf("Mismatch!\n");
 Error_Handler();
 }

 printf("AES-GCM Hardware DMA: %lu us\r\n", time);
}

The second one use DMA to transfer data between RAM and CRYP peripheral 

When starting the program i got normal results with DATA_SIZE<50Kib. But after that I start getting Mismatches results. When I compare for example only the 100 fisrt bytes it seems that the decrypted data match the initial plaintext and I got an absurd results showing that the encryption exec time of 100Kib < the encryption exec time of 50Kib.

 

Please feel free to ask me for additional informations.
Thank you.

Best answer by TDK

The same issue is in both HAL_CRYP_Encrypt_DMA and HAL_CRYP_Decrypt_DMA . I just chose one.

stm32h7xx-hal-driver/Src/stm32h7xx_hal_cryp.c at a1996eed9172b59887bafaaa0ea1816ea14d48b5 · STMicroelectronics/stm32h7xx-hal-driver

 

You pass in 25600, it multiplies it by 4, so 102400, then stores as a uint16_t, so it truncates to 36864. That is how many bytes (9216 uint32_t vales) get encrypted/decrypted. Which is exactly what you see.

10 replies

TDK
Super User
April 11, 2026

DMA has a transfer limit of 65535 items. It's possible you're running into that issue. Not enough code is shown to tell.

"If you feel a post has answered your question, please click ""Accept as Solution""."
g2f1Author
Associate
April 11, 2026

What parts of code you need to tell? And also what you mean by items in the context of DMA?
Thanks

TDK
Super User
April 11, 2026

> What parts of code you need to tell?

Please include the full part number of the chip you are using. "STM32" refers to too many. Whatever code you are using doesn't appear to be compatible with the STM32H7, so my guess is it's a different one.

The definition of DATA_SIZE would help. Seems like it is 50000 and 100000. If so, these are absolutely massive arrays being allocated on the stack which could be causing its own issues. Typically a chip doesn't have 300+ kB dedicated to the stack.

> And also what you mean by items in the context of DMA?

DMA has a configurable word size which is 1-4 bytes. This is what "item" means in this context.

"If you feel a post has answered your question, please click ""Accept as Solution""."
TDK
Super User
April 11, 2026

My strong guess would be that a uint16_t value is being used somewhere in HAL which is overflowing when you are transferring more than 2^16 bytes. But the details would allow this to be confirmed, and determine whether it is a bug or a limitation.

"If you feel a post has answered your question, please click ""Accept as Solution""."
g2f1Author
Associate
April 11, 2026

Hello, in fact I'm working on H753ZI. For the DATA_SIZE I tested with 10240 Byte (10Kib) and it works but for 102400 byte (100Kib) it won't even though it should since I'm not in the limits of the stack.When debugging I notice that the Module managed to encrypt data well up to the 9205 word but after that it stops somehow.

TDK
Super User
April 11, 2026

If hcryp is zero-initialized, then it's set as DataWidthUnit = CRYP_DATAWIDTHUNIT_WORD. (It's not explicitly initialized in the code, which is why I thought it was another MCU family.)

When HAL_CRYP_Decrypt_DMA is called, it sets Size to the size of the operation in bytes as a uint16_t, which overflows.

https://github.com/STMicroelectronics/stm32h7xx-hal-driver/blob/a1996eed9172b59887bafaaa0ea1816ea14d48b5/Src/stm32h7xx_hal_cryp.c#L1587

https://github.com/STMicroelectronics/stm32h7xx-hal-driver/blob/a1996eed9172b59887bafaaa0ea1816ea14d48b5/Inc/stm32h7xx_hal_cryp.h#L111

So this appears to be a HAL bug, as far as I can see.

 

Setting .Size to the size in bytes also contradicts what the comments say about it, saying it's either in words or bytes.

 

I opened an issue. We will see. Could be missing something.

[Bug]: HAL_CRYP_Decrypt_DMA fails when transfer size is > 65535 bytes · Issue #343 · STMicroelectronics/STM32CubeH7

"If you feel a post has answered your question, please click ""Accept as Solution""."
g2f1Author
Associate
April 11, 2026

Hello,
The problem in fact is not from the HAL_CRYP_Decrypt_DMA function but it's comming from HAL_CRYP_Encrypt_DMA. The latter can't encrypt the entire data and it only encrypt exactly the first 9215 of 32 bits(~36 kib) as you can see in the image above. The decryption works fine. Other thing the problem occurs in both implementation with DMA or without it. It's like there is something that limit the maximum size of the plaintext data to be encrypted.

TDK
TDKBest answer
Super User
April 11, 2026

The same issue is in both HAL_CRYP_Encrypt_DMA and HAL_CRYP_Decrypt_DMA . I just chose one.

stm32h7xx-hal-driver/Src/stm32h7xx_hal_cryp.c at a1996eed9172b59887bafaaa0ea1816ea14d48b5 · STMicroelectronics/stm32h7xx-hal-driver

 

You pass in 25600, it multiplies it by 4, so 102400, then stores as a uint16_t, so it truncates to 36864. That is how many bytes (9216 uint32_t vales) get encrypted/decrypted. Which is exactly what you see.

"If you feel a post has answered your question, please click ""Accept as Solution""."
g2f1Author
Associate
April 11, 2026

CRYP is initialized in my code : 

 hcryp.Instance = CRYP;
 hcryp.Init.DataType = CRYP_DATATYPE_32B;
 hcryp.Init.KeySize = CRYP_KEYSIZE_256B;
 hcryp.Init.pKey = key;
 hcryp.Init.Algorithm = CRYP_AES_GCM;
 hcryp.Init.pInitVect = iv;
 hcryp.Init.Header = NULL;
 hcryp.Init.HeaderSize = 0;
g2f1Author
Associate
April 11, 2026

I see. One more thing why it doesn't truncate to the max oon 16 bit which is 65537.

TDK
Super User
April 11, 2026

That's just how math works on processors. The high bits are dropped.

uint32_t x = 102400;
uint16_t y = x;
printf("y=%u\n", (unsigned)y);

102400 in binary is 0b1 1001 0000 0000 0000. Lowest 16 bits are 0b1001 0000 0000 0000, or 36864.

"If you feel a post has answered your question, please click ""Accept as Solution""."
g2f1Author
Associate
April 11, 2026

It multiply it by 4 meaning that it excepts the size of data to encrypt divided by 4. So i f we want to encrypt 1024 byte i need to give size of 1024/4?

TDK
Super User
April 11, 2026

HAL_CRYP_Encrypt_DMA expects the number of items (as defined by DataWidthUnit), as the documentation states. In your case, this is the number of words.

/**
 * @brief Encryption in DMA mode.
 * @PAram hcryp: pointer to a CRYP_HandleTypeDef structure that contains
 * the configuration information for CRYP module
 * @PAram Input: Pointer to the input buffer (plaintext)
 * @PAram Size: Length of the plaintext buffer either in word or in byte, according to DataWidthUnit
 * @PAram Output: Pointer to the output buffer(ciphertext)
 * @retval HAL status
 */DataWidthUnit

 

It's a bug. You won't be able to encrypt/decrypt more than 16383 words at a time until it is fixed.

"If you feel a post has answered your question, please click ""Accept as Solution""."
g2f1Author
Associate
April 13, 2026

Hello TDK, thank you for your response earlier. I just want to know if changing the type of Size filed of the struct ti uint32_t will solve the issue?

TDK
Super User
April 13, 2026

Yes, changing it to a uint32_t in the HAL library will likely solve the issue.

"If you feel a post has answered your question, please click ""Accept as Solution""."