cancel
Showing results for 
Search instead for 
Did you mean: 

Nucleo F439ZI AES in GCM Mode Accelerator Struggles

CatChips
Associate II

Hi Everyone!

 

I am trying to understand why I cannot get the result of the AES in GCM mode HAL_CRYP_Encrypt on the F439ZI board to match the AES in GCM result anywhere else.  I am using Python's pycryptodome library for result comparison. I have previously seen this very informative post: https://community.st.com/t5/stm32-mcus-security/a-guide-to-the-hal-of-the-aes-accelerator-or-how-to-fix-it/m-p/134252

However, I am still stuck somewhat.

 

I am also using the default AES-256 key together with the default IV provided by the CubeMX:

 

 

 

 

 

 

CRYP_HandleTypeDef hcryp;
__ALIGN_BEGIN static const uint32_t pKeyCRYP[8] __ALIGN_END = {
                            0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000};
__ALIGN_BEGIN static const uint32_t pInitVectCRYP[4] __ALIGN_END = {
                            0x00000000,0x00000000,0x00000000,0x00000002};
__ALIGN_BEGIN static const uint32_t HeaderCRYP[1] __ALIGN_END = {
                            0x00000000};


/**
  * @brief CRYP Initialization Function
  *  None
  * @retval None
  */
static void MX_CRYP_Init(void)
{

  /* USER CODE BEGIN CRYP_Init 0 */

  /* USER CODE END CRYP_Init 0 */

  /* USER CODE BEGIN CRYP_Init 1 */

  /* USER CODE END CRYP_Init 1 */
  hcryp.Instance = CRYP;
  hcryp.Init.DataType = CRYP_DATATYPE_32B;
  hcryp.Init.KeySize = CRYP_KEYSIZE_256B;
  hcryp.Init.pKey = (uint32_t *)pKeyCRYP;
  hcryp.Init.pInitVect = (uint32_t *)pInitVectCRYP;
  hcryp.Init.Algorithm = CRYP_AES_GCM;
  hcryp.Init.Header = (uint32_t *)HeaderCRYP;
  hcryp.Init.HeaderSize = 1;
  hcryp.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_WORD;
  if (HAL_CRYP_Init(&hcryp) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN CRYP_Init 2 */

  /* USER CODE END CRYP_Init 2 */

}


int main(void)
{
.
.
.
.
  MX_CRYP_Init();

 uint8_t keyBuff[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

  uint32_t ivBuff[4] = {0x00000000, 0x00000000, 0x00000000, 0x00000000};

  uint32_t plain[4] = {0x61616161, 0x61616161, 0x61616161, 0x61616161};

  uint8_t ciphertext[16];


  if (HAL_CRYP_Encrypt(&hcryp, plain, 4, ciphertext, HAL_MAX_DELAY) != HAL_OK) {
      // HANDE THE ERROR
  }


  // Print debugging information
  for (int i = 0; i < 16; ++i) {
	  char printy[10];
	  int len = sprintf(printy, " -%x-", ciphertext[i]);
	  HAL_UART_Transmit(&huart3, (uint8_t*)printy, len, 5000);
  }

  HAL_UART_Transmit(&huart3, "\n\n", 2, 5000);


}

 

 

 

 

 

 

 

I am getting the output of:  -5c- -21- -c6- -af- -f- -a- -1- -2c- -b2- -a4- -2f- -66- -79- -fc- -92- -db-

 

When I simulate above in the following Python code:

 

 

 

 

 

 

from Cryptodome.Cipher import AES 
from Cryptodome.Random import get_random_bytes

# Key and IV (Initialization Vector) from your STM32 code
key = bytes([0x00] * 32)  # 256-bit key
key = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

iv = bytes([0x00] * 15 + [0x02])  # 96-bit IV (12 bytes)


# Header (AAD - Additional Authenticated Data)
header = bytes([0x00]*4)

# Data to encrypt
plaintext = b'aaaaaaaaaaaaaaaa'
plaintext = b'\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61'

# Create AES-GCM cipher object
cipher = AES.new(key, AES.MODE_GCM, nonce=iv)

# Encrypt the data
#cipher.update(header)  # Add AAD
ciphertext, tag = cipher.encrypt_and_digest(plaintext)

print(f'Ciphertext: {ciphertext.hex()}')
#print(f'Tag: {tag.hex()}')

 

 

 

I get 981e09865ee3f41ea3d5fc7981166d94

 

I am still lost on why the discrepancy exists.  Did lots of looking and read much documentation and posts, but no luck.  Any help would be much appreciated.

 

1 ACCEPTED SOLUTION

Accepted Solutions
STea
ST Employee

Hello @CatChips ,

in fact, this is a problem with the python script and not with the calculated value in the STM32.
the last four Hex digits in the initialization vector should not be used in the python script here you will find attached a version of the script implementing your desired test with the same calculated value in the STM32 as well as the main.c config used.

 here is the calculated cipher with the script:

STea_0-1723756194016.png

and here is the calculated cipher with the MCU:

STea_1-1723756254138.png

Regards



In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

View solution in original post

4 REPLIES 4
STea
ST Employee

Hello @CatChips ,

in fact, this is a problem with the python script and not with the calculated value in the STM32.
the last four Hex digits in the initialization vector should not be used in the python script here you will find attached a version of the script implementing your desired test with the same calculated value in the STM32 as well as the main.c config used.

 here is the calculated cipher with the script:

STea_0-1723756194016.png

and here is the calculated cipher with the MCU:

STea_1-1723756254138.png

Regards



In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

You've got endian issues with your IV, pass the array as bytes to be consistent

Or

__ALIGN_BEGIN static const uint32_t pInitVectCRYP[4] __ALIGN_END = {
0x00000000,0x00000000,0x00000000,0x02000000};

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Thank you so much @STea and @Tesla DeLorean ! This is very helpful!  I am now able to get the same results for a single encryption.

However, I noticed that whenever I encrypt the same block using STM32 using HAL_CRYP_Encrypt with AES-GCM, it seems to be generating the same result.  This goes against the GCM mode.

Any ideas?

Thank you.

 

Edit: I have added the following to the config, but it does not have effect. Seems like the state of the CRYP device is reset after each call to HAL_CRYP_Encrypt:

hcryp->Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ONCE;

Hello @CatChips ,

One of the key features of GCM mode is that it uses a unique initialization vector (IV) for each encryption operation to ensure that the same plaintext encrypted multiple times will produce different ciphertexts. This is crucial for maintaining security, as reusing the same IV with the same key can lead to vulnerabilities. If the IV is not changing between encryption operations, the same plaintext will produce the same ciphertext. Ensure that the IV is unique for each encryption operation. Properly manage the IV to ensure it is not reused is required. This can be done by incrementing a counter or using a random number generator to create a new IV for each encryption.
Regards

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.