From afdc63f32074d8a2d290276c4d9e311bb727be4f Mon Sep 17 00:00:00 2001 From: David Leach Date: Tue, 23 Jul 2019 14:16:24 -0500 Subject: [PATCH] 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 --- CODEOWNERS | 1 + boards/arm/frdm_kw41z/frdm_kw41z_defconfig | 1 - doc/reference/drivers/index.rst | 12 +- doc/reference/index.rst | 1 + doc/reference/peripherals/entropy.rst | 4 + doc/reference/random/index.rst | 101 ++++++++++++ ext/lib/crypto/tinycrypt/Kconfig | 7 +- include/random/rand32.h | 57 ++++++- .../nxp_kinetis/kwx/Kconfig.defconfig.mkw40z4 | 11 ++ .../nxp_kinetis/kwx/Kconfig.defconfig.mkw41z4 | 21 +++ subsys/random/CMakeLists.txt | 23 ++- subsys/random/Kconfig | 79 +++++++++- subsys/random/rand32_ctr_drbg.c | 149 ++++++++++++++++++ subsys/random/rand32_entropy_device.c | 69 ++++++++ subsys/random/rand32_timer.c | 33 ++++ subsys/random/rand32_timestamp.c | 34 ++++ subsys/random/rand32_xoroshiro128.c | 35 ++-- 17 files changed, 596 insertions(+), 42 deletions(-) create mode 100644 doc/reference/random/index.rst create mode 100644 subsys/random/rand32_ctr_drbg.c diff --git a/CODEOWNERS b/CODEOWNERS index bbfe8a1358e..fd97973871e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -364,6 +364,7 @@ /subsys/net/l2/ @jukkar @tbursztyka /subsys/net/l2/canbus/ @alexanderwachter @jukkar /subsys/power/ @wentongwu @pizi-nordic +/subsys/random/ @dleach02 /subsys/settings/ @nvlsianpu /subsys/shell/ @jakub-uC @nordic-krch /subsys/storage/ @nvlsianpu diff --git a/boards/arm/frdm_kw41z/frdm_kw41z_defconfig b/boards/arm/frdm_kw41z/frdm_kw41z_defconfig index 6416cf57ecb..643f3e75aff 100644 --- a/boards/arm/frdm_kw41z/frdm_kw41z_defconfig +++ b/boards/arm/frdm_kw41z/frdm_kw41z_defconfig @@ -12,5 +12,4 @@ CONFIG_GPIO=y CONFIG_PINMUX=y CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=40000000 CONFIG_OSC_EXTERNAL=y -CONFIG_XOROSHIRO_RANDOM_GENERATOR=y CONFIG_ADC_MCUX_ADC16_VREF_ALTERNATE=y diff --git a/doc/reference/drivers/index.rst b/doc/reference/drivers/index.rst index 406197952e1..5905e8dbd34 100644 --- a/doc/reference/drivers/index.rst +++ b/doc/reference/drivers/index.rst @@ -38,13 +38,17 @@ are listed below. * **Serial communication**: This device driver is used by the kernel's system console subsystem. -* **Random number generator**: This device driver provides a source of random - numbers. +* **Entropy**: This device driver provides a source of entropy numbers + for the random number generator subsystem. .. important:: - Certain implementations of the random number generator device driver - do not generate sequences of values that are truly random. + Use the :ref:`random API functions ` for random + values. :ref:`Entropy functions ` 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 ***************** diff --git a/doc/reference/index.rst b/doc/reference/index.rst index 2f57c5745a0..a04f6006f6d 100644 --- a/doc/reference/index.rst +++ b/doc/reference/index.rst @@ -17,6 +17,7 @@ API Reference networking/index.rst peripherals/index.rst power_management/index.rst + random/index.rst shell/index.rst storage/index.rst usb/index.rst diff --git a/doc/reference/peripherals/entropy.rst b/doc/reference/peripherals/entropy.rst index dbc70f7e553..fa2b8122dfc 100644 --- a/doc/reference/peripherals/entropy.rst +++ b/doc/reference/peripherals/entropy.rst @@ -6,6 +6,10 @@ Entropy 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 ************* diff --git a/doc/reference/random/index.rst b/doc/reference/random/index.rst new file mode 100644 index 00000000000..435838abd85 --- /dev/null +++ b/doc/reference/random/index.rst @@ -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 +`_. +The algorithm can be provided by `TinyCrypt `_ +or `mbedTLS `_ 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 + + diff --git a/ext/lib/crypto/tinycrypt/Kconfig b/ext/lib/crypto/tinycrypt/Kconfig index 209228df980..7f279fbc59a 100644 --- a/ext/lib/crypto/tinycrypt/Kconfig +++ b/ext/lib/crypto/tinycrypt/Kconfig @@ -8,16 +8,15 @@ config TINYCRYPT help This option enables the TinyCrypt cryptography library. +if TINYCRYPT config TINYCRYPT_CTR_PRNG bool "PRNG in counter mode" - depends on TINYCRYPT help This option enables support for the pseudo-random number generator in counter mode. config TINYCRYPT_SHA256 bool "SHA-256 Hash function support" - depends on TINYCRYPT help This option enables support for SHA-256 hash function primitive. @@ -38,7 +37,6 @@ config TINYCRYPT_SHA256_HMAC_PRNG config TINYCRYPT_ECC_DH bool "ECC_DH anonymous key agreement protocol" - depends on TINYCRYPT help This option enables support for the Elliptic curve Diffie-Hellman anonymous key agreement protocol. @@ -48,7 +46,6 @@ config TINYCRYPT_ECC_DH config TINYCRYPT_ECC_DSA bool "ECC_DSA digital signature algorithm" - depends on TINYCRYPT help This option enables support for the Elliptic Curve Digital Signature Algorithm (ECDSA). @@ -58,7 +55,6 @@ config TINYCRYPT_ECC_DSA config TINYCRYPT_AES bool "AES-128 decrypt/encrypt" - depends on TINYCRYPT help This option enables support for AES-128 decrypt and encrypt. @@ -85,3 +81,4 @@ config TINYCRYPT_AES_CMAC depends on TINYCRYPT_AES help This option enables support for AES-128 CMAC mode. +endif diff --git a/include/random/rand32.h b/include/random/rand32.h index 186b68fb739..a0651490529 100644 --- a/include/random/rand32.h +++ b/include/random/rand32.h @@ -8,28 +8,75 @@ * @file * @brief Random number generator header file * - * This header file declares prototypes for the kernel's random number generator - * APIs. + * This header file declares prototypes for the kernel's random number + * 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 - * configuration option and provide its own driver that implements - * sys_rand32_get(). + * configuration option. */ #ifndef ZEPHYR_INCLUDE_RANDOM_RAND32_H_ #define ZEPHYR_INCLUDE_RANDOM_RAND32_H_ #include +#include + +/** + * @brief Random Function APIs + * @defgroup random_api Random Function APIs + * @{ + */ #ifdef __cplusplus extern "C" { #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); +/** + * @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 } #endif +/** + * @} + */ + #endif /* ZEPHYR_INCLUDE_RANDOM_RAND32_H_ */ diff --git a/soc/arm/nxp_kinetis/kwx/Kconfig.defconfig.mkw40z4 b/soc/arm/nxp_kinetis/kwx/Kconfig.defconfig.mkw40z4 index a9072454c0c..f3ecc975d9e 100644 --- a/soc/arm/nxp_kinetis/kwx/Kconfig.defconfig.mkw40z4 +++ b/soc/arm/nxp_kinetis/kwx/Kconfig.defconfig.mkw40z4 @@ -66,6 +66,17 @@ config ENTROPY_MCUX_TRNG 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 config SOC_FLASH_MCUX diff --git a/soc/arm/nxp_kinetis/kwx/Kconfig.defconfig.mkw41z4 b/soc/arm/nxp_kinetis/kwx/Kconfig.defconfig.mkw41z4 index 84582feb72c..9b7012d362d 100644 --- a/soc/arm/nxp_kinetis/kwx/Kconfig.defconfig.mkw41z4 +++ b/soc/arm/nxp_kinetis/kwx/Kconfig.defconfig.mkw41z4 @@ -96,4 +96,25 @@ config NET_CONFIG_IEEE802154_DEV_NAME 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 diff --git a/subsys/random/CMakeLists.txt b/subsys/random/CMakeLists.txt index b0bea8f7130..1fd6a078b97 100644 --- a/subsys/random/CMakeLists.txt +++ b/subsys/random/CMakeLists.txt @@ -1,6 +1,21 @@ # SPDX-License-Identifier: Apache-2.0 -zephyr_sources_ifdef(CONFIG_TIMER_RANDOM_GENERATOR rand32_timer.c) -zephyr_sources_ifdef(CONFIG_X86_TSC_RANDOM_GENERATOR rand32_timestamp.c) -zephyr_sources_ifdef(CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR rand32_entropy_device.c) -zephyr_sources_ifdef(CONFIG_XOROSHIRO_RANDOM_GENERATOR rand32_xoroshiro128.c) +if (CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR OR + CONFIG_TIMER_RANDOM_GENERATOR OR + CONFIG_X86_TSC_RANDOM_GENERATOR OR + 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() diff --git a/subsys/random/Kconfig b/subsys/random/Kconfig index 15cd84d3123..d746bda7095 100644 --- a/subsys/random/Kconfig +++ b/subsys/random/Kconfig @@ -3,6 +3,8 @@ # Copyright (c) 2017 Intel Corporation # SPDX-License-Identifier: Apache-2.0 +menu "Random subsystem" + config TEST_RANDOM_GENERATOR bool "Non-random number generator" depends on !ENTROPY_HAS_DRIVER @@ -13,10 +15,16 @@ config TEST_RANDOM_GENERATOR number generator is not available. The non-random number generator should not be used in a production environment. -choice +choice RNG_GENERATOR_CHOICE prompt "Random generator" default ENTROPY_DEVICE_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 bool "x86 timestamp counter based number generator" @@ -37,18 +45,73 @@ config ENTROPY_DEVICE_RANDOM_GENERATOR bool "Use entropy driver to generate random numbers" depends on ENTROPY_HAS_DRIVER help - Enables a random number generator that uses the enabled - hardware entropy gathering driver to generate random - numbers. + Enables a random number generator that uses the enabled hardware + entropy gathering driver to generate random numbers. Should only be + selected if hardware entropy driver is designed to be a random + number generator source. config XOROSHIRO_RANDOM_GENERATOR bool "Use Xoroshiro128+ as PRNG" depends on ENTROPY_HAS_DRIVER help - Enables the Xoroshiro128+ pseudo-random number generator, that - uses the entropy driver as a seed source. This is not a - cryptographically secure random number generator. + Enables the Xoroshiro128+ pseudo-random number generator, that uses + the entropy driver as a seed source. This is a fast non-cryptographically + secure random number generator. 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 diff --git a/subsys/random/rand32_ctr_drbg.c b/subsys/random/rand32_ctr_drbg.c new file mode 100644 index 00000000000..be208a9365f --- /dev/null +++ b/subsys/random/rand32_ctr_drbg.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2019, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#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 + +#elif defined(CONFIG_TINYCRYPT) + +#include +#include +#include + +#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; +} diff --git a/subsys/random/rand32_entropy_device.c b/subsys/random/rand32_entropy_device.c index 8af6ce342be..4c289343cb8 100644 --- a/subsys/random/rand32_entropy_device.c +++ b/subsys/random/rand32_entropy_device.c @@ -7,9 +7,11 @@ #include #include #include +#include static struct device *entropy_driver; +#if defined(CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR) u32_t sys_rand32_get(void) { struct device *dev = entropy_driver; @@ -42,3 +44,70 @@ u32_t sys_rand32_get(void) 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 */ diff --git a/subsys/random/rand32_timer.c b/subsys/random/rand32_timer.c index 76bd228288c..20ba6efec84 100644 --- a/subsys/random/rand32_timer.c +++ b/subsys/random/rand32_timer.c @@ -18,6 +18,7 @@ #include #include #include +#include #if defined(__GNUC__) @@ -45,4 +46,36 @@ u32_t sys_rand32_get(void) 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__ */ diff --git a/subsys/random/rand32_timestamp.c b/subsys/random/rand32_timestamp.c index bb78bd25156..e26d9583f7e 100644 --- a/subsys/random/rand32_timestamp.c +++ b/subsys/random/rand32_timestamp.c @@ -17,6 +17,7 @@ #include #include #include +#include /** * @@ -33,3 +34,36 @@ u32_t sys_rand32_get(void) { 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; + } +} diff --git a/subsys/random/rand32_xoroshiro128.c b/subsys/random/rand32_xoroshiro128.c index ca0d32d58f7..610e9cc3e4c 100644 --- a/subsys/random/rand32_xoroshiro128.c +++ b/subsys/random/rand32_xoroshiro128.c @@ -41,11 +41,10 @@ #include #include #include +#include static u64_t state[2]; -K_SEM_DEFINE(state_sem, 1, 1); - static inline u64_t rotl(const u64_t x, int k) { return (x << k) | (x >> (64 - k)); @@ -72,8 +71,6 @@ static int xoroshiro128_initialize(struct device *dev) return -EINVAL; } - k_object_access_all_grant(&state_sem); - return 0; } @@ -94,22 +91,30 @@ u32_t sys_rand32_get(void) { 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(); - k_sem_give(&state_sem); - 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 * initialized properly before initializing ourselves. */