Skip to main content
AKova.3
Associate II
November 8, 2024
Question

SAES using wrapped key

  • November 8, 2024
  • 7 replies
  • 2936 views

I am working with SAES on STM32U585. I am trying to make use of wrapping/unwrappinng my encryption key with  hardware-secret key DHUK . 

This in the SAES initialization I am using

 

	hcryp.Instance = SAES;
	hcryp.Init.DataType = CRYP_BYTE_SWAP;
	hcryp.Init.KeySize = CRYP_KEYSIZE_128B;
	hcryp.Init.pInitVect = (uint32_t *)iv;
	hcryp.Init.pKey = (uint32_t *)key;
	hcryp.Init.Algorithm = CRYP_AES_CBC;
	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;

 

 I make the encryption key available to SAES with 

 

	 HAL_CRYPEx_WrapKey(&hcryp, key, encrypted_key, 100);
	 HAL_CRYPEx_UnwrapKey(&hcryp, encrypted_key, 100);

 

If I make a simple test with

 

	 HAL_CRYP_Encrypt(&hcryp, (uint32_t*)test, 4, (uint32_t*)wbuf, 100);
	 HAL_CRYP_Decrypt(&hcryp, (uint32_t*)wbuf, 4, (uint32_t*)dbuf, 100);

 

i get the expected results. The encrypted text is what it shoud be and decrypt returns the original text. 

If I however call HAL_CRYP_Decrypt for the second time following the first call, passing it the same encypted text as the first time, it returns incorrect result. Also, a call to HAL_CRYP_Encrypt following a previous HAL_CRYP_Decrypt produces different result if passed the same plain text each time. I have found that all successive calls to HAL_CRYP_Encrypt produce the same result, which is correct if HAL_CRYP_Decrypt hasn't been called before, or incorrect if HAL_CRYP_Decrypt has previously been called. KEYVALID bit in SAES->CR register is set for the whole time and no error flags are raised. I have stepped through both HAL_CRYP_Encrypt and HAL_CRYP_Decrypt functions making sure that software doesn't try to load KEY registers since a valid key is already present there from wrapping/unwrapping procedure. I have observed the same thing when using ECB or CBC mode.

If I do a sequence of denit, init and key unwrapping, the next call to either HAL_CRYP_Encrypt or HAL_CRYP_Decrypt produces expected results. 

It sort of looks like that some state is carried over from decryption on to the next operation.

I did not observe this behaviour if I didn't use key wrapping/unwrapping but was loading the encryption key with software.

Any help would be appriciated.

7 replies

Jocelyn RICARD
ST Employee
November 12, 2024

Hello @AKova.3 ,

When using HAL_CRYP_Decrypt, you have the key preparation that is done automatically.

This key preparation has to be done only once.

So, the way to use this API several times is to setup cryp configuration with:

hcryp.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ONCE;

This configuration has to be done before the first call to HAL_CRYP_Decrypt

Best regards

Jocelyn

AKova.3
AKova.3Author
Associate II
November 13, 2024

I have put CRYP_KEYIVCONFIG_ONCE in to my init function, and if the first function I call afterwards is HAL_CRYP_Decrypt, providing it the encrypted text which would be produced with encryption, the funtion returns all 0s. If I first call HAL_CRYP_Encrypt it returns the correct encrypted text, but the following call to HAL_CRYP_Decrypt returns incorrect value (which is not all 0s this time). It is true that if I repeatedly call HAL_CRYP_Decrypt afterwards it returns the same value each time, but the value is incorrect. As before, a call to HAL_CRYP_Encrypt at this point also returns incorrect results. I have tried other options for hcryp.Init.KeyIVConfigSkip but none of them
provide the desired results. 

Jocelyn RICARD
ST Employee
November 13, 2024

Hello @AKova.3 ,

the parameter  CRYP_KEYIVCONFIG_ONCE must be set only for decryption.

Best regards

Jocelyn

AKova.3
AKova.3Author
Associate II
November 13, 2024

Here's the code I am running

 

uint32_t key[4] = {0x2b7e1516,0x28aed2a6,0xabf71588,0x09cf4f3c};
uint32_t iv[4] = {0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f};
uint32_t encrypted_key[4] = {0};

