zephyr/subsys/random/rand32_ctr_drbg.c

160 lines
3.1 KiB
C

/*
* Copyright (c) 2019, NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <init.h>
#include <device.h>
#include <drivers/entropy.h>
#include <kernel.h>
#include <string.h>
#if defined(CONFIG_MBEDTLS)
#if !defined(CONFIG_MBEDTLS_CFG_FILE)
#include "mbedtls/config.h"
#else
#include CONFIG_MBEDTLS_CFG_FILE
#endif /* CONFIG_MBEDTLS_CFG_FILE */
#include <mbedtls/ctr_drbg.h>
#elif defined(CONFIG_TINYCRYPT)
#include <tinycrypt/ctr_prng.h>
#include <tinycrypt/aes.h>
#include <tinycrypt/constants.h>
#endif /* CONFIG_MBEDTLS */
static K_SEM_DEFINE(state_sem, 1, 1);
static const struct device *entropy_driver;
static const unsigned char drbg_seed[] = CONFIG_CS_CTR_DRBG_PERSONALIZATION;
#if defined(CONFIG_MBEDTLS)
static mbedtls_ctr_drbg_context ctr_ctx;
static int ctr_drbg_entropy_func(void *ctx, unsigned char *buf, size_t len)
{
return entropy_get_entropy(entropy_driver, (void *)buf, len);
}
#elif defined(CONFIG_TINYCRYPT)
static TCCtrPrng_t ctr_ctx;
#endif /* CONFIG_MBEDTLS */
static int ctr_drbg_initialize(void)
{
int ret;
/* Only one entropy device exists, so this is safe even
* if the whole operation isn't atomic.
*/
entropy_driver = device_get_binding(DT_CHOSEN_ZEPHYR_ENTROPY_LABEL);
if (!entropy_driver) {
__ASSERT((entropy_driver != NULL),
"Device driver for %s (DT_CHOSEN_ZEPHYR_ENTROPY_LABEL) not found. "
"Check your build configuration!",
DT_CHOSEN_ZEPHYR_ENTROPY_LABEL);
return -EINVAL;
}
#if defined(CONFIG_MBEDTLS)
mbedtls_ctr_drbg_init(&ctr_ctx);
ret = mbedtls_ctr_drbg_seed(&ctr_ctx,
ctr_drbg_entropy_func,
NULL,
drbg_seed,
sizeof(drbg_seed));
if (ret != 0) {
mbedtls_ctr_drbg_free(&ctr_ctx);
return -EIO;
}
#elif defined(CONFIG_TINYCRYPT)
uint8_t entropy[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
ret = entropy_get_entropy(entropy_driver, (void *)&entropy,
sizeof(entropy));
if (ret != 0) {
return -EIO;
}
ret = tc_ctr_prng_init(&ctr_ctx,
(uint8_t *)&entropy,
sizeof(entropy),
(uint8_t *)drbg_seed,
sizeof(drbg_seed));
if (ret == TC_CRYPTO_FAIL) {
return -EIO;
}
#endif
return 0;
}
int z_impl_sys_csrand_get(void *dst, uint32_t outlen)
{
int ret;
unsigned int key = irq_lock();
if (unlikely(!entropy_driver)) {
ret = ctr_drbg_initialize();
if (ret != 0) {
ret = -EIO;
goto end;
}
}
#if defined(CONFIG_MBEDTLS)
ret = mbedtls_ctr_drbg_random(&ctr_ctx, (unsigned char *)dst, outlen);
#elif defined(CONFIG_TINYCRYPT)
uint8_t entropy[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
ret = tc_ctr_prng_generate(&ctr_ctx, 0, 0, (uint8_t *)dst, outlen);
if (ret == TC_CRYPTO_SUCCESS) {
ret = 0;
} else if (ret == TC_CTR_PRNG_RESEED_REQ) {
ret = entropy_get_entropy(entropy_driver,
(void *)&entropy, sizeof(entropy));
if (ret != 0) {
ret = -EIO;
goto end;
}
ret = tc_ctr_prng_reseed(&ctr_ctx,
entropy,
sizeof(entropy),
drbg_seed,
sizeof(drbg_seed));
ret = tc_ctr_prng_generate(&ctr_ctx, 0, 0,
(uint8_t *)dst, outlen);
ret = (ret == TC_CRYPTO_SUCCESS) ? 0 : -EIO;
} else {
ret = -EIO;
}
#endif
end:
irq_unlock(key);
return ret;
}