subsys/random: Add cryptographically secure and bulk fill functions

1) Add cryptographically secure random functions to provide
FIPS 140-2 compliant random functions.

2) Add name to random function choice selectors to ease
selection in SOC .defconfig files

3) Add bulk fill random functions.

Signed-off-by: David Leach <david.leach@nxp.com>
This commit is contained in:
David Leach 2019-07-23 14:16:24 -05:00 committed by Kumar Gala
parent 07bf345db3
commit afdc63f320
17 changed files with 596 additions and 42 deletions

View file

@ -364,6 +364,7 @@
/subsys/net/l2/ @jukkar @tbursztyka /subsys/net/l2/ @jukkar @tbursztyka
/subsys/net/l2/canbus/ @alexanderwachter @jukkar /subsys/net/l2/canbus/ @alexanderwachter @jukkar
/subsys/power/ @wentongwu @pizi-nordic /subsys/power/ @wentongwu @pizi-nordic
/subsys/random/ @dleach02
/subsys/settings/ @nvlsianpu /subsys/settings/ @nvlsianpu
/subsys/shell/ @jakub-uC @nordic-krch /subsys/shell/ @jakub-uC @nordic-krch
/subsys/storage/ @nvlsianpu /subsys/storage/ @nvlsianpu

View file

@ -12,5 +12,4 @@ CONFIG_GPIO=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=40000000 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=40000000
CONFIG_OSC_EXTERNAL=y CONFIG_OSC_EXTERNAL=y
CONFIG_XOROSHIRO_RANDOM_GENERATOR=y
CONFIG_ADC_MCUX_ADC16_VREF_ALTERNATE=y CONFIG_ADC_MCUX_ADC16_VREF_ALTERNATE=y

View file

@ -38,13 +38,17 @@ are listed below.
* **Serial communication**: This device driver is used by the kernel's * **Serial communication**: This device driver is used by the kernel's
system console subsystem. system console subsystem.
* **Random number generator**: This device driver provides a source of random * **Entropy**: This device driver provides a source of entropy numbers
numbers. for the random number generator subsystem.
.. important:: .. important::
Certain implementations of the random number generator device driver Use the :ref:`random API functions <random_api>` for random
do not generate sequences of values that are truly random. values. :ref:`Entropy functions <entropy_interface>` should not be
directly used as a random number generator source as some hardware
implementations are designed to be an entropy seed source for random
number generators and will not provide cryptographically secure
random number streams.
Synchronous Calls Synchronous Calls
***************** *****************

View file

@ -17,6 +17,7 @@ API Reference
networking/index.rst networking/index.rst
peripherals/index.rst peripherals/index.rst
power_management/index.rst power_management/index.rst
random/index.rst
shell/index.rst shell/index.rst
storage/index.rst storage/index.rst
usb/index.rst usb/index.rst

View file

@ -6,6 +6,10 @@ Entropy
Overview Overview
******** ********
The entropy API provides functions to retrieve entropy values from
entropy hardware present on the platform. The entropy APIs are provided
for use by the random subsystem and cryptographic services. They are not
suitable to be used as random number generation functions.
API Reference API Reference
************* *************

View file