hcryp.Instance = SAES;
hcryp.Init.DataType = CRYP_BYTE_SWAP;
hcryp.Init.KeySize = CRYP_KEYSIZE_128B;
hcryp.Init.pInitVect = (uint32_t *)iv;
hcryp.Init.pKey = (uint32_t *)key;
hcryp.Init.Algorithm = CRYP_AES_CBC;
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;
HAL_CRYP_Init(&hcryp);

HAL_CRYPEx_WrapKey(&hcryp, key, encrypted_key, 100);
HAL_CRYPEx_UnwrapKey(&hcryp, encrypted_key, 100);

CRYP_ConfigTypeDef Conf = {0};
HAL_CRYP_GetConfig(&hcryp, &Conf);
Conf.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ONCE;
HAL_CRYP_SetConfig(&hcryp, &Conf);

uint8_t wbuf[16] = {0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d};
HAL_CRYP_Decrypt(&hcryp, (uint32_t*)wbuf, 4, (uint32_t*)dbuf, 100);

 

HAL_CRYP_Decrypt return the value of all 0s but should be {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a}

 

Jocelyn RICARD
ST Employee
November 13, 2024

Hello @AKova.3 ,

reason is you removed the encrypt call which is setting the key mode to normal (not done in decrypt).

So, a simple way to fix this is to add:

MODIFY_REG(hcryp.Instance->CR, AES_CR_KMOD, CRYP_KEYMODE_NORMAL);

before the decryption

Best regards

Jocelyn

AKova.3
AKova.3Author
Associate II
November 18, 2024

I appriciate your help but it still didn't solve my issue. I still get the incorrect result when I put the line you suggested before the first call to HAL_CRYP_Decrypt. As before I have configured AES in CBC mode with 128 bit key with this the following inputs:

Key: 2b7e151628aed2a6abf7158809cf4f3c

IV: 000102030405060708090a0b0c0d0e0f

Plaintext: 6bc1bee22e409f96e93d7e117393172a

These parameters procude the ciphertext 7649abac8119b246cee98e9b12e9197d, which I have as an input the to the decrypt function.

I am running the following code:

hcryp.Instance = SAES;
hcryp.Init.DataType = CRYP_BYTE_SWAP;
hcryp.Init.KeySize = CRYP_KEYSIZE_128B;
hcryp.Init.pInitVect = (uint32_t *)iv;
hcryp.Init.pKey = (uint32_t *)key;
hcryp.Init.Algorithm = CRYP_AES_CBC;
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;
HAL_CRYP_Init(&hcryp);

HAL_CRYPEx_WrapKey(&hcryp, ekey, encrypted_key, 100); 
HAL_CRYPEx_UnwrapKey(&hcryp, encrypted_key, 100);

CRYP_ConfigTypeDef Conf = {0};
HAL_CRYP_GetConfig(&hcryp, &Conf);
Conf.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ONCE;
HAL_CRYP_SetConfig(&hcryp, &Conf);

MODIFY_REG(hcryp.Instance->CR, AES_CR_KMOD, CRYP_KEYMODE_NORMAL);
HAL_CRYP_Decrypt(&hcryp, (uint32_t*)wbuf, 4, (uint32_t*)dbuf, 100);

 

The decrypted output I get is f49dac72ed15204d80ed9d5d7b50c478, which is not the original plaintext.

 

I've also found that if I move the wrapping/unwrapping function calls after setting the KeyIVConfigSkip option to CRYP_KEYIVCONFIG_ONCE or if I have the CRYP_KEYIVCONFIG_ONCE option already set with the HAL_CRYP_Init function I get a different result from HAL_CRYP_Decrypt, which this time is c6998505d039fa1d1e6d365a607e4d2c.

Jocelyn RICARD
ST Employee
November 25, 2024

Hello @AKova.3 ,

 

