rt-thread/bsp/hc32/libraries/hc32_drivers/drv_crypto.c

530 lines
13 KiB
C
Raw Normal View History

2024-01-09 21:56:37 +08:00
/*
* Copyright (C) 2022-2024, Xiaohua Semiconductor Co., Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-02-10 CDT first version
*/
#include "board.h"
#if defined(BSP_USING_HWCRYPTO)
// #define DRV_DEBUG
#define LOG_TAG "drv_crypto"
#include <drv_log.h>
struct hc32_hwcrypto_device
{
struct rt_hwcrypto_device dev;
struct rt_mutex mutex;
};
#if defined(BSP_USING_CRC)
#define DEFAULT_CRC16_CCITT_POLY (0x1021) /*!< X^16 + X^12 + X^5 + 1 */
#define DEFAULT_CRC32_POLY (0x04C11DB7) /*!< X^32 + X^26 + X^23 + X^22 + X^16 + X^12 + X^11 + X^10 +X^8 + X^7 + X^5 + X^4 + X^2+ X + 1 */
static rt_uint32_t _crc_update(struct hwcrypto_crc *ctx, const rt_uint8_t *in, rt_size_t length)
{
rt_uint32_t result = 0;
stc_crc_init_t stcCrcInit;
static struct hwcrypto_crc_cfg crc_cfgbk = {0};
struct hc32_hwcrypto_device *hc32_hw_dev = (struct hc32_hwcrypto_device *)ctx->parent.device->user_data;
rt_mutex_take(&hc32_hw_dev->mutex, RT_WAITING_FOREVER);
if (ctx->crc_cfg.poly != DEFAULT_CRC16_CCITT_POLY && ctx->crc_cfg.poly != DEFAULT_CRC32_POLY)
{
LOG_E("CRC polynomial only support 0x1021/0x04C11DB7U.");
goto _exit;
}
/* if crc_cfg change we need init crc again */
if (rt_memcmp(&crc_cfgbk, &ctx->crc_cfg, sizeof(struct hwcrypto_crc_cfg)))
{
#if defined(HC32F460)
switch (ctx->crc_cfg.flags)
{
case 0:
stcCrcInit.u32RefIn = CRC_REFIN_DISABLE;
stcCrcInit.u32RefOut = CRC_REFOUT_DISABLE;
break;
case CRC_FLAG_REFIN:
stcCrcInit.u32RefIn = CRC_REFIN_ENABLE;
stcCrcInit.u32RefOut = CRC_REFOUT_DISABLE;
break;
case CRC_FLAG_REFOUT:
stcCrcInit.u32RefIn = CRC_REFIN_DISABLE;
stcCrcInit.u32RefOut = CRC_REFOUT_ENABLE;
break;
case CRC_FLAG_REFIN | CRC_FLAG_REFOUT:
stcCrcInit.u32RefIn = CRC_REFIN_ENABLE;
stcCrcInit.u32RefOut = CRC_REFOUT_ENABLE;
break;
default :
LOG_E("crc flag parameter error.");
goto _exit;
}
if (ctx->crc_cfg.xorout)
{
stcCrcInit.u32XorOut = CRC_XOROUT_ENABLE;
}
else
{
stcCrcInit.u32XorOut = CRC_XOROUT_DISABLE;
}
#endif
switch (ctx->crc_cfg.width)
{
case 16U:
stcCrcInit.u32Protocol = CRC_CRC16;
break;
case 32U:
stcCrcInit.u32Protocol = CRC_CRC32;
break;
default :
LOG_E("crc width only support 16/32.");
goto _exit;
}
stcCrcInit.u32InitValue = ctx->crc_cfg.last_val;
if (CRC_Init(&stcCrcInit) != LL_OK)
{
LOG_E("crc init error.");
goto _exit;
}
LOG_D("CRC_Init.");
rt_memcpy(&crc_cfgbk, &ctx->crc_cfg, sizeof(struct hwcrypto_crc_cfg));
}
if (16U == ctx->crc_cfg.width)
{
result = CRC_CRC16_Calculate(ctx->crc_cfg.last_val, CRC_DATA_WIDTH_8BIT, in, length);
}
else /* CRC32 */
{
result = CRC_CRC32_Calculate(ctx->crc_cfg.last_val, CRC_DATA_WIDTH_8BIT, in, length);
}
_exit:
rt_mutex_release(&hc32_hw_dev->mutex);
return result;
}
static const struct hwcrypto_crc_ops crc_ops =
{
.update = _crc_update,
};
#endif /* BSP_USING_CRC */
#if defined(BSP_USING_RNG)
static rt_uint32_t _rng_rand(struct hwcrypto_rng *ctx)
{
rt_uint32_t gen_random = 0;
if (TRNG_GenerateRandom(&gen_random, 1U) != LL_OK)
{
return 0;
}
return gen_random;
}
static const struct hwcrypto_rng_ops rng_ops =
{
.update = _rng_rand,
};
#endif /* BSP_USING_RNG */
#if defined(BSP_USING_HASH)
#define HASH_SHA256_MSG_DIGEST_SIZE (32U)
static const rt_uint8_t *hash_in = RT_NULL;
static rt_size_t hash_length = 0;
static rt_err_t _hash_update(struct hwcrypto_hash *ctx, const rt_uint8_t *in, rt_size_t length)
{
rt_uint32_t result = RT_EOK;
struct hc32_hwcrypto_device *hc32_hw_dev = (struct hc32_hwcrypto_device *)ctx->parent.device->user_data;
rt_mutex_take(&hc32_hw_dev->mutex, RT_WAITING_FOREVER);
/* Start HASH computation transfer */
switch (ctx->parent.type)
{
case HWCRYPTO_TYPE_SHA256:
hash_in = in;
hash_length = length;
break;
default :
LOG_E("not support hash type: %x", ctx->parent.type);
result = -RT_ERROR;
break;
}
rt_mutex_release(&hc32_hw_dev->mutex);
return result;
}
static rt_err_t _hash_finish(struct hwcrypto_hash *ctx, rt_uint8_t *out, rt_size_t length)
{
rt_uint32_t result = RT_EOK;
struct hc32_hwcrypto_device *hc32_hw_dev = (struct hc32_hwcrypto_device *)ctx->parent.device->user_data;
rt_mutex_take(&hc32_hw_dev->mutex, RT_WAITING_FOREVER);
if (hash_in == RT_NULL || hash_length == 0)
{
LOG_E("no data input.");
result = -RT_ERROR;
goto _exit;
}
/* Get the hash Subtype */
switch (ctx->parent.type)
{
case HWCRYPTO_TYPE_SHA256:
/* SHA256 = 32*8 Bits */
if (length == HASH_SHA256_MSG_DIGEST_SIZE)
{
result = HASH_Calculate(hash_in, hash_length, out);
}
else
{
LOG_E("The out size must be 32 bytes");
}
break;
default :
LOG_E("not support hash type: %x", ctx->parent.type);
result = -RT_ERROR;
break;
}
_exit:
rt_mutex_release(&hc32_hw_dev->mutex);
return result;
}
static const struct hwcrypto_hash_ops hash_ops =
{
.update = _hash_update,
.finish = _hash_finish
};
#endif /* BSP_USING_HASH */
#if defined(BSP_USING_AES)
static rt_err_t _cryp_crypt(struct hwcrypto_symmetric *ctx, struct hwcrypto_symmetric_info *info)
{
rt_uint32_t result = RT_EOK;
struct hc32_hwcrypto_device *hc32_hw_dev = (struct hc32_hwcrypto_device *)ctx->parent.device->user_data;
rt_mutex_take(&hc32_hw_dev->mutex, RT_WAITING_FOREVER);
switch (ctx->parent.type)
{
case HWCRYPTO_TYPE_AES_ECB:
LOG_D("AES type is ECB.");
break;
case HWCRYPTO_TYPE_AES_CBC:
case HWCRYPTO_TYPE_AES_CTR:
case HWCRYPTO_TYPE_DES_ECB:
case HWCRYPTO_TYPE_DES_CBC:
default :
LOG_E("not support cryp type: %x", ctx->parent.type);
break;
}
#if defined (HC32F460)
if (ctx->key_bitlen != (AES_KEY_SIZE_16BYTE * 8U))
{
LOG_E("not support key bitlen: %d", ctx->key_bitlen);
result = -RT_ERROR;
goto _exit;
}
#elif defined (HC32F4A0)
if (ctx->key_bitlen != (AES_KEY_SIZE_16BYTE * 8U) && ctx->key_bitlen != (AES_KEY_SIZE_24BYTE * 8U) && \
ctx->key_bitlen != (AES_KEY_SIZE_32BYTE * 8U))
{
LOG_E("not support key bitlen: %d", ctx->key_bitlen);
result = -RT_ERROR;
goto _exit;
}
#endif
if ((info->length % 16U) != 0U)
{
LOG_E("aes supports only an integer multiple of 16 in length");
result = -RT_ERROR;
goto _exit;
}
if (info->mode == HWCRYPTO_MODE_ENCRYPT)
{
/* AES encryption. */
result = AES_Encrypt(info->in, info->length, ctx->key, (ctx->key_bitlen / 8U), info->out);
}
else if (info->mode == HWCRYPTO_MODE_DECRYPT)
{
/* AES decryption */
result = AES_Decrypt(info->in, info->length, ctx->key, (ctx->key_bitlen / 8U), info->out);
}
else
{
rt_kprintf("error cryp mode : %02x!\n", info->mode);
result = -RT_ERROR;
goto _exit;
}
_exit:
rt_mutex_release(&hc32_hw_dev->mutex);
return result;
}
static const struct hwcrypto_symmetric_ops cryp_ops =
{
.crypt = _cryp_crypt
};
#endif
static rt_err_t _crypto_create(struct rt_hwcrypto_ctx *ctx)
{
rt_err_t res = RT_EOK;
switch (ctx->type & HWCRYPTO_MAIN_TYPE_MASK)
{
#if defined(BSP_USING_RNG)
case HWCRYPTO_TYPE_RNG:
{
/* Enable TRNG. */
FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_TRNG, ENABLE);
/* TRNG initialization configuration. */
TRNG_Init(TRNG_SHIFT_CNT64, TRNG_RELOAD_INIT_VAL_ENABLE);
((struct hwcrypto_rng *)ctx)->ops = &rng_ops;
break;
}
#endif /* BSP_USING_RNG */
#if defined(BSP_USING_CRC)
case HWCRYPTO_TYPE_CRC:
{
/* Enable CRC module clock. */
FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_CRC, ENABLE);
/* do not Initialize CRC because crc_update will do it */
((struct hwcrypto_crc *)ctx)->ops = &crc_ops;
break;
}
#endif /* BSP_USING_CRC */
#if defined(BSP_USING_HASH)
case HWCRYPTO_TYPE_MD5:
case HWCRYPTO_TYPE_SHA1:
case HWCRYPTO_TYPE_SHA2:
{
if (ctx->type == HWCRYPTO_TYPE_SHA256)
{
/* Enable HASH. */
FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_HASH, ENABLE);
((struct hwcrypto_hash *)ctx)->ops = &hash_ops;
}
else
{
LOG_E("not support hash type.");
res = -RT_ERROR;
}
break;
}
#endif /* BSP_USING_HASH */
#if defined(BSP_USING_AES)
case HWCRYPTO_TYPE_AES:
case HWCRYPTO_TYPE_DES:
case HWCRYPTO_TYPE_3DES:
case HWCRYPTO_TYPE_RC4:
case HWCRYPTO_TYPE_GCM:
{
/* Enable AES peripheral clock. */
FCG_Fcg0PeriphClockCmd(PWC_FCG0_AES, ENABLE);
((struct hwcrypto_symmetric *)ctx)->ops = &cryp_ops;
break;
}
#endif /* BSP_USING_AES */
default:
res = -RT_ERROR;
break;
}
return res;
}
static void _crypto_destroy(struct rt_hwcrypto_ctx *ctx)
{
switch (ctx->type & HWCRYPTO_MAIN_TYPE_MASK)
{
#if defined(BSP_USING_RNG)
case HWCRYPTO_TYPE_RNG:
TRNG_DeInit();
FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_TRNG, DISABLE);
break;
#endif /* BSP_USING_RNG */
#if defined(BSP_USING_CRC)
case HWCRYPTO_TYPE_CRC:
CRC_DeInit();
FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_CRC, DISABLE);
break;
#endif /* BSP_USING_CRC */
#if defined(BSP_USING_HASH)
case HWCRYPTO_TYPE_MD5:
case HWCRYPTO_TYPE_SHA1:
case HWCRYPTO_TYPE_SHA2:
HASH_DeInit();
FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_HASH, DISABLE);
break;
#endif /* BSP_USING_HASH */
#if defined(BSP_USING_AES)
case HWCRYPTO_TYPE_AES:
case HWCRYPTO_TYPE_DES:
case HWCRYPTO_TYPE_3DES:
case HWCRYPTO_TYPE_RC4:
case HWCRYPTO_TYPE_GCM:
AES_DeInit();
FCG_Fcg0PeriphClockCmd(PWC_FCG0_AES, DISABLE);
break;
#endif /* BSP_USING_AES */
default:
break;
}
}
static rt_err_t _crypto_clone(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src)
{
rt_err_t res = RT_EOK;
switch (src->type & HWCRYPTO_MAIN_TYPE_MASK)
{
#if defined(BSP_USING_RNG)
case HWCRYPTO_TYPE_RNG:
break;
#endif /* BSP_USING_RNG */
#if defined(BSP_USING_CRC)
case HWCRYPTO_TYPE_CRC:
break;
#endif /* BSP_USING_CRC */
#if defined(BSP_USING_HASH)
case HWCRYPTO_TYPE_MD5:
case HWCRYPTO_TYPE_SHA1:
case HWCRYPTO_TYPE_SHA2:
break;
#endif /* BSP_USING_HASH */
#if defined(BSP_USING_AES)
case HWCRYPTO_TYPE_AES:
case HWCRYPTO_TYPE_DES:
case HWCRYPTO_TYPE_3DES:
case HWCRYPTO_TYPE_RC4:
case HWCRYPTO_TYPE_GCM:
break;
#endif /* BSP_USING_AES */
default:
res = -RT_ERROR;
break;
}
return res;
}
static void _crypto_reset(struct rt_hwcrypto_ctx *ctx)
{
switch (ctx->type & HWCRYPTO_MAIN_TYPE_MASK)
{
#if defined(BSP_USING_RNG)
case HWCRYPTO_TYPE_RNG:
break;
#endif /* BSP_USING_RNG */
#if defined(BSP_USING_CRC)
case HWCRYPTO_TYPE_CRC:
break;
#endif /* BSP_USING_CRC */
#if defined(BSP_USING_HASH)
case HWCRYPTO_TYPE_MD5:
case HWCRYPTO_TYPE_SHA1:
case HWCRYPTO_TYPE_SHA2:
break;
#endif /* BSP_USING_HASH*/
#if defined(BSP_USING_AES)
case HWCRYPTO_TYPE_AES:
case HWCRYPTO_TYPE_DES:
case HWCRYPTO_TYPE_3DES:
case HWCRYPTO_TYPE_RC4:
case HWCRYPTO_TYPE_GCM:
break;
#endif /* BSP_USING_AES */
default:
break;
}
}
static const struct rt_hwcrypto_ops _ops =
{
.create = _crypto_create,
.destroy = _crypto_destroy,
.copy = _crypto_clone,
.reset = _crypto_reset,
};
static int rt_hw_crypto_device_init(void)
{
static struct hc32_hwcrypto_device _crypto_dev;
#if defined(BSP_USING_UQID)
stc_efm_unique_id_t pstcUID;
rt_uint32_t cpuid[3] = {0};
EFM_GetUID(&pstcUID);
cpuid[0] = pstcUID.u32UniqueID0;
cpuid[1] = pstcUID.u32UniqueID1;
cpuid[2] = pstcUID.u32UniqueID2;
/* we only used 2 words to as the UQID */
rt_memcpy(&_crypto_dev.dev.id, cpuid, 8);
LOG_D("UQID = %x%x", cpuid[0], cpuid[1]);
#endif /* BSP_USING_UQID */
_crypto_dev.dev.ops = &_ops;
_crypto_dev.dev.user_data = &_crypto_dev;
if (rt_hwcrypto_register(&_crypto_dev.dev, RT_HWCRYPTO_DEFAULT_NAME) != RT_EOK)
{
return -RT_ERROR;
}
rt_mutex_init(&_crypto_dev.mutex, RT_HWCRYPTO_DEFAULT_NAME, RT_IPC_FLAG_PRIO);
return RT_EOK;
}
INIT_DEVICE_EXPORT(rt_hw_crypto_device_init);
#endif