@ -0,0 +1,101 @@
.. _random_reference:
Random
######
The random API subsystem provides random number generation APIs in both
cryptographically and non-cryptographically secure instances. Which
random API to use is based on the cryptographic requirements of the
random number. The non-cryptographic APIs will return random values
much faster if non-cryptographic values are needed.
The cryptographically secure random functions shall be compliant to the
FIPS 140-2 [NIST02]_ recommended algorithms. Hardware based random-number
generators (RNG) can be used on platforms with appropriate hardware support.
Platforms without hardware RNG support shall use the `CTR-DRBG algorithm
<https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf>`_.
The algorithm can be provided by `TinyCrypt <https://01.org/tinycrypt>`_
or `mbedTLS <https://tls.mbed.org/ctr-drbg-source-code>`_ depending on
your application performance and resource requirements.
.. note::
The CTR-DRBG generator needs an entropy source to establish and
maintain the cryptographic security of the PRNG.
.. _random_kconfig:
Kconfig Options
***************
These options can be found in the following path :zephyr_file:`subsys/random/Kconfig`.
:option:`CONFIG_TEST_RANDOM_GENERATOR`
For testing, this option permits random number APIs to return values
that are not truly random.
The random number generator choice group allows selection of the RNG
source function for the system via the RNG_GENERATOR_CHOICE choice group.
An override of the default value can be specified in the SOC or board
.defconfig file by using:
.. code-block:: none
choice RNG_GENERATOR_CHOICE
default XOROSHIRO_RANDOM_GENERATOR
endchoice
The random number generators available include:
:option:`CONFIG_X86_TSC_RANDOM_GENERATOR`
enables number generator based on timestamp counter of x86 boards,
obtained with rdtsc instruction.
:option:`CONFIG_TIMER_RANDOM_GENERATOR`
enables number generator based on system timer clock. This number
generator is not random and used for testing only.
:option:`CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR`
enables a random number generator that uses the enabled hardware
entropy gathering driver to generate random numbers.
:option:`CONFIG_XOROSHIRO_RANDOM_GENERATOR`
enables the Xoroshiro128+ pseudo-random number generator, that uses the
entropy driver as a seed source.
The CSPRNG_GENERATOR_CHOICE choice group provides selection of the
cryptographically secure random number generator source function. An
override of the default value can be specified in the SOC or board
.defconfig file by using:
.. code-block:: none
choice CSPRNG_GENERATOR_CHOICE
default CTR_DRBG_CSPRNG_GENERATOR
endchoice
The cryptographically secure random number generators available include:
:option:`CONFIG_HARDWARE_DEVICE_CS_GENERATOR`
enables a cryptographically secure random number generator using the
hardware random generator driver
:option:`CONFIG_CTR_DRBG_CSPRNG_GENERATOR`
enables the CTR-DRBG pseudo-random number generator. The CTR-DRBG is
a FIPS140-2 recommended cryptographically secure random number generator.
Personalization data can be provided in addition to the entropy source
to make the initialization of the CTR-DRBG as unique as possible.
:option:`CONFIG_CS_CTR_DRBG_PERSONALIZATION`
CTR-DRBG Initialization Personalization string
.. _random_api:
API Reference
*************
.. doxygengroup:: random_api
:project: Zephyr

View file

@ -8,16 +8,15 @@ config TINYCRYPT
help help
This option enables the TinyCrypt cryptography library. This option enables the TinyCrypt cryptography library.
if TINYCRYPT
config TINYCRYPT_CTR_PRNG config TINYCRYPT_CTR_PRNG
bool "PRNG in counter mode" bool "PRNG in counter mode"
depends on TINYCRYPT
help help
This option enables support for the pseudo-random number This option enables support for the pseudo-random number
generator in counter mode. generator in counter mode.
config TINYCRYPT_SHA256 config TINYCRYPT_SHA256
bool "SHA-256 Hash function support" bool "SHA-256 Hash function support"
depends on TINYCRYPT
help help
This option enables support for SHA-256 This option enables support for SHA-256
hash function primitive. hash function primitive.
@ -38,7 +37,6 @@ config TINYCRYPT_SHA256_HMAC_PRNG
config TINYCRYPT_ECC_DH config TINYCRYPT_ECC_DH
bool "ECC_DH anonymous key agreement protocol" bool "ECC_DH anonymous key agreement protocol"
depends on TINYCRYPT
help help
This option enables support for the Elliptic curve This option enables support for the Elliptic curve
Diffie-Hellman anonymous key agreement protocol. Diffie-Hellman anonymous key agreement protocol.
@ -48,7 +46,6 @@ config TINYCRYPT_ECC_DH
config TINYCRYPT_ECC_DSA config TINYCRYPT_ECC_DSA
bool "ECC_DSA digital signature algorithm" bool "ECC_DSA digital signature algorithm"
depends on TINYCRYPT
help help
This option enables support for the Elliptic Curve Digital This option enables support for the Elliptic Curve Digital
Signature Algorithm (ECDSA). Signature Algorithm (ECDSA).
@ -58,7 +55,6 @@ config TINYCRYPT_ECC_DSA
config TINYCRYPT_AES config TINYCRYPT_AES
bool "AES-128 decrypt/encrypt" bool "AES-128 decrypt/encrypt"
depends on TINYCRYPT
help help
This option enables support for AES-128 decrypt and encrypt. This option enables support for AES-128 decrypt and encrypt.
@ -85,3 +81,4 @@ config TINYCRYPT_AES_CMAC
depends on TINYCRYPT_AES depends on TINYCRYPT_AES
help help
This option enables support for AES-128 CMAC mode. This option enables support for AES-128 CMAC mode.
endif