here is the sequence that works:

 

 MX_SAES_AES_Init();
 /* USER CODE BEGIN 2 */
 /* User key AESKey256 encryption*/
 if (HAL_CRYPEx_WrapKey(&hcryp, AESKey256, Encryptedkey, TIMEOUT_VALUE) != HAL_OK)
 {
 /* Processing Error */
 Error_Handler();
 }
 /* we could not compare results, key is not known and unique for each device */

 /* User key AESKey256 decryption*/
 if (HAL_CRYPEx_UnwrapKey(&hcryp, Encryptedkey, TIMEOUT_VALUE) != HAL_OK)
 {
 /* Processing Error */
 Error_Handler();
 }

 MODIFY_REG(hcryp.Instance->CR, AES_CR_KMOD, CRYP_KEYMODE_NORMAL);
 //MODIFY_REG(hcryp.Instance->CR, AES_CR_MODE, AES_CR_MODE_1);

 hcryp.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ONCE;


 /*Secure AES ECB Decryption */
 if (HAL_CRYP_Decrypt(&hcryp, CiphertextAESECB256, 16, DecryptedText, TIMEOUT_VALUE) != HAL_OK)
 {
 /* Processing Error */
 Error_Handler();
 }
 /*Compare decryption result with Plaintext*/
 if(memcmp(DecryptedText, Plaintext, 64) != 0)
 {
 /* Processing Error */
 Error_Handler();
 }


 /*Secure AES ECB Decryption */
 if (HAL_CRYP_Decrypt(&hcryp, CiphertextAESECB256, 16, DecryptedText, TIMEOUT_VALUE) != HAL_OK)
 {
 /* Processing Error */
 Error_Handler();
 }
 /*Compare decryption result with Plaintext*/
 if(memcmp(DecryptedText, Plaintext, 64) != 0)
 {
 /* Processing Error */
 Error_Handler();
 }

 

Best regards

Jocelyn

AKova.3
AKova.3Author
Associate II
November 26, 2024

The code you posted works for me in ECB mode, but not in CBC. In CBC mode I get the correct result only the on the first call to HAL_CRYP_Decrypt, all the following calls produce incorrect result, which is at least the same every time.

Jocelyn RICARD
ST Employee
November 26, 2024

Hello @AKova.3 ,

Sorry, I missed this point.

You can check with following configuration:

 CRYP_ConfigTypeDef Conf={0};
 HAL_CRYP_GetConfig(&hcryp, &Conf);

 /* Change CRYP parameters */
 Conf.KeyMode = CRYP_KEYMODE_NORMAL;
 Conf.KeySelect = CRYP_KEYSEL_NORMAL;
 Conf.Algorithm = CRYP_AES_CBC;
 Conf.pInitVect = AESIV;
 Conf.KeyMode = CRYP_KEYMODE_NORMAL;

Best regards,

Jocelyn

 

AKova.3
AKova.3Author
Associate II
November 27, 2024

With this piece of code in place, the program behaves the same as before.

Jocelyn RICARD
ST Employee
November 27, 2024

Hello @AKova.3 ,

I attach the main.c file I used for testing.

I'm not using CBC to wrap the key. Is this really what you want to do ?

I mean using CBC for key wrapping with an IV. And then using again CBC for decryption with the same IV ?

In the example I provide, I use AES_ECB for wrapping.

Then AES CBC with specific IV to decrypt.

Best regards

Jocelyn

AKova.3
AKova.3Author
Associate II
November 27, 2024

Fair point about key wrapping, but I wasn't really concerned about it at this point. 

I tried running your code. What is there works fine. If I however add another exactly the same call to HAL_CRYP_Decrypt after the first one, it produces different result compared to first one. Correct me if I am wrong but I was working under the assumption that each call to HAL_CRYP_Decrypt would be independant from another for both EBC and CBC modes and therefore I would expect all to them to produce the same result given the same inputs.

Jocelyn RICARD
ST Employee
November 27, 2024

Hi @AKova.3 ,

here you are using AES CBC. This is Cypher Block Chaining. This is exactly the purpose to not being able to decrypt twice the same thing, as the initial vector propagates.

To get same output, you would need to reset the decryption to start with initial vector again.

Another way to check is to encrypt with CBC more than one buffer.

Then use same buffer sequence for decryption.

Best regards

Jocelyn

AKova.3
AKova.3Author
Associate II
November 27, 2024

I understand that there is chaining between blocks of a single message, but is there also chaining between subsequent messages, that is subsequent calls to, for instance HAL_CRYP_Decrypt funtion because the peripheral retains some internal state between HAL function calls?

You mentioned that decryption needs to be reset to get the same output with the same inputs. Should this be done with calls to HAL_CRYP_DeInit, HAL_CRYP_Init and wrapping/unwrapping the key again or is there a more appropriate way? I have tried that and it does work but I can't imagine this is the way it was meant to be done.