#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#ifdef WOLFSSL_IMXRT_DCP
#include <wolfssl/wolfcrypt/aes.h>
#include <wolfssl/wolfcrypt/sha.h>
#include <wolfssl/wolfcrypt/sha256.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
#error "DCACHE not supported by this driver. Please undefine DCP_USE_DCACHE."
#endif
#ifndef DCP_USE_OTP_KEY
#define DCP_USE_OTP_KEY 0
#endif
#include "fsl_dcp.h"
#ifndef SINGLE_THREADED
#define dcp_lock_init() wolfSSL_CryptHwMutexInit()
#define dcp_lock() wolfSSL_CryptHwMutexLock()
#define dcp_unlock() wolfSSL_CryptHwMutexUnLock()
#else
#define dcp_lock_init() WC_DO_NOTHING
#define dcp_lock() WC_DO_NOTHING
#define dcp_unlock() WC_DO_NOTHING
#endif
#if DCP_USE_OTP_KEY
typedef enum _dcp_otp_key_select
{
kDCP_OTPMKKeyLow = 1U,
kDCP_OTPMKKeyHigh = 2U,
kDCP_OCOTPKeyLow = 3U,
kDCP_OCOTPKeyHigh = 4U
} dcp_otp_key_select;
#endif
#if DCP_USE_OTP_KEY
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;
}
#endif
static const int dcp_channels[4] = {
kDCP_Channel0,
kDCP_Channel1,
kDCP_Channel2,
kDCP_Channel3
};
#ifndef SINGLE_THREADED
static int dcp_status[4] = {0, 0, 0, 0};
#endif
static int dcp_get_channel(void)
{
#ifdef SINGLE_THREADED
return dcp_channels[0];
#else
int i;
int ret = 0;
dcp_lock();
for (i = 0; i < 4; i++) {
if (dcp_status[i] == 0) {
dcp_status[i]++;
ret = dcp_channels[i];
break;
}
}
dcp_unlock();
return ret;
#endif
}
static int dcp_key_slot(int ch)
{
int ret = -1;
#if DCP_USE_OTP_KEY
return kDCP_OtpKey;
#endif
#ifndef SINGLE_THREADED
int i;
dcp_lock();
for (i = 0; i < 4; i++) {
if (ch == dcp_channels[i]) {
ret = i;
break;
}
}
dcp_unlock();
#else
ret = 0;
#endif
return ret;
}
int wc_dcp_init(void)
{
dcp_config_t dcpConfig;
dcp_lock_init();
dcp_lock();
DCP_GetDefaultConfig(&dcpConfig);
DCP_Init(DCP, &dcpConfig);
#if DCP_USE_OTP_KEY
DCP_OTPKeySelect(kDCP_OTPMKKeyLow);
#endif
dcp_unlock();
return 0;
}
static void dcp_free(int ch)
{
#ifndef SINGLE_THREADED
int i;
dcp_lock();
for (i = 0; i < 4; i++) {
if (ch == dcp_channels[i]) {
dcp_status[i] = 0;
break;
}
}
dcp_unlock();
#endif
}
#ifndef NO_AES
int DCPAesInit(Aes *aes)
{
int ch;
if (!aes)
return BAD_FUNC_ARG;
ch = dcp_get_channel();
if (ch == 0)
return WC_PENDING_E;
XMEMSET(&aes->handle, 0, sizeof(aes->handle));
aes->handle.channel = (dcp_channel_t)ch;
aes->handle.keySlot = (dcp_key_slot_t)dcp_key_slot(aes->handle.channel);
aes->handle.swapConfig = kDCP_NoSwap;
return 0;
}
void DCPAesFree(Aes *aes)
{
dcp_free(aes->handle.channel);
aes->handle.channel = 0;
}
static unsigned char aes_key_aligned[16] __attribute__((aligned(0x10)));
int DCPAesSetKey(Aes* aes, const byte* key, word32 len, const byte* iv,
int dir)
{
#if DCP_USE_OTP_KEY
#warning Please update cipherAes128 variables to match expected AES ciphertext for your OTP key.
#endif
status_t status;
if (!aes || !key)
return BAD_FUNC_ARG;
if (len != 16)
return BAD_FUNC_ARG;
if (aes->handle.channel == 0) {
if (DCPAesInit(aes) != 0)
return WC_HW_E;
}
dcp_lock();
memcpy(aes_key_aligned, key, 16);
status = DCP_AES_SetKey(DCP, &aes->handle, aes_key_aligned, 16);
if (status != kStatus_Success)
status = WC_HW_E;
else {
if (iv)
XMEMCPY(aes->reg, iv, 16);
else
XMEMSET(aes->reg, 0, 16);
}
dcp_unlock();
return status;
}
int DCPAesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
int ret;
if (sz % 16)
return BAD_FUNC_ARG;
dcp_lock();
ret = DCP_AES_EncryptCbc(DCP, &aes->handle, in, out, sz, (const byte *)aes->reg);
if (ret)
ret = WC_HW_E;
else
XMEMCPY(aes->reg, out, WC_AES_BLOCK_SIZE);
dcp_unlock();
return ret;
}
int DCPAesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
int ret;
if (sz % 16)
return BAD_FUNC_ARG;
dcp_lock();
ret = DCP_AES_DecryptCbc(DCP, &aes->handle, in, out, sz, (const byte *)aes->reg);
if (ret)
ret = WC_HW_E;
else
XMEMCPY(aes->reg, in, WC_AES_BLOCK_SIZE);
dcp_unlock();
return ret;
}
int DCPAesEcbEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
int ret;
if (sz % 16)
return BAD_FUNC_ARG;
dcp_lock();
ret = DCP_AES_EncryptEcb(DCP, &aes->handle, in, out, sz);
if (ret)
ret = WC_HW_E;
dcp_unlock();
return ret;
}
int DCPAesEcbDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
int ret;
if (sz % 16)
return BAD_FUNC_ARG;
dcp_lock();
ret = DCP_AES_DecryptEcb(DCP, &aes->handle, in, out, sz);
if (ret)
ret = WC_HW_E;
dcp_unlock();
return ret;
}
#endif
#ifndef NO_SHA256
int wc_InitSha256_ex(wc_Sha256* sha256, void* heap, int devId)
{
int ret;
int ch;
int keyslot;
if (sha256 == NULL)
return BAD_FUNC_ARG;
ch = dcp_get_channel();
if (ch == 0)
return WC_PENDING_E;
keyslot = dcp_key_slot(ch);
dcp_lock();
(void)devId;
XMEMSET(sha256, 0, sizeof(wc_Sha256));
sha256->handle.channel = (dcp_channel_t)ch;
sha256->handle.keySlot = (dcp_key_slot_t)keyslot;
sha256->handle.swapConfig = kDCP_NoSwap;
ret = DCP_HASH_Init(DCP, &sha256->handle, &sha256->ctx, kDCP_Sha256);
if (ret != kStatus_Success)
ret = WC_HW_E;
dcp_unlock();
return ret;
}
void DCPSha256Free(wc_Sha256* sha256)
{
if (sha256)
dcp_free(sha256->handle.channel);
}
int wc_Sha256Update(wc_Sha256* sha256, const byte* data, word32 len)
{
int ret;
if (sha256 == NULL || (data == NULL && len != 0)) {
return BAD_FUNC_ARG;
}
dcp_lock();
ret = DCP_HASH_Update(DCP, &sha256->ctx, data, len);
if (ret != kStatus_Success)
ret = WC_HW_E;
dcp_unlock();
return ret;
}
int wc_Sha256GetHash(wc_Sha256* sha256, byte* hash)
{
int ret;
size_t outlen = WC_SHA256_DIGEST_SIZE;
dcp_hash_ctx_t saved_ctx;
if (sha256 == NULL || hash == NULL)
return BAD_FUNC_ARG;
dcp_lock();
XMEMCPY(&saved_ctx, &sha256->ctx, sizeof(dcp_hash_ctx_t));
XMEMSET(hash, 0, WC_SHA256_DIGEST_SIZE);
ret = DCP_HASH_Finish(DCP, &sha256->ctx, hash, &outlen);
if ((ret != kStatus_Success) || (outlen != SHA256_DIGEST_SIZE))
ret = WC_HW_E;
else
XMEMCPY(&sha256->ctx, &saved_ctx, sizeof(dcp_hash_ctx_t));
dcp_unlock();
return ret;
}
int wc_Sha256Final(wc_Sha256* sha256, byte* hash)
{
int ret;
size_t outlen = WC_SHA256_DIGEST_SIZE;
dcp_lock();
ret = DCP_HASH_Finish(DCP, &sha256->ctx, hash, &outlen);
if ((ret != kStatus_Success) || (outlen != SHA256_DIGEST_SIZE))
ret = WC_HW_E;
else {
ret = DCP_HASH_Init(DCP, &sha256->handle, &sha256->ctx, kDCP_Sha256);
if (ret != kStatus_Success)
ret = WC_HW_E;
}
dcp_unlock();
return ret;
}
#ifdef WOLFSSL_HASH_FLAGS
int wc_Sha256SetFlags(wc_Sha256* sha256, word32 flags)
{
if (sha256) {
sha256->flags = flags;
}
return 0;
}
int wc_Sha256GetFlags(wc_Sha256* sha256, word32* flags)
{
if (sha256 && flags) {
*flags = sha256->flags;
}
return 0;
}
#endif
int wc_Sha256Copy(wc_Sha256* src, wc_Sha256* dst)
{
if (src == NULL || dst == NULL)
return BAD_FUNC_ARG;
dcp_lock();
XMEMCPY(&dst->ctx, &src->ctx, sizeof(dcp_hash_ctx_t));
dcp_unlock();
return 0;
}
#endif
#ifndef NO_SHA
int wc_InitSha_ex(wc_Sha* sha, void* heap, int devId)
{
int ret;
int ch;
int keyslot;
if (sha == NULL)
return BAD_FUNC_ARG;
ch = dcp_get_channel();
if (ch == 0)
return WC_PENDING_E;
keyslot = dcp_key_slot(ch);
dcp_lock();
(void)devId;
XMEMSET(sha, 0, sizeof(wc_Sha));
sha->handle.channel = (dcp_channel_t)ch;
sha->handle.keySlot = (dcp_key_slot_t)keyslot;
sha->handle.swapConfig = kDCP_NoSwap;
ret = DCP_HASH_Init(DCP, &sha->handle, &sha->ctx, kDCP_Sha1);
if (ret != kStatus_Success)
ret = WC_HW_E;
dcp_unlock();
return ret;
}
void DCPShaFree(wc_Sha* sha)
{
if (sha)
dcp_free(sha->handle.channel);
}
int wc_ShaUpdate(wc_Sha* sha, const byte* data, word32 len)
{
int ret;
if (sha == NULL || (data == NULL && len != 0)) {
return BAD_FUNC_ARG;
}
dcp_lock();
ret = DCP_HASH_Update(DCP, &sha->ctx, data, len);
if (ret != kStatus_Success)
ret = WC_HW_E;
dcp_unlock();
return ret;
}
int wc_ShaGetHash(wc_Sha* sha, byte* hash)
{
int ret;
size_t outlen = WC_SHA_DIGEST_SIZE;
dcp_hash_ctx_t saved_ctx;
if (sha == NULL || hash == NULL)
return BAD_FUNC_ARG;
dcp_lock();
XMEMCPY(&saved_ctx, &sha->ctx, sizeof(dcp_hash_ctx_t));
XMEMSET(hash, 0, WC_SHA_DIGEST_SIZE);
ret = DCP_HASH_Finish(DCP, &sha->ctx, hash, &outlen);
if ((ret != kStatus_Success) || (outlen != WC_SHA_DIGEST_SIZE))
ret = WC_HW_E;
else
XMEMCPY(&sha->ctx, &saved_ctx, sizeof(dcp_hash_ctx_t));
dcp_unlock();
return ret;
}
int wc_ShaFinal(wc_Sha* sha, byte* hash)
{
int ret;
size_t outlen = WC_SHA_DIGEST_SIZE;
dcp_lock();
ret = DCP_HASH_Finish(DCP, &sha->ctx, hash, &outlen);
if ((ret != kStatus_Success) || (outlen != SHA_DIGEST_SIZE)) {
ret = WC_HW_E;
} else {
ret = DCP_HASH_Init(DCP, &sha->handle, &sha->ctx, kDCP_Sha1);
if (ret != kStatus_Success)
ret = WC_HW_E;
}
dcp_unlock();
return ret;
}
#ifdef WOLFSSL_HASH_FLAGS
int wc_ShaSetFlags(wc_Sha* sha, word32 flags)
{
if (sha) {
sha->flags = flags;
}
return 0;
}
int wc_ShaGetFlags(wc_Sha* sha, word32* flags)
{
if (sha && flags) {
*flags = sha->flags;
}
return 0;
}
#endif
int wc_ShaCopy(wc_Sha* src, wc_Sha* dst)
{
if (src == NULL || dst == NULL)
return BAD_FUNC_ARG;
dcp_lock();
XMEMCPY(&dst->ctx, &src->ctx, sizeof(dcp_hash_ctx_t));
dcp_unlock();
return 0;
}
#endif
#endif