View file

@ -8,28 +8,75 @@
* @file * @file
* @brief Random number generator header file * @brief Random number generator header file
* *
* This header file declares prototypes for the kernel's random number generator * This header file declares prototypes for the kernel's random number
* APIs. * generator APIs.
* *
* Typically, a platform enables the hidden CUSTOM_RANDOM_GENERATOR or * Typically, a platform enables the appropriate source for the random
* number generation based on the hardware platform's capabilities or
* (for testing purposes only) enables the TEST_RANDOM_GENERATOR * (for testing purposes only) enables the TEST_RANDOM_GENERATOR
* configuration option and provide its own driver that implements * configuration option.
* sys_rand32_get().
*/ */
#ifndef ZEPHYR_INCLUDE_RANDOM_RAND32_H_ #ifndef ZEPHYR_INCLUDE_RANDOM_RAND32_H_
#define ZEPHYR_INCLUDE_RANDOM_RAND32_H_ #define ZEPHYR_INCLUDE_RANDOM_RAND32_H_
#include <zephyr/types.h> #include <zephyr/types.h>
#include <stddef.h>
/**
* @brief Random Function APIs
* @defgroup random_api Random Function APIs
* @{
*/
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/**
* @brief Return a 32-bit random value that should pass general
* randomness tests.
*
* @note The random value returned is not a cryptographically secure
* random number value.
*
* @return 32-bit random value.
*/
extern u32_t sys_rand32_get(void); extern u32_t sys_rand32_get(void);
/**
* @brief Fill the destination buffer with random data values that should
* pass general randomness tests.
*
* @note The random values returned are not considered cryptographically
* secure random number values.
*
* @param [out] dst destination buffer to fill with random data.
* @param len size of the destination buffer.
*
*/
extern void sys_rand_get(void *dst, size_t len);
/**
* @brief Fill the destination buffer with cryptographically secure
* random data values.
*
* @note If the random values requested do not need to be cryptographically
* secure then use sys_rand_get() instead.
*
* @param [out] dst destination buffer to fill.
* @param len size of the destination buffer.
*
* @return 0 if success, -EIO if entropy reseed error
*
*/
extern int sys_csrand_get(void *dst, size_t len);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
/**
* @}
*/
#endif /* ZEPHYR_INCLUDE_RANDOM_RAND32_H_ */ #endif /* ZEPHYR_INCLUDE_RANDOM_RAND32_H_ */

View file

@ -66,6 +66,17 @@ config ENTROPY_MCUX_TRNG
endif # ENTROPY_GENERATOR endif # ENTROPY_GENERATOR
choice CSPRNG_GENERATOR_CHOICE
default CTR_DRBG_CSPRNG_GENERATOR
endchoice
choice RNG_GENERATOR_CHOICE
default XOROSHIRO_RANDOM_GENERATOR
endchoice
config TINYCRYPT
default y
if FLASH if FLASH
config SOC_FLASH_MCUX config SOC_FLASH_MCUX

View file

