From 9b1c1a302a221d7c753462cdfaab76a16a5a6f49 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 13 Jan 2025 17:47:42 +0100 Subject: [PATCH] Add CRACEN CTR DRBG random driver Add a new random CTR DRBG driver using the CRACEN HW TRNG and AES-ECB acceleration. Signed-off-by: Alberto Escolar Piedras --- nrfx/drivers/include/nrfx_cracen_ctr_drbg.h | 99 +++++++++ .../src/cracen/nrfx_cracen_cm_aes_ecb.c | 131 +++++++++++ .../src/cracen/nrfx_cracen_cm_aes_ecb.h | 79 +++++++ .../drivers/src/cracen/nrfx_cracen_ctr_drbg.c | 209 ++++++++++++++++++ nrfx/drivers/src/cracen/nrfx_cracen_trng.c | 184 +++++++++++++++ nrfx/drivers/src/cracen/nrfx_cracen_trng.h | 86 +++++++ 6 files changed, 788 insertions(+) create mode 100644 nrfx/drivers/include/nrfx_cracen_ctr_drbg.h create mode 100644 nrfx/drivers/src/cracen/nrfx_cracen_cm_aes_ecb.c create mode 100644 nrfx/drivers/src/cracen/nrfx_cracen_cm_aes_ecb.h create mode 100644 nrfx/drivers/src/cracen/nrfx_cracen_ctr_drbg.c create mode 100755 nrfx/drivers/src/cracen/nrfx_cracen_trng.c create mode 100755 nrfx/drivers/src/cracen/nrfx_cracen_trng.h diff --git a/nrfx/drivers/include/nrfx_cracen_ctr_drbg.h b/nrfx/drivers/include/nrfx_cracen_ctr_drbg.h new file mode 100644 index 00000000..2b23851c --- /dev/null +++ b/nrfx/drivers/include/nrfx_cracen_ctr_drbg.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2025, Nordic Semiconductor ASA + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NRFX_CRACEN_CTR_DRBG_H +#define NRFX_CRACEN_CTR_DRBG_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup nrfx_cracen_ctr_drbg CRACEN CTR DRBG + * @{ + * @ingroup nrfx_cracen_ctr_drbg + * @brief CRACEN CTR DRBG random generator driver + * + */ + +/** + * @brief Initialize the CRACEN CTR DRBG pseudo random generator + * + * @retval NRFX_SUCCESS Initialization was successful. + * @retval NRFX_ERROR_INTERNAL Unexpected error. + * + * @note This function is only meant to be called once. + * + * @note It is not required to call this function before @nrfx_cracen_ctr_drbg_get_random. + * If @ref nrfx_cracen_ctr_drbg_get_random() were to be called without ever calling this, + * the same initialization would be done with its first call. + * But this initialization is relatively slow and power consuming. So this function + * allows initializing in it what may be a less constrained moment. + * + * @note This function assumes exclusive access to the CRACEN TRNG and CryptoMaster, and may + * not be used while any other component is using those peripherals. I.e. this driver + * may not be used together with the nRF security solution. + * + * @note This function is not reentrant. + */ +nrfx_err_t nrfx_cracen_ctr_drbg_init(void); + +/** + * @brief Fill the /p p_buf buffer with /p size bytes of random data + * + * @param[out] p_buf Buffer into which to copy \p size bytes of entropy + * @param[in] size Number of bytes to copy + * + * @retval NRFX_SUCCESS Success + * @retval NRFX_ERROR_INVALID_PARAM Invalid inputs + * @retval NRFX_ERROR_INTERNAL Unexpected error. + * + * @note This function assumes exclusive access to the CRACEN TRNG and CryptoMaster, and may + * not be used while any other component is using those peripherals. I.e. this driver + * may not be used together with the nRF security solution. + * + * @note This function is not reentrant. + */ +nrfx_err_t nrfx_cracen_ctr_drbg_get_random(uint8_t *p_buf, size_t size); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* NRFX_CRACEN_CTR_DRBG_H */ diff --git a/nrfx/drivers/src/cracen/nrfx_cracen_cm_aes_ecb.c b/nrfx/drivers/src/cracen/nrfx_cracen_cm_aes_ecb.c new file mode 100644 index 00000000..65697c5a --- /dev/null +++ b/nrfx/drivers/src/cracen/nrfx_cracen_cm_aes_ecb.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2025, Nordic Semiconductor ASA + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "hal/nrf_cracen.h" +#include "hal/nrf_cracen_cm.h" +#include "helpers/nrf_cracen_cm_dma.h" +#include "soc/nrfx_coredep.h" + +/* + * Check if the CryptoMaster is done + * + * returns 0 if done, -1 if busy, and -2 on error + */ +static int cracen_cm_check_done(void) +{ + uint32_t ret; + uint32_t busy; + + ret = nrf_cracen_cm_int_pending_get(NRF_CRACENCORE); + + if (ret & (NRF_CRACEN_CM_INT_FETCH_ERROR_MASK | NRF_CRACEN_CM_INT_PUSH_ERROR_MASK)) { + return -2; + } + + busy = nrf_cracen_cm_status_get(NRF_CRACENCORE, + (NRF_CRACEN_CM_STATUS_BUSY_FETCH_MASK + | NRF_CRACEN_CM_STATUS_BUSY_PUSH_MASK + | NRF_CRACEN_CM_STATUS_PUSH_WAITING_MASK)); + + if (busy) { + return -1; + } + + return 0; +} + +int nrfx_cracen_cm_aes_ecb(uint8_t *key_p, size_t key_size, uint8_t *input_p, uint8_t *output_p) +{ +#define ECB_BLK_SZ (16U) + + int ret; + + const uint32_t aes_config_value = NRF_CRACEN_CM_AES_CONFIG( + NRF_CRACEN_CM_AES_CONFIG_MODE_ECB, + NRF_CRACEN_CM_AES_CONFIG_KEY_SW_PROGRAMMED, + false, false, false); + + struct nrf_cracen_cm_dma_desc in_descs[3]; + + in_descs[0].p_addr = (uint8_t *)&aes_config_value; + in_descs[0].length = sizeof(aes_config_value) | NRF_CRACEN_CM_DMA_DESC_LENGTH_REALIGN; + in_descs[0].dmatag = NRF_CRACEN_CM_DMA_TAG_AES_CONFIG(NRF_CRACEN_CM_AES_REG_OFFSET_CONFIG); + in_descs[0].p_next = &in_descs[1]; + + in_descs[1].p_addr = key_p; + in_descs[1].length = key_size | NRF_CRACEN_CM_DMA_DESC_LENGTH_REALIGN; + in_descs[1].dmatag = NRF_CRACEN_CM_DMA_TAG_AES_CONFIG(NRF_CRACEN_CM_AES_REG_OFFSET_KEY); + in_descs[1].p_next = &in_descs[2]; + + in_descs[2].p_addr = input_p; + in_descs[2].length = ECB_BLK_SZ | NRF_CRACEN_CM_DMA_DESC_LENGTH_REALIGN; + in_descs[2].dmatag = NRF_CRACEN_CM_DMA_TAG_LAST | NRF_CRACEN_CM_DMA_TAG_ENGINE_AES + | NRF_CRACEN_CM_DMA_TAG_DATATYPE_AES_PAYLOAD; + in_descs[2].p_next = NRF_CRACEN_CM_DMA_DESC_STOP; + + struct nrf_cracen_cm_dma_desc out_desc; + + out_desc.p_addr = output_p; + out_desc.length = ECB_BLK_SZ | NRF_CRACEN_CM_DMA_DESC_LENGTH_REALIGN; + out_desc.p_next = NRF_CRACEN_CM_DMA_DESC_STOP; + out_desc.dmatag = NRF_CRACEN_CM_DMA_TAG_LAST; + + nrf_cracen_module_enable(NRF_CRACEN, CRACEN_ENABLE_CRYPTOMASTER_Msk); + + nrf_cracen_cm_fetch_addr_set(NRF_CRACENCORE, (void *)in_descs); + nrf_cracen_cm_push_addr_set(NRF_CRACENCORE, (void *)&out_desc); + + nrf_cracen_cm_config_indirect_set(NRF_CRACENCORE, NRF_CRACEN_CM_CONFIG_INDIRECT_FETCH_MASK + | NRF_CRACEN_CM_CONFIG_INDIRECT_PUSH_MASK); + + __DMB(); + + nrf_cracen_cm_start(NRF_CRACENCORE); + + do { + /* The HW is so fast that it is better to "busy wait" here than program an + * interrupt. This will normally already succeed in the first try + */ +#if defined(CONFIG_SOC_SERIES_BSIM_NRFXX) + nrfx_coredep_delay_us(1); +#endif + ret = cracen_cm_check_done(); + } while (ret == -1); + + nrf_cracen_cm_softreset(NRF_CRACENCORE); + nrf_cracen_module_disable(NRF_CRACEN, CRACEN_ENABLE_CRYPTOMASTER_Msk); + + return ret; +} diff --git a/nrfx/drivers/src/cracen/nrfx_cracen_cm_aes_ecb.h b/nrfx/drivers/src/cracen/nrfx_cracen_cm_aes_ecb.h new file mode 100644 index 00000000..feed56ef --- /dev/null +++ b/nrfx/drivers/src/cracen/nrfx_cracen_cm_aes_ecb.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025, Nordic Semiconductor ASA + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NRFX_CRACEN_CM_AES_ECB_H +#define NRFX_CRACEN_CM_AES_ECB_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file + * + * Minimal driver for the CRACEN CryptoMaster AES ECB for the cracen_ctr_drbg driver + */ + +/** + * Encrypt with AES-ECB the input data using the CRACEN CryptoMaster module + * + * @param[in] key_p Pointer to the key + * @param[in] key_size Size of the key in bytes (valid sizes 16, 24 or 32 => 128, 192 or 256 bits) + * @param[in] input_p Pointer to the input data (16 bytes/128 bits) + * @param[in] output_p Pointer to the output data (16 bytes/128 bits) + * + * @return 0 on success, a negative number on failure + * + * @note The key, input and output data are in big endian/cryptographic order. That is, input[0] + * corresponds to the highest byte of the 128bit input. + * + * @note The only failure one can normally expect are bus failures due to incorrect pointers. + * + * @note This function is meant to be used by the nrfx_random_ctr_drbg driver. + * If using it outside of this driver it must be used with care specially if any other + * component is using CRACEN. + * It may not be used if any other component is using the CRACEN CM at the same time. + * + * @note This function is not reentrant. + * + * @note The key size needs to be supported by the CRACEN CryptoMaster AES engine. + */ +int nrfx_cracen_cm_aes_ecb(uint8_t *key_p, size_t key_size, uint8_t *input_p, uint8_t *output_p); + +#ifdef __cplusplus +} +#endif + +#endif /* NRFX_CRACEN_CM_AES_ECB_H */ diff --git a/nrfx/drivers/src/cracen/nrfx_cracen_ctr_drbg.c b/nrfx/drivers/src/cracen/nrfx_cracen_ctr_drbg.c new file mode 100644 index 00000000..a421b72b --- /dev/null +++ b/nrfx/drivers/src/cracen/nrfx_cracen_ctr_drbg.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2025, Nordic Semiconductor ASA + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include "nrfx_cracen_trng.h" +#include "nrfx_cracen_cm_aes_ecb.h" + +#define MAX_BYTES_PER_REQUEST (1 << 16) /* NIST.SP.800-90Ar1:Table 3 */ +#define RESEED_INTERVAL ((uint64_t)1 << 48) /* 2^48 as per NIST spec */ +#define KEY_SIZE 32U /* 256 bits AES Key */ +#define AES_BLK_SZ 16U /* 128 bits */ +#define ENTROPY_SIZE (KEY_SIZE + AES_BLK_SZ) /* Seed equals key-len + 16 */ + +/** @brief Internal status of this PRNG driver */ +struct cracen_prng_status { + uint8_t key[KEY_SIZE]; + uint8_t V[AES_BLK_SZ]; + uint64_t reseed_counter; + bool initialized; +}; +static struct cracen_prng_status prng; + +/** + * Increment by 1 a number stored in memory in big endian representation. + * /p v is a pointer to the first byte storing the number. + * /p size is the size of the number. + */ +static void be_incr(unsigned char *v, size_t size) +{ + unsigned int add = 1; + + do { + size--; + add += v[size]; + v[size] = add & 0xFF; + add >>= 8; + } while ((add != 0) && (size > 0)); +} + +/* + * XOR two arrays of /p size bytes. + * /p size must be a multiple of 4. + */ +static void xor_array(uint32_t *a, const uint32_t *b, size_t size) +{ + uintptr_t end = (uintptr_t)a + size; + + for (; (uintptr_t)a < end; a++, b++) { + *a = *a ^ *b; + } +} + +/* + * Implementation of the CTR_DRBG_Update process as described in NIST.SP.800-90Ar1 + * with ctr_len equal to blocklen. + * Returns 0 on success, -1 on error + */ +static int ctr_drbg_update(uint8_t *data) +{ + int r = 0; + char temp[ENTROPY_SIZE]; + size_t temp_length = 0; + + while (temp_length < sizeof(temp)) { + be_incr(prng.V, AES_BLK_SZ); + + r = nrfx_cracen_cm_aes_ecb(prng.key, sizeof(prng.key), prng.V, temp + temp_length); + + if (r != 0) { + return -1; + } + temp_length += AES_BLK_SZ; + } + + if (data) { + xor_array((uint32_t *)temp, (uint32_t *)data, sizeof(temp)); + } + + memcpy(prng.key, temp, sizeof(prng.key)); + memcpy(prng.V, temp + sizeof(prng.key), sizeof(prng.V)); + + return 0; +} + +/* + * Re-seed the CTR DRBG + * + * return 0 on success, -1 on error + */ +static int cracen_ctr_drbg_reseed(void) +{ + int r; + char entropy[ENTROPY_SIZE]; + + /* Get the entropy used to seed the DRBG */ + r = nrfx_cracen_rng_get_entropy(entropy, sizeof(entropy)); + if (r != 0) { + return -1; + } + + r = ctr_drbg_update(entropy); + if (r != 0) { + return -1; + } + + prng.reseed_counter = 1; + + return 0; +} + +nrfx_err_t nrfx_cracen_ctr_drbg_init(void) { + int r; + + memset(&prng, 0, sizeof(prng)); + + r = cracen_ctr_drbg_reseed(); + if (r != 0) { + return NRFX_ERROR_INTERNAL; + } + + prng.initialized = 1; + return 0; +} + +nrfx_err_t nrfx_cracen_ctr_drbg_get_random(uint8_t *p_buf, size_t size) +{ + int r = 0; + + if (size > 0 && p_buf == NULL) { + return NRFX_ERROR_INVALID_PARAM; + } + + if (size > MAX_BYTES_PER_REQUEST ) { + return NRFX_ERROR_INVALID_PARAM; + } + + if (!prng.initialized) { + r = nrfx_cracen_ctr_drbg_init(); + if (r != 0) { + return NRFX_ERROR_INTERNAL; + } + } + + if (prng.reseed_counter >= RESEED_INTERVAL) { + r = cracen_ctr_drbg_reseed(); + if (r != 0) { + return NRFX_ERROR_INTERNAL; + } + } + + while (size > 0) { + char temp[AES_BLK_SZ]; + size_t cur_len = (size < AES_BLK_SZ) ? size : AES_BLK_SZ; + + be_incr(prng.V, AES_BLK_SZ); + + r = nrfx_cracen_cm_aes_ecb(prng.key, sizeof(prng.key), prng.V, temp); + if (r != 0) { + return NRFX_ERROR_INTERNAL; + } + + memcpy(p_buf, temp, cur_len); + + size -= cur_len; + p_buf += cur_len; + } + + r = ctr_drbg_update(NULL); + if (r != 0) { + return NRFX_ERROR_INTERNAL; + } + + prng.reseed_counter += 1; + + return NRFX_SUCCESS; +} diff --git a/nrfx/drivers/src/cracen/nrfx_cracen_trng.c b/nrfx/drivers/src/cracen/nrfx_cracen_trng.c new file mode 100755 index 00000000..da9a3592 --- /dev/null +++ b/nrfx/drivers/src/cracen/nrfx_cracen_trng.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2025, Nordic Semiconductor ASA + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "hal/nrf_cracen.h" +#include "hal/nrf_cracen_rng.h" +#include "soc/nrfx_coredep.h" + +/* TRNG HW chosen configuration options */ +#define TRNG_CLK_DIV 0 +#define TRNG_OFF_TIMER_VAL 0 +#define TRNG_INIT_WAIT_VAL 512 +#define TRNG_NUMBER_128BIT_BLOCKS 4 + +#define CONDITIONING_KEY_SIZE 4 /* Size of the conditioning key: 4 words, 16 bytes */ + +/* Return values common between these internal functions: */ +#define OK 0 /* The function or operation succeeded */ +#define HW_PROCESSING -1 /* Waiting for the hardware to produce data */ +#define ERR_TOO_BIG -2 /* Requested size too large */ +#define TRNG_RESET_NEEDED -5 /* Reset needed */ + +static bool conditioning_key_set; + +/* + * Initialize the TRNG HW and this driver status + */ +static void cracen_trng_init(void) +{ + conditioning_key_set = false; + + /* Disable and softreset the RNG */ + const nrf_cracen_rng_control_t control_reset = {.soft_reset = true}; + + nrf_cracen_rng_control_set(NRF_CRACENCORE, &control_reset); + + /* Change from configuration defaults to what we prefer: */ + nrf_cracen_rng_off_timer_set(NRF_CRACENCORE, TRNG_OFF_TIMER_VAL); + nrf_cracen_rng_clk_div_set(NRF_CRACENCORE, TRNG_CLK_DIV); + nrf_cracen_rng_init_wait_val_set(NRF_CRACENCORE, TRNG_INIT_WAIT_VAL); + + /* Configure the control register and enable */ + const nrf_cracen_rng_control_t control_enable = { + .number_128_blocks = TRNG_NUMBER_128BIT_BLOCKS, + .enable = true + }; + + nrf_cracen_rng_control_set(NRF_CRACENCORE, &control_enable); +} + +/* + * Set the TRNG HW conditioning key. + * + * If there is not yet enough data to do so, return HW_PROCESSING + * otherwise return OK. + */ +static int cracen_trng_setup_conditioning_key(void) +{ + uint32_t level = nrf_cracen_rng_fifo_level_get(NRF_CRACENCORE); + + if (level < CONDITIONING_KEY_SIZE) { + return HW_PROCESSING; + } + + for (size_t i = 0; i < CONDITIONING_KEY_SIZE; i++) { + uint32_t key; + key = nrf_cracen_rng_fifo_get(NRF_CRACENCORE); + nrf_cracen_rng_key_set(NRF_CRACENCORE, i, key); + } + + conditioning_key_set = true; + + return OK; +} + +/* + * If the TRNG HW detected the entropy quality was not ok, return TRNG_RESET_NEEDED + * If the HW is still starting or there is not enough data, return HW_PROCESSING + * If the conditioning key is not yet setup, attempt to fill it or return HW_PROCESSING if + * we don't have enough data to fill it yet. + * If enough data is ready, fill the /p dst buffer with /p size bytes and return OK + */ +static int cracen_trng_get(char *dst, size_t size) +{ + /* Check that startup tests did not fail and we are ready to read data */ + switch (nrf_cracen_rng_fsm_state_get(NRF_CRACENCORE)) { + case CRACENCORE_RNGCONTROL_STATUS_STATE_ERROR: + return TRNG_RESET_NEEDED; + break; + case CRACENCORE_RNGCONTROL_STATUS_STATE_RESET: + return HW_PROCESSING; + break; + case CRACENCORE_RNGCONTROL_STATUS_STATE_STARTUP: + default: + break; + } + + /* Program random key for the conditioning function */ + if (!conditioning_key_set) { + int status = cracen_trng_setup_conditioning_key(); + + if (status != OK) { + return status; + } + } + + uint32_t level = nrf_cracen_rng_fifo_level_get(NRF_CRACENCORE); + + if (size > level * 4) { /* FIFO level in 4-byte words */ + return HW_PROCESSING; + } + + while (size) { + uint32_t data = nrf_cracen_rng_fifo_get(NRF_CRACENCORE); + + for (int i = 0; i < 4 && size; i++, size--) { + *dst = (char)(data & 0xFF); + dst++; + data >>= 8; + } + } + + return OK; +} + +int nrfx_cracen_rng_get_entropy(uint8_t *p_buf, size_t size) +{ + /* Block sizes above the FIFO wakeup level to guarantee that the + * hardware will be able at some time to provide the requested bytes. */ + if (size > (CRACENCORE_RNGCONTROL_FIFOTHRESHOLD_ResetValue + 1) * 16) { + return ERR_TOO_BIG; + } + + nrf_cracen_module_enable(NRF_CRACEN, CRACEN_ENABLE_RNG_Msk); + + int ret = TRNG_RESET_NEEDED; + + while (true) { + if (ret == TRNG_RESET_NEEDED) { + cracen_trng_init(); + } + ret = cracen_trng_get(p_buf, size); + if (ret == OK) { + break; + } +#if defined(CONFIG_SOC_SERIES_BSIM_NRFXX) + nrfx_coredep_delay_us(1); +#endif + } + + nrf_cracen_module_disable(NRF_CRACEN, CRACEN_ENABLE_RNG_Msk); + + return OK; +} diff --git a/nrfx/drivers/src/cracen/nrfx_cracen_trng.h b/nrfx/drivers/src/cracen/nrfx_cracen_trng.h new file mode 100755 index 00000000..2ddf2e57 --- /dev/null +++ b/nrfx/drivers/src/cracen/nrfx_cracen_trng.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025, Nordic Semiconductor ASA + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NRFX_CRACEN_TRNG_H +#define NRFX_CRACEN_TRNG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/** + * @file + * + * Minimal driver for the CRACEN TRNG for the nrfx_cracen_ctr_drbg driver + */ + +/** + * @brief Fill a buffer with entropy from the CRACEN TRNG + * + * When this function returns 0, \p size random bytes have been written to \p p_buf. + * + * Up to 64 bytes can be requested. + * If more is requested the function will return -2 without copying any data + * + * The entropy generated by this function is NIST800-90B and AIS31 compliant, and can be used to + * seed FIPS 140-2 compliant pseudo random number generators. + * + * @param[out] p_buf Buffer into which to copy \p size bytes of entropy + * @param[in] size Number of bytes to copy + * + * @return 0 on success, a negative number on error + * + * @note This function is blocking. It will take around a couple of tenths of microseconds to + * complete depending on the amount of bytes requested. + * (~40 microseconds for an nRF54L15 the maximum 64bytes) + * + * @note Note this is a quite power hungry operation. + * + * @note This function will enable and configure the CRACEN TRNG HW, wait until the entropy has been + * generated, copy it to the destination buffer and disable the HW. + * This function is meant as as internal utility of this driver but may be used by others with + * extra care, specially if some other component is using CRACEN. + * It may not be used if any other component is using the CRACEN TRNG at the same time. + * + * @note This function is not reentrant. + */ +int nrfx_cracen_rng_get_entropy(uint8_t *p_buf, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* NRFX_CRACEN_TRNG_H */