2019-10-07 03:17 PM
Hi,
I am new the the development and I have been testing the hardware aes module.
I have tested against a known vector and the results differ from what is expected, I have checked the test vectors using AES provider in .NET and I get the results I expect, so am wondering what is wrong with the code I have.
I am running it on a nucleo with the STM32WB55RGV6 MCU
The code is
#include "main.h"
#define AES_TEXT_SIZE 4
/*TEST VECTORS FROM
*https://github.com/ircmaxell/quality-checker/blob/master/tmp/gh_18/PHP-PasswordLib-master/test/Data/Vectors/aes-cbc.test-vectors
*Set 3 vector 3
**/
CRYP_HandleTypeDef hcryp1;
DMA_HandleTypeDef hdma_aes1_in;
DMA_HandleTypeDef hdma_aes1_out;
uint32_t aAES256key[8] =
{283852128,3195128341,4037964587,2172091781,120337695,3607650619,2735773741,4108260361};
/* Initialization vector */
uint32_t AESIV[4] =
{2521758876,2374032254,2071437159, 2100064454};
uint32_t aPlaintextCBC[AES_TEXT_SIZE] =
{ 1176291376,300178595,432143333,4015131162 };
uint32_t aEncryptedtextCBC256[AES_TEXT_SIZE] =
{1765012025,3485129129,1675767973,1628709636};
/* Used for storing the encrypted text */
uint32_t aEncryptedtext[AES_TEXT_SIZE];
/* Used for storing the decrypted text */
uint32_t aDecryptedtext[AES_TEXT_SIZE];
void SystemClock_Config(void);
static void MX_DMA_Init(void);
void SystemClock_Config(void);
void data_cmp(uint32_t *EncryptedText, uint32_t *RefText, uint8_t Size);
/* Private functions ---------------------------------------------------------*/
#if defined(__GNUC__)
extern void initialise_monitor_handles(void);
#endif
int main(void)
{
/* USER CODE BEGIN 1 */
#if defined(__GNUC__)
initialise_monitor_handles();
#endif
HAL_Init();
SystemClock_Config();
MX_DMA_Init();
hcryp1.Instance = AES1;
hcryp1.Init.DataType = CRYP_DATATYPE_8B;
hcryp1.Init.Algorithm = CRYP_AES_CBC;
hcryp1.Init.KeySize = CRYP_KEYSIZE_256B;
hcryp1.Init.pKey = aAES256key;
hcryp1.Init.pInitVect = AESIV;
if(HAL_CRYP_Init(&hcryp1) != HAL_OK)
{
Error_Handler();
}
if (HAL_CRYP_Encrypt_IT(&hcryp1, aPlaintextCBC, AES_TEXT_SIZE, aEncryptedtext)!= HAL_OK)
{
Error_Handler();
}
/* Wait for processing to be done */
while (HAL_CRYP_GetState(&hcryp1) != HAL_CRYP_STATE_READY);
data_cmp(aEncryptedtext, aEncryptedtextCBC256, AES_TEXT_SIZE);
while (1){}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
RCC_OscInitStruct.PLL.PLLN = 32;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV5;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Configure the SYSCLKSource, HCLK, PCLK1 and PCLK2 clocks dividers
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK4|RCC_CLOCKTYPE_HCLK2
|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.AHBCLK2Divider = RCC_SYSCLK_DIV2;
RCC_ClkInitStruct.AHBCLK4Divider = RCC_SYSCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
{
Error_Handler();
}
}
static void MX_DMA_Init(void)
{
__HAL_RCC_DMAMUX1_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}
void data_cmp(uint32_t *EncryptedText, uint32_t *RefText, uint8_t Size)
{
if(memcmp(EncryptedText, RefText, Size*4) != 0)
{
Error_Handler();
}
else
{
/* Right encryption */
}
}
void Error_Handler(void)
{
printf("\n\r Error Detected...\n ");
while (1)
{
}
}
The result return is
{1057025506,4094683968,291643854,3202963458}
Not
{1765012025,3485129129,1675767973,1628709636}
as expected
Any help would be much appreciated.
2019-10-08 01:05 AM
I'm not sure how did you manage to convert those test vectors to uint32_t arrays and why would you do that? Those are binary data represented as hexadecimal values, use uint8_t arrays to represent single bytes. Yeah, you can convert them to uint32_t arrays (and have also endianness and other issues), but why?
So for example, the 603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 aes-256 key should become:
uint8_t aes_key[] = {0x60, 0x3d, 0xeb, ...etc};
2019-10-08 01:18 AM
Thank you for your reply @After Forever .
HAL_CRYP_Encrypt_IT requires the key to be uint32t*.
So, for testing, I took the hexadecimal string in a .net console application for test, converted it to bytes (as .net requires the key to be a byte array), executed the test to get the results.
I then used the byte array converted to uint32_t array on the STM32 to replicate the test and I get different results.
So if I have missed something here, would your uint8_t array converted it to uint32_t array give you a different result than that I gave in my example code?
Thanks again
2019-10-08 03:34 AM
Uh, you are right, I haven't used stm32 hardware crypto directly (only through X-CUBE-CRYPTOLIB), and it seems it prefers to work with 32-bit values. Yeah, that's logical, at the low level the values must be copied to/from hardware registers which are 32-bit..
So I would recheck the correctness of your test vectors conversion. There might be endianness issues.
2019-10-08 04:47 AM
Please have a look at CBC256 encryption examples available in ~STM32Cube_FW_WB_V1.3.0\Projects\P-NUCLEO-WB55.Nucleo\Examples\CRYP\CRYP_AESModes
Take care about the endianness and the (8B, 32B) data type.
2019-10-08 03:10 PM
@Remi QUINTIN
Thank you, I was using the examples but I was having trouble replicating the results between the MCU and a .NET application.
I have managed to match the results now and I thought I would share for comments just in case it is a false positive.
So when converting the key and iv from the uint8_t array from .net application to the mcu version, I was converting the array to uint32_t (little endian) to pass to the function for encryption. this fails.
What I have found is that if the key and the iv are converting from uint8_t to uint32_t (big endian) whilst keeping the data little endian the encryption succeeds.
I am not sure this seems right but it works.
Thank you all for the time to view and provide feedback so far, it is much appreciated