@ -96,4 +96,25 @@ config NET_CONFIG_IEEE802154_DEV_NAME
endif # NETWORKING endif # NETWORKING
choice CSPRNG_GENERATOR_CHOICE
default CTR_DRBG_CSPRNG_GENERATOR
endchoice
if ENTROPY_GENERATOR
#
# MBEDTLS is larger but much faster than TinyCrypt so choose wisely
#
#config MBEDTLS
config TINYCRYPT
default y
endif
#
# KW41Z TRNG entropy source cannot be used as a Hardware RNG source so
# use XOROSHIRO for PRNG
#
choice RNG_GENERATOR_CHOICE
default XOROSHIRO_RANDOM_GENERATOR
endchoice
endif # SOC_MKW41Z4 endif # SOC_MKW41Z4

View file

@ -1,6 +1,21 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
zephyr_sources_ifdef(CONFIG_TIMER_RANDOM_GENERATOR rand32_timer.c) if (CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR OR
zephyr_sources_ifdef(CONFIG_X86_TSC_RANDOM_GENERATOR rand32_timestamp.c) CONFIG_TIMER_RANDOM_GENERATOR OR
zephyr_sources_ifdef(CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR rand32_entropy_device.c) CONFIG_X86_TSC_RANDOM_GENERATOR OR
zephyr_sources_ifdef(CONFIG_XOROSHIRO_RANDOM_GENERATOR rand32_xoroshiro128.c) CONFIG_XOROSHIRO_RANDOM_GENERATOR)
zephyr_library()
endif()
zephyr_library_sources_ifdef(CONFIG_TIMER_RANDOM_GENERATOR rand32_timer.c)
zephyr_library_sources_ifdef(CONFIG_X86_TSC_RANDOM_GENERATOR rand32_timestamp.c)
zephyr_library_sources_ifdef(CONFIG_XOROSHIRO_RANDOM_GENERATOR rand32_xoroshiro128.c)
zephyr_library_sources_ifdef(CONFIG_CTR_DRBG_CSPRNG_GENERATOR rand32_ctr_drbg.c)
if (CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR OR CONFIG_HARDWARE_DEVICE_CS_GENERATOR)
zephyr_library_sources(rand32_entropy_device.c)
endif()
if (CONFIG_CTR_DRBG_CSPRNG_GENERATOR)
zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS)
endif()

View file

