MCUXpresso_MIMXRT1052xxxxB/boards/evkbimxrt1050/azure_rtos_examples/azure_iot_embedded_sdk_adu/secure_storage.c
Yilin Sun 75f32185d2
Updated to v2.14.0
Signed-off-by: Yilin Sun <imi415@imi.moe>
2023-11-30 20:55:00 +08:00

333 lines
9.0 KiB
C

/*
* Copyright 2022 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_common.h"
#if defined(FSL_FEATURE_SOC_CAAM_COUNT) && (FSL_FEATURE_SOC_CAAM_COUNT > 0)
#include "fsl_caam.h"
#elif defined(FSL_FEATURE_SOC_DCP_COUNT) && (FSL_FEATURE_SOC_DCP_COUNT > 0)
#include "fsl_dcp.h"
#else
#error "NOTE: The platform does not support DCP or CAAM. Will store plaintext."
#endif
#include "fsl_debug_console.h"
#include "mflash_file.h"
#define MAX_FILE_SIZE (400U)
#define CIPHER_KEY_SIZE_BITS (128U)
#define CIPHER_KEY_SIZE_BYTES (CIPHER_KEY_SIZE_BITS / 8)
AT_NONCACHEABLE_SECTION_ALIGN(static uint8_t in_buffer[CIPHER_KEY_SIZE_BYTES], 64);
AT_NONCACHEABLE_SECTION_ALIGN(static uint8_t out_buffer[CIPHER_KEY_SIZE_BYTES], 64);
#if defined(FSL_FEATURE_SOC_CAAM_COUNT) && (FSL_FEATURE_SOC_CAAM_COUNT > 0)
/*! @brief CAAM job ring interface 0 in system memory. */
AT_NONCACHEABLE_SECTION(static caam_job_ring_interface_t s_jrif0);
/*! @brief 16 bytes key for CBC method: "ultrapassword123". */
static const uint8_t s_CbcKey128[] = {0x75, 0x6c, 0x74, 0x72, 0x61, 0x70, 0x61, 0x73,
0x73, 0x77, 0x6f, 0x72, 0x64, 0x31, 0x32, 0x33};
/*! @brief Initialization vector for CBC method: 16 bytes: "mysecretpassword". */
static const uint8_t s_CbcIv[CAAM_AES_BLOCK_SIZE] = {0x6d, 0x79, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74,
0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64};
static caam_handle_t caamHandle = {
.jobRing = kCAAM_JobRing0
};
/*!
* @brief Encrypts and decrypts in AES CBC mode.
*/
static status_t do_crypto(uint8_t *data, uint8_t *output, uint32_t *data_len, bool encrypt)
{
uint8_t iv_temp[CAAM_AES_BLOCK_SIZE];
uint32_t size = 0;
status_t status;
memcpy(iv_temp, s_CbcIv, CAAM_AES_BLOCK_SIZE);
while(size < *data_len) {
memset(in_buffer, 0, CIPHER_KEY_SIZE_BYTES);
memcpy(in_buffer, data, (*data_len - size) >= CIPHER_KEY_SIZE_BYTES ?
CIPHER_KEY_SIZE_BYTES : (*data_len - size));
if (encrypt) {
status = CAAM_AES_EncryptCbc(CAAM, &caamHandle, in_buffer, out_buffer, CIPHER_KEY_SIZE_BYTES,
iv_temp, s_CbcKey128, sizeof(s_CbcKey128));
memcpy(iv_temp, out_buffer, CIPHER_KEY_SIZE_BYTES);
} else {
status = CAAM_AES_DecryptCbc(CAAM, &caamHandle, in_buffer, out_buffer, CIPHER_KEY_SIZE_BYTES,
iv_temp, s_CbcKey128, sizeof(s_CbcKey128));
memcpy(iv_temp, in_buffer, CIPHER_KEY_SIZE_BYTES);
}
if (status != kStatus_Success) {
PRINTF("do_crypto error!\r\n");
return status;
}
memcpy(output, out_buffer, CIPHER_KEY_SIZE_BYTES);
data += CIPHER_KEY_SIZE_BYTES;
output += CIPHER_KEY_SIZE_BYTES;
size += CIPHER_KEY_SIZE_BYTES;
}
*data_len = size;
return status;
}
static status_t init_sec_engine(void)
{
caam_config_t caamConfig;
/* Get default configuration. */
CAAM_GetDefaultConfig(&caamConfig);
/* setup memory for job ring interfaces. Can be in system memory or CAAM's secure memory. */
caamConfig.jobRingInterface[0] = &s_jrif0;
/* Init CAAM driver, including CAAM's internal RNG */
return CAAM_Init(CAAM, &caamConfig);
}
uint32_t get_seed(void)
{
uint32_t random_val = 0;
CAAM_RNG_GetRandomData(CAAM, &caamHandle, kCAAM_RngStateHandle0,
(uint8_t *)&random_val, 4, kCAAM_RngDataAny, NULL);
return random_val;
}
#elif defined(FSL_FEATURE_SOC_DCP_COUNT) && (FSL_FEATURE_SOC_DCP_COUNT > 0)
typedef enum _dcp_otp_key_select
{
kDCP_OTPMKKeyLow = 1U, /* Use [127:0] from snvs key as dcp key */
kDCP_OTPMKKeyHigh = 2U, /* Use [255:128] from snvs key as dcp key */
kDCP_OCOTPKeyLow = 3U, /* Use [127:0] from ocotp key as dcp key */
kDCP_OCOTPKeyHigh = 4U /* Use [255:128] from ocotp key as dcp key */
} dcp_otp_key_select;
static status_t DCP_OTPKeySelect(dcp_otp_key_select keySelect)
{
status_t retval = kStatus_Success;
if (keySelect == kDCP_OTPMKKeyLow)
{
IOMUXC_GPR->GPR3 &= ~(1 << IOMUXC_GPR_GPR3_DCP_KEY_SEL_SHIFT);
IOMUXC_GPR->GPR10 &= ~(1 << IOMUXC_GPR_GPR10_DCPKEY_OCOTP_OR_KEYMUX_SHIFT);
}
else if (keySelect == kDCP_OTPMKKeyHigh)
{
IOMUXC_GPR->GPR3 |= (1 << IOMUXC_GPR_GPR3_DCP_KEY_SEL_SHIFT);
IOMUXC_GPR->GPR10 &= ~(1 << IOMUXC_GPR_GPR10_DCPKEY_OCOTP_OR_KEYMUX_SHIFT);
}
else if (keySelect == kDCP_OCOTPKeyLow)
{
IOMUXC_GPR->GPR3 &= ~(1 << IOMUXC_GPR_GPR3_DCP_KEY_SEL_SHIFT);
IOMUXC_GPR->GPR10 |= (1 << IOMUXC_GPR_GPR10_DCPKEY_OCOTP_OR_KEYMUX_SHIFT);
}
else if (keySelect == kDCP_OCOTPKeyHigh)
{
IOMUXC_GPR->GPR3 |= (1 << IOMUXC_GPR_GPR3_DCP_KEY_SEL_SHIFT);
IOMUXC_GPR->GPR10 |= (1 << IOMUXC_GPR_GPR10_DCPKEY_OCOTP_OR_KEYMUX_SHIFT);
}
else
{
retval = kStatus_InvalidArgument;
}
return retval;
}
/* When doing encryption, the size of output will be a mutiple of CIPHER_KEY_SIZE_BYTES. */
static status_t do_crypto(uint8_t *data, uint8_t *output, uint32_t *data_len, bool encrypt)
{
status_t status;
dcp_handle_t m_handle;
uint8_t *start;
uint8_t *end;
uint8_t *dst;
size_t copy_size;
m_handle.channel = kDCP_Channel0;
m_handle.swapConfig = kDCP_NoSwap;
m_handle.keySlot = kDCP_OtpKey;
status = DCP_AES_SetKey(DCP, &m_handle, NULL, 0);
if (status != kStatus_Success)
{
return status;
}
start = data;
end = data + *data_len;
dst = output;
*data_len = 0;
while (start < end)
{
copy_size = MIN(CIPHER_KEY_SIZE_BYTES, end - start);
memset(in_buffer, 0, sizeof(in_buffer));
memcpy(in_buffer, start, copy_size);
if (encrypt)
{
status = DCP_AES_EncryptEcb(DCP, &m_handle,
in_buffer, out_buffer,
CIPHER_KEY_SIZE_BYTES);
}
else
{
status = DCP_AES_DecryptEcb(DCP, &m_handle,
in_buffer, out_buffer,
CIPHER_KEY_SIZE_BYTES);
}
if (status != kStatus_Success)
{
return status;
}
memcpy(dst, out_buffer, sizeof(out_buffer));
start += copy_size;
dst += copy_size;
*data_len += CIPHER_KEY_SIZE_BYTES;
}
return kStatus_Success;
}
static status_t init_sec_engine(void)
{
dcp_config_t dcpConfig;
status_t status;
DCP_GetDefaultConfig(&dcpConfig);
/* Set OTP key type in IOMUX registers before initializing DCP. */
/* Software reset of DCP must be issued after changing the OTP key type. */
status = DCP_OTPKeySelect(kDCP_OTPMKKeyLow);
if (status != kStatus_Success)
{
return status;
}
/* Reset and initialize DCP */
DCP_Init(DCP, &dcpConfig);
return kStatus_Success;
}
#else
/* When there is no supported engine for acceleration, just use plaintext. */
static status_t do_crypto(uint8_t *data, uint8_t *output, uint32_t *data_len, bool encrypt)
{
memcpy(output, data, *data_len);
return kStatus_Success;
}
static status_t init_sec_engine(void)
{
return kStatus_Success;
}
#endif /* FSL_FEATURE_SOC_CAAM_COUNT */
status_t secure_storage_init(char *filename)
{
status_t status;
mflash_file_t file_table[] =
{
{
.path = filename,
.max_size = 200
},
{0}
};
status = init_sec_engine();
if (status != kStatus_Success)
{
return status;
}
status = mflash_init(file_table, 1);
if (status != kStatus_Success)
{
PRINTF("[!] ERROR in mflash_init!");
return status;
}
return kStatus_Success;
}
status_t secure_save_file(char *filename, uint8_t *data, uint32_t data_len)
{
status_t status;
uint8_t output[MAX_FILE_SIZE];
uint32_t size;
if ((filename == NULL) || (strlen(filename) > 63) ||
(data == NULL) || (data_len <= 0) || (data_len > MAX_FILE_SIZE))
{
return kStatus_InvalidArgument;
}
size = data_len;
status = do_crypto(data, output, &size, true);
if (kStatus_Success != status)
{
return status;
}
status = mflash_file_save(filename, output, size);
if (kStatus_Success != status)
{
return status;
}
return kStatus_Success;
}
status_t secure_read_file(char *filename, uint8_t *data, uint32_t *data_len)
{
status_t status;
uint8_t *ciphertext;
if ((filename == NULL) || (strlen(filename) > 63) ||
(data == NULL))
{
return kStatus_InvalidArgument;
}
status = mflash_file_mmap(filename, &ciphertext, data_len);
if (kStatus_Success != status)
{
return status;
}
status = do_crypto(ciphertext, data, data_len, false);
if (kStatus_Success != status)
{
return status;
}
return kStatus_Success;
}