From 767ec2735055d5d5f6d8556a1a564fec2024c3b6 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 15 Aug 2018 17:25:19 +1000 Subject: [PATCH 1/2] bootloader_support: Move bootloader_random.h to public header directory --- .../{include_bootloader => include}/bootloader_random.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename components/bootloader_support/{include_bootloader => include}/bootloader_random.h (100%) diff --git a/components/bootloader_support/include_bootloader/bootloader_random.h b/components/bootloader_support/include/bootloader_random.h similarity index 100% rename from components/bootloader_support/include_bootloader/bootloader_random.h rename to components/bootloader_support/include/bootloader_random.h From 83a179abb0d2bd0bfd50da71edaa63ea1add0071 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 15 Aug 2018 18:20:16 +1000 Subject: [PATCH 2/2] esp32: Add esp_fill_random() function Convenience function to fill a buffer with random bytes. Add some unit tests (only sanity checks, really.) --- .../src/bootloader_random.c | 16 +++-- components/esp32/hw_random.c | 14 ++++ components/esp32/include/esp_system.h | 23 +++++-- components/esp32/test/test_random.c | 67 +++++++++++++++++++ components/fatfs/test/test_fatfs_sdmmc.c | 4 +- components/fatfs/test/test_fatfs_spiflash.c | 4 +- components/libsodium/port/randombytes_esp32.c | 10 +-- components/mbedtls/port/esp_hardware.c | 11 +-- components/newlib/random.c | 15 +---- components/wpa_supplicant/port/os_xtensa.c | 19 +----- .../bluetooth/blufi/main/blufi_security.c | 6 +- .../wifi/espnow/main/espnow_example_main.c | 6 +- 12 files changed, 124 insertions(+), 71 deletions(-) create mode 100644 components/esp32/test/test_random.c diff --git a/components/bootloader_support/src/bootloader_random.c b/components/bootloader_support/src/bootloader_random.c index 36628e6c4..eb34d6add 100644 --- a/components/bootloader_support/src/bootloader_random.c +++ b/components/bootloader_support/src/bootloader_random.c @@ -23,19 +23,23 @@ #ifndef BOOTLOADER_BUILD #include "esp_system.h" -#endif +void bootloader_fill_random(void *buffer, size_t length) +{ + return esp_fill_random(buffer, length); +} + +#else void bootloader_fill_random(void *buffer, size_t length) { uint8_t *buffer_bytes = (uint8_t *)buffer; uint32_t random; -#ifdef BOOTLOADER_BUILD uint32_t start, now; -#endif + + assert(buffer != NULL); for (int i = 0; i < length; i++) { if (i == 0 || i % 4 == 0) { /* redundant check is for a compiler warning */ -#ifdef BOOTLOADER_BUILD /* in bootloader with ADC feeding HWRNG, we accumulate 1 bit of entropy per 40 APB cycles (==80 CPU cycles.) @@ -49,14 +53,12 @@ void bootloader_fill_random(void *buffer, size_t length) random ^= REG_READ(WDEV_RND_REG); RSR(CCOUNT, now); } while(now - start < 80*32*2); /* extra factor of 2 is precautionary */ -#else - random = esp_random(); -#endif } buffer_bytes[i] = random >> ((i % 4) * 8); } } +#endif // BOOTLOADER_BUILD void bootloader_random_enable(void) { diff --git a/components/esp32/hw_random.c b/components/esp32/hw_random.c index 78ad542fc..1bd0e6300 100644 --- a/components/esp32/hw_random.c +++ b/components/esp32/hw_random.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "esp_attr.h" #include "esp_clk.h" #include "soc/wdev_reg.h" @@ -54,3 +55,16 @@ uint32_t IRAM_ATTR esp_random(void) last_ccount = ccount; return result ^ REG_READ(WDEV_RND_REG); } + +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; + } +} diff --git a/components/esp32/include/esp_system.h b/components/esp32/include/esp_system.h index b43dbebb8..05214c8f5 100644 --- a/components/esp32/include/esp_system.h +++ b/components/esp32/include/esp_system.h @@ -151,18 +151,31 @@ uint32_t esp_get_minimum_free_heap_size( void ); /** * @brief Get one random 32-bit word from hardware RNG * - * The hardware RNG is fully functional whenever an RF subsystem is running (ie Bluetooth or WiFi is enabled). For secure + * The hardware RNG is fully functional whenever an RF subsystem is running (ie Bluetooth or WiFi is enabled). For * random values, call this function after WiFi or Bluetooth are started. * - * When the app is running without an RF subsystem enabled, it should be considered a PRNG. To help improve this - * situation, the RNG is pre-seeded with entropy while the IDF bootloader is running. However no new entropy is - * available during the window of time between when the bootloader exits and an RF subsystem starts. It may be possible - * to discern a non-random pattern in a very large amount of output captured during this window of time. + * If the RF subsystem is not used by the program, the function bootloader_random_enable() can be called to enable an + * entropy source. bootloader_random_disable() must be called before RF subsystem or I2S peripheral are used. See these functions' + * documentation for more details. + * + * Any time the app is running without an RF subsystem (or bootloader_random) enabled, RNG hardware should be + * considered a PRNG. A very small amount of entropy is available due to pre-seeding while the IDF + * bootloader is running, but this should not be relied upon for any use. * * @return Random value between 0 and UINT32_MAX */ uint32_t esp_random(void); +/** + * @brief Fill a buffer with random bytes from hardware RNG + * + * @note This function has the same restrictions regarding available entropy as esp_random() + * + * @param buf Pointer to buffer to fill with random numbers. + * @param len Length of buffer in bytes + */ +void esp_fill_random(void *buf, size_t len); + /** * @brief Set base MAC address with the MAC address which is stored in BLK3 of EFUSE or * external storage e.g. flash and EEPROM. diff --git a/components/esp32/test/test_random.c b/components/esp32/test/test_random.c new file mode 100644 index 000000000..b0ce1a039 --- /dev/null +++ b/components/esp32/test/test_random.c @@ -0,0 +1,67 @@ +#include +#include +#include "unity.h" +#include "esp_system.h" + +/* Note: these are just sanity tests, not the same as + entropy tests +*/ + +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++) { + uint32_t r = esp_random(); + ones |= r; + zeroes &= ~r; + } + + /* assuming a 'white' random distribution, we can expect + usually at least one time each bit will be zero and at + least one time each will be one. Statistically this + can still fail, just *very* unlikely to. */ + TEST_ASSERT_EQUAL_HEX32(0, zeroes); + TEST_ASSERT_EQUAL_HEX32(UINT32_MAX, ones); +} + +TEST_CASE("call esp_fill_random()", "[random]") +{ + const size_t NUM_BUF = 200; + const size_t BUF_SZ = 16; + uint8_t buf[NUM_BUF][BUF_SZ]; + uint8_t zero_buf[BUF_SZ]; + uint8_t one_buf[BUF_SZ]; + + bzero(buf, sizeof(buf)); + bzero(one_buf, sizeof(zero_buf)); + memset(zero_buf, 0xFF, sizeof(one_buf)); + + for (int i = 0; i < NUM_BUF; i++) { + esp_fill_random(buf[i], BUF_SZ); + } + /* No two 128-bit buffers should be the same + (again, statistically this could happen but it's very unlikely) */ + for (int i = 0; i < NUM_BUF; i++) { + for (int j = 0; j < NUM_BUF; j++) { + if (i != j) { + TEST_ASSERT_NOT_EQUAL(0, memcmp(buf[i], buf[j], BUF_SZ)); + } + } + } + + /* Do the same all bits are zero and one at least once test across the buffers */ + for (int i = 0; i < NUM_BUF; i++) { + for (int x = 0; x < BUF_SZ; x++) { + zero_buf[x] &= ~buf[i][x]; + one_buf[x] |= buf[i][x]; + } + } + for (int x = 0; x < BUF_SZ; x++) { + TEST_ASSERT_EQUAL_HEX8(0, zero_buf[x]); + TEST_ASSERT_EQUAL_HEX8(0xFF, one_buf[x]); + } +} + diff --git a/components/fatfs/test/test_fatfs_sdmmc.c b/components/fatfs/test/test_fatfs_sdmmc.c index 2ab31f087..74ef2207b 100644 --- a/components/fatfs/test/test_fatfs_sdmmc.c +++ b/components/fatfs/test/test_fatfs_sdmmc.c @@ -167,9 +167,7 @@ TEST_CASE("(SD) write/read speed test", "[fatfs][sd][test_env=UT_T1_SDMODE][time const size_t buf_size = 16 * 1024; uint32_t* buf = (uint32_t*) calloc(1, buf_size); - for (size_t i = 0; i < buf_size / 4; ++i) { - buf[i] = esp_random(); - } + esp_fill_random(buf, buf_size); const size_t file_size = 1 * 1024 * 1024; speed_test(buf, 4 * 1024, file_size, true); diff --git a/components/fatfs/test/test_fatfs_spiflash.c b/components/fatfs/test/test_fatfs_spiflash.c index 38ea765dd..9d0724948 100644 --- a/components/fatfs/test/test_fatfs_spiflash.c +++ b/components/fatfs/test/test_fatfs_spiflash.c @@ -162,9 +162,7 @@ TEST_CASE("(WL) write/read speed test", "[fatfs][wear_levelling][timeout=60]") const size_t buf_size = 16 * 1024; uint32_t* buf = (uint32_t*) calloc(1, buf_size); - for (size_t i = 0; i < buf_size / 4; ++i) { - buf[i] = esp_random(); - } + esp_fill_random(buf, buf_size); const size_t file_size = 256 * 1024; const char* file = "/spiflash/256k.bin"; diff --git a/components/libsodium/port/randombytes_esp32.c b/components/libsodium/port/randombytes_esp32.c index 9ff5493cc..73c77ec69 100644 --- a/components/libsodium/port/randombytes_esp32.c +++ b/components/libsodium/port/randombytes_esp32.c @@ -14,14 +14,6 @@ #include "randombytes_default.h" #include "esp_system.h" -static void randombytes_esp32_random_buf(void * const buf, const size_t size) -{ - uint8_t *p = (uint8_t *)buf; - for (size_t i = 0; i < size; i++) { - p[i] = esp_random(); - } -} - static const char *randombytes_esp32_implementation_name(void) { return "esp32"; @@ -39,7 +31,7 @@ const struct randombytes_implementation randombytes_esp32_implementation = { .random = esp_random, .stir = NULL, .uniform = NULL, - .buf = randombytes_esp32_random_buf, + .buf = esp_fill_random, .close = NULL, }; diff --git a/components/mbedtls/port/esp_hardware.c b/components/mbedtls/port/esp_hardware.c index 915766249..09ededb18 100644 --- a/components/mbedtls/port/esp_hardware.c +++ b/components/mbedtls/port/esp_hardware.c @@ -7,17 +7,18 @@ #include #include #include +#include -#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) +#ifndef MBEDTLS_ENTROPY_HARDWARE_ALT +#error "MBEDTLS_ENTROPY_HARDWARE_ALT should always be set in ESP-IDF" +#endif -extern int os_get_random(unsigned char *buf, size_t len); int mbedtls_hardware_poll( void *data, unsigned char *output, size_t len, size_t *olen ) { - os_get_random(output, len); + esp_fill_random(output, len); *olen = len; - return 0; } -#endif + diff --git a/components/newlib/random.c b/components/newlib/random.c index 47ebb23ca..5d3e6175c 100644 --- a/components/newlib/random.c +++ b/components/newlib/random.c @@ -36,17 +36,8 @@ ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) return -1; } - uint8_t *dst = (uint8_t *) buf; - ssize_t ret = 0; + esp_fill_random(buf, buflen); - while (ret < buflen) { - const uint32_t random = esp_random(); - const int needed = buflen - ret; - const int copy_len = MIN(sizeof(random), needed); - memcpy(dst + ret, &random, copy_len); - ret += copy_len; - } - - ESP_LOGD(TAG, "getrandom returns %d", ret); - return ret; + ESP_LOGD(TAG, "getrandom returns %d", buflen); + return buflen; } diff --git a/components/wpa_supplicant/port/os_xtensa.c b/components/wpa_supplicant/port/os_xtensa.c index 9ecde1f11..7c2177c4d 100644 --- a/components/wpa_supplicant/port/os_xtensa.c +++ b/components/wpa_supplicant/port/os_xtensa.c @@ -39,26 +39,9 @@ unsigned long os_random(void) return esp_random(); } -unsigned long r_rand(void) __attribute__((alias("os_random"))); - - int os_get_random(unsigned char *buf, size_t len) { - int i, j; - unsigned long tmp; - - for (i = 0; i < ((len + 3) & ~3) / 4; i++) { - tmp = r_rand(); - - for (j = 0; j < 4; j++) { - if ((i * 4 + j) < len) { - buf[i * 4 + j] = (uint8_t)(tmp >> (j * 8)); - } else { - break; - } - } - } - + esp_fill_random(buf, len); return 0; } diff --git a/examples/bluetooth/blufi/main/blufi_security.c b/examples/bluetooth/blufi/main/blufi_security.c index c32d3ad49..49ba6c1c6 100644 --- a/examples/bluetooth/blufi/main/blufi_security.c +++ b/examples/bluetooth/blufi/main/blufi_security.c @@ -61,11 +61,7 @@ static struct blufi_security *blufi_sec; static int myrand( void *rng_state, unsigned char *output, size_t len ) { - size_t i; - - for( i = 0; i < len; ++i ) - output[i] = esp_random(); - + esp_fill_random(output, len); return( 0 ); } diff --git a/examples/wifi/espnow/main/espnow_example_main.c b/examples/wifi/espnow/main/espnow_example_main.c index afb1428c5..c4e949bff 100644 --- a/examples/wifi/espnow/main/espnow_example_main.c +++ b/examples/wifi/espnow/main/espnow_example_main.c @@ -144,7 +144,6 @@ int example_espnow_data_parse(uint8_t *data, uint16_t data_len, uint8_t *state, void example_espnow_data_prepare(example_espnow_send_param_t *send_param) { example_espnow_data_t *buf = (example_espnow_data_t *)send_param->buffer; - int i = 0; assert(send_param->len >= sizeof(example_espnow_data_t)); @@ -153,9 +152,8 @@ void example_espnow_data_prepare(example_espnow_send_param_t *send_param) buf->seq_num = s_example_espnow_seq[buf->type]++; buf->crc = 0; buf->magic = send_param->magic; - for (i = 0; i < send_param->len - sizeof(example_espnow_data_t); i++) { - buf->payload[i] = (uint8_t)esp_random(); - } + /* Fill all remaining bytes after the data with random values */ + esp_fill_random(buf->payload, send_param->len - sizeof(example_espnow_data_t)); buf->crc = crc16_le(UINT16_MAX, (uint8_t const *)buf, send_param->len); }