@ -3,6 +3,8 @@
# Copyright (c) 2017 Intel Corporation # Copyright (c) 2017 Intel Corporation
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
menu "Random subsystem"
config TEST_RANDOM_GENERATOR config TEST_RANDOM_GENERATOR
bool "Non-random number generator" bool "Non-random number generator"
depends on !ENTROPY_HAS_DRIVER depends on !ENTROPY_HAS_DRIVER
@ -13,10 +15,16 @@ config TEST_RANDOM_GENERATOR
number generator is not available. The non-random number generator number generator is not available. The non-random number generator
should not be used in a production environment. should not be used in a production environment.
choice choice RNG_GENERATOR_CHOICE
prompt "Random generator" prompt "Random generator"
default ENTROPY_DEVICE_RANDOM_GENERATOR default ENTROPY_DEVICE_RANDOM_GENERATOR
depends on ENTROPY_HAS_DRIVER || TEST_RANDOM_GENERATOR depends on ENTROPY_HAS_DRIVER || TEST_RANDOM_GENERATOR
help
Platform dependent non-cryptographically secure random number support.
If the entropy support of the platform has sufficient performance
to support random request then select that. Otherwise, select the
XOROSHIRO algorithm
config X86_TSC_RANDOM_GENERATOR config X86_TSC_RANDOM_GENERATOR
bool "x86 timestamp counter based number generator" bool "x86 timestamp counter based number generator"
@ -37,18 +45,73 @@ config ENTROPY_DEVICE_RANDOM_GENERATOR
bool "Use entropy driver to generate random numbers" bool "Use entropy driver to generate random numbers"
depends on ENTROPY_HAS_DRIVER depends on ENTROPY_HAS_DRIVER
help help
Enables a random number generator that uses the enabled Enables a random number generator that uses the enabled hardware
hardware entropy gathering driver to generate random entropy gathering driver to generate random numbers. Should only be
numbers. selected if hardware entropy driver is designed to be a random
number generator source.
config XOROSHIRO_RANDOM_GENERATOR config XOROSHIRO_RANDOM_GENERATOR
bool "Use Xoroshiro128+ as PRNG" bool "Use Xoroshiro128+ as PRNG"
depends on ENTROPY_HAS_DRIVER depends on ENTROPY_HAS_DRIVER
help help
Enables the Xoroshiro128+ pseudo-random number generator, that Enables the Xoroshiro128+ pseudo-random number generator, that uses
uses the entropy driver as a seed source. This is not a the entropy driver as a seed source. This is a fast non-cryptographically
cryptographically secure random number generator. secure random number generator.
It is so named because it uses 128 bits of state. It is so named because it uses 128 bits of state.
endchoice endchoice # RNG_GENERATOR_CHOICE
#
# Implied dependency on a cryptographically secure entropy source when
# enabling CS generators. ENTROPY_HAS_DRIVER is the flag indicating the
# CS entropy source.
#
config CSPRING_ENABLED
# bool "Cryptographically secure RNG functions enabled"
bool
default y
depends on ENTROPY_HAS_DRIVER
choice CSPRNG_GENERATOR_CHOICE
prompt "Cryptographically secure random generator"
default HARDWARE_DEVICE_CS_GENERATOR
help
Platform dependent cryptographically secure random number support.
If the hardware entropy support of the platform has sufficient
performance to support CSRNG then select that. Otherwise, select
CTR-DRBG CSPRNG as that is a FIPS140-2 recommmended CSPRNG.
config HARDWARE_DEVICE_CS_GENERATOR
bool "Use hardware random driver for CS random numbers"
depends on ENTROPY_HAS_DRIVER
help
Enables a cryptographically secure random number generator that
uses the enabled hardware random number driver to generate
random numbers.
config CTR_DRBG_CSPRNG_GENERATOR
bool "Use CTR-DRBG CSPRNG"
depends on MBEDTLS || TINYCRYPT
depends on ENTROPY_HAS_DRIVER
select TINYCRYPT_CTR_PRNG if TINYCRYPT
select TINYCRYPT_AES if TINYCRYPT
help
Enables the CTR-DRBG pseudo-random number generator. This CSPRNG
shall use the entropy API for an initialization seed. The CTR-DRBG
is a a FIPS140-2 recommended cryptographically secure random number
generator.
endchoice # CSPRNG_GENERATOR_CHOICE
config CS_CTR_DRBG_PERSONALIZATION
string "CTR-DRBG Personalization string"
default "zephyr ctr-drbg seed"
depends on CTR_DRBG_CSPRNG_GENERATOR
help
Personalization data can be provided in addition to the entropy
source to make the initialization of the CTR-DRBG as unique as
possible.
endmenu

View file

