Skip to main content
Visitor
Nov 12, 2026 3:45 PM UTC
Question

STM32WBA65 SAES: Chained HAL_CRYPEx_UnwrapKey() Works on STM32U545 but Fails on WBA65

Hello ST Community,
 
I am working with the SAES peripheral on both an STM32U545 and an STM32WBA65.
I am trying to use the wrapped key mode to protect encryption keys.
 
For firmware updates, I have implemented the following key hierarchy:
  • A product key is wrapped using the DHUK and stored in Flash.
  • A binary key is used to encrypt the firmware image.
  • The binary key is encrypted using the product key.
At runtime, the device should:
  • Unwrap the product key using the DHUK.
  • Use the unwrapped product key to unwrap the binary key.
  • Use the binary key to decrypt the firmware image.
I would like to perform this complete sequence using SAES wrapped mode.
This works correctly on the STM32U545, but not on the STM32WBA65, and I cannot identify the reason for this difference in behavior.
 
On both Nucleo boards (NUCLEO-U545RE-Q and NUCLEO-WBA65RI), I implemented the following test code:
  /* The size of the plaintext is in words */
#define KEY_SIZE 8U
#define PLAINTEXT_SIZE 8U

uint32_t ProductKey[KEY_SIZE] = {
0x30313233U, 0x34353637U, // 0123 4567
0x38394142U, 0x43444546U, // 89AB CDEF
0x30313233U, 0x34353637U, // 0123 4567
0x38394142U, 0x43444546U // 89AB CDEF
};

uint32_t BinaryKey[KEY_SIZE] = {
0x46454443U, 0x42413938U, // FEDC BA98
0x37363534U, 0x33323130U, // 7654 3210
0x46454443U, 0x42413938U, // FEDC BA98
0x37363534U, 0x33323130U // 7654 3210
};

uint32_t Plaintext[PLAINTEXT_SIZE] = {
0x41424344U, 0x45464748U, // ABCD EFGH
0x494A4B4CU, 0x4D4E4F50U, // IJKL MNOP
0x51525354U, 0x55565758U, // QRST UVWX
0x595A4142U, 0x43444546U // YZAB CDEF
};

/* Used for storing the encrypted product key */
uint32_t EncryptedProductKey[KEY_SIZE];

/* Used for storing the encrypted binary key */
uint32_t EncryptedBinaryKey[KEY_SIZE];

/* Used for storing the encrypted text */
uint32_t EncryptedText[PLAINTEXT_SIZE];

/* Used for storing the decrypted text */
uint32_t DecryptedText[PLAINTEXT_SIZE];


/* *************************************************** */
/* Encrypt product key with DHUK */
/* *************************************************** */
hcryp.Instance = SAES;
hcryp.Init.DataType = CRYP_NO_SWAP;
hcryp.Init.KeySize = CRYP_KEYSIZE_256B;
hcryp.Init.Algorithm = CRYP_AES_ECB;
hcryp.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_WORD;
hcryp.Init.KeyIVConfigSkip = CRYP_KEYNOCONFIG;
hcryp.Init.KeyMode = CRYP_KEYMODE_WRAPPED;
hcryp.Init.KeySelect = CRYP_KEYSEL_HW;
hcryp.Init.KeyProtection = CRYP_KEYPROT_DISABLE;
if (HAL_CRYP_Init(&hcryp) != HAL_OK)
{
Error_Handler();
}

if (HAL_CRYPEx_WrapKey(&hcryp, ProductKey, EncryptedProductKey, TIMEOUT_VALUE) != HAL_OK)
{
Error_Handler();
}

/* *************************************************** */
/* Encrypt binary key with product key */
/* *************************************************** */
hcryp.Instance = SAES;
hcryp.Init.DataType = CRYP_NO_SWAP;
hcryp.Init.KeySize = CRYP_KEYSIZE_256B;
hcryp.Init.pKey = ProductKey;
hcryp.Init.Algorithm = CRYP_AES_ECB;
hcryp.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_WORD;
hcryp.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ONCE;
hcryp.Init.KeyMode = CRYP_KEYMODE_NORMAL;
hcryp.Init.KeySelect = CRYP_KEYSEL_NORMAL;
hcryp.Init.KeyProtection = CRYP_KEYPROT_DISABLE;
if (HAL_CRYP_Init(&hcryp) != HAL_OK)
{
Error_Handler();
}

if (HAL_CRYP_Encrypt(&hcryp, BinaryKey, KEY_SIZE, EncryptedBinaryKey, TIMEOUT_VALUE) != HAL_OK)
{
Error_Handler();
}

