diff --git a/components/esp_hw_support/port/linux/esp_random.c b/components/esp_hw_support/port/linux/esp_random.c index 71f2013f82..e1dc505a2e 100644 --- a/components/esp_hw_support/port/linux/esp_random.c +++ b/components/esp_hw_support/port/linux/esp_random.c @@ -1,40 +1,38 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include -#include +#include #include #include -#include -#include +#include #include "esp_log.h" -static const char* TAG = "esp-random"; +#define GETENTROPY_MAX_LEN 256 -static void __attribute__((constructor)) esp_random_init(void) -{ - srand(time(NULL)); - ESP_LOGW(TAG, "esp_random do not provide a cryptographically secure numbers on Linux, and should never be used for anything security related"); -} +static void __attribute__((constructor)) esp_random_init(void) { } uint32_t esp_random(void) { - /* Adding INT32_MAX to shift the results such that after conversion to uint32_t we still get 32 bits of random data */ - return (rand() + INT32_MAX); + uint32_t random_number; + assert(getentropy(&random_number, sizeof(random_number)) == 0); + return random_number; } void esp_fill_random(void *buf, size_t len) { assert(buf != NULL); - uint8_t *buf_bytes = (uint8_t *)buf; - while (len > 0) { - uint32_t word = esp_random(); - uint32_t to_copy = MIN(sizeof(word), len); - memcpy(buf_bytes, &word, to_copy); - buf_bytes += to_copy; - len -= to_copy; + + // Note that we can't use getentropy() with len > 256 directly (see getentropy man page), + // hence reading in chunks + const size_t FULL_CHUNKS_NUM = (len / GETENTROPY_MAX_LEN); + const size_t REST_CHUNK_SIZE = len % GETENTROPY_MAX_LEN; + + for (size_t chunk_num = 0; chunk_num < FULL_CHUNKS_NUM; chunk_num++) { + assert(getentropy(buf + chunk_num * GETENTROPY_MAX_LEN, GETENTROPY_MAX_LEN) == 0); } + + assert(getentropy(buf + FULL_CHUNKS_NUM * GETENTROPY_MAX_LEN, REST_CHUNK_SIZE) == 0); } diff --git a/components/esp_hw_support/test_apps/host_test_linux/main/test_hw_support_linux.c b/components/esp_hw_support/test_apps/host_test_linux/main/test_hw_support_linux.c index eeaef0966c..26839c069a 100644 --- a/components/esp_hw_support/test_apps/host_test_linux/main/test_hw_support_linux.c +++ b/components/esp_hw_support/test_apps/host_test_linux/main/test_hw_support_linux.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,13 +8,13 @@ #include "unity.h" #include "esp_random.h" -/* Note: these are just sanity tests, the implementation of esp_random do not produce cryptographically secure numbers on Linux +/* Note: these are just sanity tests, the implementation of esp_random() relies on getentropy() on Linux. */ +const size_t NUM_RANDOM = 128; /* in most cases this is massive overkill */ + TEST_CASE("call esp_random()", "[random]") { - const size_t NUM_RANDOM = 128; /* in most cases this is massive overkill */ - uint32_t zeroes = UINT32_MAX; uint32_t ones = 0; for (int i = 0; i < NUM_RANDOM - 1; i++) { @@ -69,10 +69,62 @@ TEST_CASE("call esp_fill_random()", "[random]") } } +TEST_CASE("esp_fill_random() fills exactly one byte", "[random]") +{ + const size_t BUF_SZ = 2; + uint8_t buf[BUF_SZ]; + uint8_t one_buf[BUF_SZ]; + bzero(one_buf, BUF_SZ); + for (size_t i = 0; i < NUM_RANDOM - 1; i++) { + esp_fill_random(buf, BUF_SZ - 1); + for (size_t j = 0; j < BUF_SZ - 1; j++) { + one_buf[j] |= buf[j]; + } + } + TEST_ASSERT_EQUAL(0, one_buf[BUF_SZ - 1]); + TEST_ASSERT_GREATER_THAN(0, one_buf[BUF_SZ - 2]); +} + +// The underlying system call accepts max 256 bytes, test that esp_fill_random() can read more +TEST_CASE("esp_fill_random() fills exactly 256 bytes", "[random]") +{ + const size_t BUF_SZ = 257; + uint8_t buf[BUF_SZ]; + uint8_t one_buf[BUF_SZ]; + bzero(one_buf, BUF_SZ); + for (size_t i = 0; i < NUM_RANDOM - 1; i++) { + esp_fill_random(buf, BUF_SZ - 1); + for (size_t j = 0; j < BUF_SZ - 1; j++) { + one_buf[j] |= buf[j]; + } + } + + TEST_ASSERT_EQUAL(0, one_buf[BUF_SZ - 1]); + TEST_ASSERT_GREATER_THAN(0, one_buf[BUF_SZ - 2]); + TEST_ASSERT_GREATER_THAN(0, one_buf[0]); +} + +TEST_CASE("esp_fill_random() fills exactly 257 bytes", "[random]") +{ + const size_t BUF_SZ = 258; + uint8_t buf[BUF_SZ]; + uint8_t one_buf[BUF_SZ]; + bzero(one_buf, BUF_SZ); + for (size_t i = 0; i < NUM_RANDOM - 1; i++) { + esp_fill_random(buf, BUF_SZ - 1); + for (size_t j = 0; j < BUF_SZ - 1; j++) { + one_buf[j] |= buf[j]; + } + } + + TEST_ASSERT_EQUAL(0, one_buf[BUF_SZ - 1]); + TEST_ASSERT_GREATER_THAN(0, one_buf[BUF_SZ - 2]); + TEST_ASSERT_GREATER_THAN(0, one_buf[0]); +} void app_main(void) { - printf("Running heap linux API host test app"); + printf("Running hw support linux API host test app"); unity_run_menu(); }