@ -0,0 +1,149 @@
/*
* Copyright (c) 2019, NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <init.h>
#include <device.h>
#include <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 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(ctx, (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(CONFIG_ENTROPY_NAME);
if (!entropy_driver) {
__ASSERT((entropy_driver != NULL),
"Device driver for %s (CONFIG_ENTROPY_NAME) not found. "
"Check your build configuration!",
CONFIG_ENTROPY_NAME);
return -EINVAL;
}
#if defined(CONFIG_MBEDTLS)
mbedtls_ctr_drbg_init(&ctr_ctx);
ret = mbedtls_ctr_drbg_seed(&ctr_ctx,
ctr_drbg_entropy_func,
entropy_driver,
drbg_seed,
sizeof(drbg_seed));
if (ret != 0) {
mbedtls_ctr_drbg_free(&ctr_ctx);
return -EIO;
}
#elif defined(CONFIG_TINYCRYPT)
u8_t entropy[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
entropy_get_entropy(entropy_driver, (void *)&entropy, sizeof(entropy));
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 sys_csrand_get(void *dst, u32_t outlen)
{
int ret;
unsigned int key = irq_lock();
if (unlikely(!entropy_driver)) {
ret = ctr_drbg_initialize();
if (ret != 0) {
return ret;
}
}
#if defined(CONFIG_MBEDTLS)
ret = mbedtls_ctr_drbg_random(&ctr_ctx, (unsigned char *)dst, outlen);
#elif defined(CONFIG_TINYCRYPT)
u8_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) {
entropy_get_entropy(entropy_driver,
(void *)&entropy, sizeof(entropy));
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
irq_unlock(key);
return ret;
}

View file

@ -7,9 +7,11 @@
#include <sys/atomic.h> #include <sys/atomic.h>
#include <kernel.h> #include <kernel.h>
#include <drivers/entropy.h> #include <drivers/entropy.h>
#include <string.h>
static struct device *entropy_driver; static struct device *entropy_driver;
#if defined(CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR)
u32_t sys_rand32_get(void) u32_t sys_rand32_get(void)
{ {
struct device *dev = entropy_driver; struct device *dev = entropy_driver;
@ -42,3 +44,70 @@ u32_t sys_rand32_get(void)
return random_num; return random_num;
} }
#endif /* CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR */
static void rand_get(u8_t *dst, size_t outlen)
{
struct device *dev = entropy_driver;
u32_t random_num;
int ret;
if (unlikely(!dev)) {
/* Only one entropy device exists, so this is safe even
* if the whole operation isn't atomic.
*/
dev = device_get_binding(CONFIG_ENTROPY_NAME);
__ASSERT((dev != NULL),
"Device driver for %s (CONFIG_ENTROPY_NAME) not found. "
"Check your build configuration!",
CONFIG_ENTROPY_NAME);
entropy_driver = dev;
}
ret = entropy_get_entropy(dev, dst, outlen);
if (unlikely(ret < 0)) {
/* Use system timer in case the entropy device couldn't deliver
* 32-bit of data. There's not much that can be done in this
* situation. An __ASSERT() isn't used here as the HWRNG might
* still be gathering entropy during early boot situations.
*/
u32_t len = 0;
u32_t blocksize = 4;
while (len < outlen) {
random_num = k_cycle_get_32();
if ((outlen-len) < sizeof(random_num)) {
blocksize = len;
(void *)memcpy(&(dst[random_num]),
&random_num, blocksize);
} else {
*((u32_t *)&dst[len]) = random_num;
}
len += blocksize;
}
}
}
#if defined(CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR)
void sys_rand_get(void *dst, size_t outlen)
{
return rand_get(dst, outlen);
}
#endif /* CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR */
#if defined(CONFIG_HARDWARE_DEVICE_CS_GENERATOR)
int sys_csrand_get(void *dst, size_t outlen)
{
rand_get(dst, outlen);
/* need deeper inspection on hardware based RNG error cases. Right
* now the assumption is that the HW will continue providing a stream
* of RNG values
*/
return 0;
}
#endif /* CONFIG_HARDWARE_DEVICE_CS_GENERATOR */

View file