/* *************************************************** */
/* Encrypt plaintext with binary key */
/* *************************************************** */
hcryp.Instance = SAES;
hcryp.Init.DataType = CRYP_NO_SWAP;
hcryp.Init.KeySize = CRYP_KEYSIZE_256B;
hcryp.Init.pKey = BinaryKey;
hcryp.Init.Algorithm = CRYP_AES_ECB;
hcryp.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_WORD;
hcryp.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ONCE;
hcryp.Init.KeyMode = CRYP_KEYMODE_NORMAL;
hcryp.Init.KeySelect = CRYP_KEYSEL_NORMAL;
hcryp.Init.KeyProtection = CRYP_KEYPROT_DISABLE;
if (HAL_CRYP_Init(&hcryp) != HAL_OK)
{
Error_Handler();
}

if (HAL_CRYP_Encrypt(&hcryp, Plaintext, PLAINTEXT_SIZE, EncryptedText, TIMEOUT_VALUE) != HAL_OK)
{
Error_Handler();
}

/* *************************************************** */
/* Decrypt plaintext with binary key */
/* *************************************************** */
hcryp.Instance = SAES;
hcryp.Init.DataType = CRYP_NO_SWAP;
hcryp.Init.KeySize = CRYP_KEYSIZE_256B;
hcryp.Init.Algorithm = CRYP_AES_ECB;
hcryp.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_WORD;
hcryp.Init.KeyIVConfigSkip = CRYP_KEYNOCONFIG;
hcryp.Init.KeyMode = CRYP_KEYMODE_WRAPPED;
hcryp.Init.KeySelect = CRYP_KEYSEL_HW;
hcryp.Init.KeyProtection = CRYP_KEYPROT_DISABLE;
if (HAL_CRYP_Init(&hcryp) != HAL_OK)
{
Error_Handler();
}

/* Unwrap product key with DHUK */
if (HAL_CRYPEx_UnwrapKey(&hcryp, EncryptedProductKey, TIMEOUT_VALUE) != HAL_OK)
{
Error_Handler();
}

/* Unwrap binary key with product key */
if (HAL_CRYPEx_UnwrapKey(&hcryp, EncryptedBinaryKey, TIMEOUT_VALUE) != HAL_OK)
{
Error_Handler();
}

/* Decrypt ciphertext with binary key */
if (HAL_CRYP_Decrypt(&hcryp, EncryptedText , PLAINTEXT_SIZE, DecryptedText, TIMEOUT_VALUE) != HAL_OK)
{
Error_Handler();
}

/*Compare decryption result with Plaintext*/
if(memcmp(DecryptedText, Plaintext, (PLAINTEXT_SIZE * sizeof(uint32_t))) != 0)
{
/* Processing Error */
Error_Handler();
}
Encryption sequence
  • Wrap ProductKey using the DHUK (HAL_CRYPEx_WrapKey)
  • Encrypt BinaryKey using ProductKey (HAL_CRYP_Encrypt)
  • Encrypt Plaintext using BinaryKey (HAL_CRYP_Encrypt)
Unwrapping / Decryption sequence
  • Unwrap ProductKey using the DHUK (HAL_CRYPEx_UnwrapKey)
  • Unwrap BinaryKey using the ProductKey (HAL_CRYPEx_UnwrapKey)
  • Decrypt the ciphertext (HAL_CRYP_Decrypt)
 
The complete test works on the STM32U545, but not on the STM32WBA65.
Performing two consecutive HAL_CRYPEx_UnwrapKey() operations does not work on the STM32WBA65.
More specifically, the second HAL_CRYPEx_UnwrapKey() call completes successfully, but the final decrypted plaintext does not match the original plaintext.
 
My suspicion is that the internal key register is cleared or overwritten during the second unwrap operation, but I have not found any documentation confirming this behavior.
 
My expectation is that, after the first HAL_CRYPEx_UnwrapKey(), the unwrapped ProductKey remains internally available and can be used by the second HAL_CRYPEx_UnwrapKey() operation to unwrap the BinaryKey, as observed on the STM32U545.
 
Is there any known limitation on the STM32WBA65 regarding chained wrapped-key operations?
Are there any architectural or implementation differences in SAES wrapped-key handling between the STM32U5 and STM32WBA families that could explain this behavior?
 
Test environment:
  • STM32CubeU5: v1.9.0
  • STM32CubeWBA: v1.10.0
 
Thank you for your help.

 

1 reply

Jocelyn RICARD
ST Employee
Nov 12, 2026 5:41 PM UTC

Hello ​@Droup ,

you cannot unwrap twice.

Unwrapping mechanism always uses DHUK as encryption key.

So, if you wrap your product key, then the firmware encryption key can only be decrypted in clear. So, the “Unwrap BinaryKey using the ProductKey (HAL_CRYPEx_UnwrapKey)” step cannot work. You need to use normal decryption.

Best regards

Jocelyn