Convenience function to fill a buffer with random bytes.
Add some unit tests (only sanity checks, really.)
#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.)
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)
{
#include <stdint.h>
#include <stddef.h>
#include <string.h>
+#include <sys/param.h>
#include "esp_attr.h"
#include "esp_clk.h"
#include "soc/wdev_reg.h"
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;
+ }
+}
/**
* @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.
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#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]);
+ }
+}
+
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);
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";
#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";
.random = esp_random,
.stir = NULL,
.uniform = NULL,
- .buf = randombytes_esp32_random_buf,
+ .buf = esp_fill_random,
.close = NULL,
};
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
+#include <esp_system.h>
-#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
+
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;
}
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;
}
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 );
}
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));
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);
}