@ -18,6 +18,7 @@
#include <drivers/timer/system_timer.h> #include <drivers/timer/system_timer.h>
#include <kernel.h> #include <kernel.h>
#include <sys/atomic.h> #include <sys/atomic.h>
#include <string.h>
#if defined(__GNUC__) #if defined(__GNUC__)
@ -45,4 +46,36 @@ u32_t sys_rand32_get(void)
return k_cycle_get_32() + atomic_add(&_rand32_counter, _RAND32_INC); return k_cycle_get_32() + atomic_add(&_rand32_counter, _RAND32_INC);
} }
/**
*
* @brief Fill destination buffer with random numbers
*
* The non-random number generator returns values that are based off the
* target's clock counter, which means that successive calls will return
* different values.
*
* @param dst destination buffer to fill
* @param outlen size of destination buffer to fill
*
* @return N/A
*/
void sys_rand_get(void *dst, size_t outlen)
{
u32_t len = 0;
u32_t blocksize = 4;
u32_t ret;
u32_t *udst = (u32_t *)dst;
while (len < outlen) {
ret = sys_rand32_get();
if ((outlen-len) < sizeof(ret)) {
blocksize = len;
(void *)memcpy(udst, &ret, blocksize);
} else {
(*udst++) = ret;
}
len += blocksize;
}
}
#endif /* __GNUC__ */ #endif /* __GNUC__ */

View file

@ -17,6 +17,7 @@
#include <kernel.h> #include <kernel.h>
#include <arch/cpu.h> #include <arch/cpu.h>
#include <random/rand32.h> #include <random/rand32.h>
#include <string.h>
/** /**
* *
@ -33,3 +34,36 @@ u32_t sys_rand32_get(void)
{ {
return z_do_read_cpu_timestamp32(); return z_do_read_cpu_timestamp32();
} }
/**
*
* @brief Fill destination buffer with random numbers
*
* The non-random number generator returns values that are based off the
* target's clock counter, which means that successive calls will return
* different values.
*
* @param dst destination buffer to fill
* @param outlen size of destination buffer to fill
*
* @return N/A
*/
void sys_rand_get(void *dst, size_t outlen)
{
u32_t len = 0;
u32_t blocksize = 4;
u32_t ret;
u32_t *udst = (u32_t *)dst;
while (len < outlen) {
ret = sys_rand32_get();
if ((outlen-len) < sizeof(ret)) {
blocksize = len;
(void *)memcpy(udst, &ret, blocksize);
} else {
(*udst++) = ret;
}
len += blocksize;
}
}

View file

@ -41,11 +41,10 @@
#include <device.h> #include <device.h>
#include <drivers/entropy.h> #include <drivers/entropy.h>
#include <kernel.h> #include <kernel.h>
#include <string.h>
static u64_t state[2]; static u64_t state[2];
K_SEM_DEFINE(state_sem, 1, 1);
static inline u64_t rotl(const u64_t x, int k) static inline u64_t rotl(const u64_t x, int k)
{ {
return (x << k) | (x >> (64 - k)); return (x << k) | (x >> (64 - k));
@ -72,8 +71,6 @@ static int xoroshiro128_initialize(struct device *dev)
return -EINVAL; return -EINVAL;
} }
k_object_access_all_grant(&state_sem);
return 0; return 0;
} }
@ -94,22 +91,30 @@ u32_t sys_rand32_get(void)
{ {
u32_t ret; u32_t ret;
if (k_sem_take(&state_sem, K_FOREVER) < 0) {
/* FIXME: with all threads having access to this semaphore,
* it's possible that they can corrupt state_sem in a way
* that k_sem_take will fail. This can be abused to
* generate numbers without using the xoroshiro128+ RNG.
*/
return k_cycle_get_32();
}
ret = xoroshiro128_next(); ret = xoroshiro128_next();
k_sem_give(&state_sem);
return ret; return ret;
} }
void sys_rand_get(void *dst, size_t outlen)
{
u32_t ret;
u32_t blocksize = 4;
u32_t len = 0;
u32_t *udst = (u32_t *)dst;
while (len < outlen) {
ret = xoroshiro128_next();
if ((outlen-len) < sizeof(ret)) {
blocksize = len;
(void *)memcpy(udst, &ret, blocksize);
} else {
(*udst++) = ret;
}
len += blocksize;
}
}
/* In-tree entropy drivers will initialize in PRE_KERNEL_1; ensure that they're /* In-tree entropy drivers will initialize in PRE_KERNEL_1; ensure that they're
* initialized properly before initializing ourselves. * initialized properly before initializing ourselves.
*/ */