diff --git a/components/bootloader_support/include/bootloader_random.h b/components/bootloader_support/include/bootloader_random.h index 0c7b61eb9b..268857dd6f 100644 --- a/components/bootloader_support/include/bootloader_random.h +++ b/components/bootloader_support/include/bootloader_random.h @@ -21,33 +21,38 @@ extern "C" { #endif /** - * @brief Enable early entropy source for RNG + * @brief Enable an entropy source for RNG if RF is disabled * - * Uses the SAR ADC to feed entropy into the HWRNG. The ADC is put - * into a test mode that reads an internal reference voltage and - * constantly feeds the LSB of data into the HWRNG. Consult the - * SoC Technical Reference Manual for more information. + * The exact internal entropy source mechanism depends on the chip in use but + * all SoCs use the SAR ADC to continuously mix random bits (an internal + * noise reading) into the HWRNG. Consult the SoC Technical Reference + * Manual for more information. * * Can also be used from app code early during operation, if true - * random numbers are required before WiFi stack is initialised. - * Call this function from app code only if WiFi/BT are not yet - * enabled and I2S and ADC are not in use. - * - * Call bootloader_random_disable() when done. + * random numbers are required before RF is initialised. Consult + * ESP-IDF Programming Guide "Random Number Generation" section for + * details. */ void bootloader_random_enable(void); /** - * @brief Disable early entropy source for RNG + * @brief Disable entropy source for RNG * - * Disables SAR ADC source and resets the I2S hardware. + * Disables internal entropy source. Must be called after + * bootloader_random_enable() and before RF features, ADC, or + * I2S (ESP32 only) are initialized. * + * Consult the ESP-IDF Programming Guide "Random Number Generation" + * section for details. */ void bootloader_random_disable(void); /** * @brief Fill buffer with 'length' random bytes * + * @note If this function is being called from app code only, and never + * from the bootloader, then it's better to call esp_fill_random(). + * * @param buffer Pointer to buffer * @param length This many bytes of random data will be copied to buffer */ diff --git a/components/esp_hw_support/include/esp_random.h b/components/esp_hw_support/include/esp_random.h index 7064fa8115..3b939ef132 100644 --- a/components/esp_hw_support/include/esp_random.h +++ b/components/esp_hw_support/include/esp_random.h @@ -24,28 +24,13 @@ extern "C" { /** * @brief Get one random 32-bit word from hardware RNG * - * The hardware RNG produces true random numbers under any of the following conditions: - * - * - An RF subsystem is running (i.e. Bluetooth or WiFi is enabled) - * - An internal entropy source has been enabled by calling bootloader_random_enable() - * and not yet disabled by calling bootloader_random_disable() - * - While the ESP-IDF bootloader is running (due to the internal entropy source being enabled - * for the duration of bootloader execution). - * - * If none of the above conditions are true, the hardware RNG will produce pseudo-random numbers only. - * - * When the hardware RNG is producing true random numbers, external entropy (noise samples) are - * continuously mixed into the internal hardware RNG state. Consult the SoC Technical Reference Manual - * for more details. + * If Wi-Fi or Bluetooth are enabled, this function returns true random numbers. In other + * situations, if true random numbers are required then consult the ESP-IDF Programming + * Guide "Random Number Generation" section for necessary prerequisites. * * This function automatically busy-waits to ensure enough external entropy has been * introduced into the hardware RNG state, before returning a new random number. * - * If generating random numbers from an app which has not yet enabled Bluetooth or Wi-Fi, call the - * API function bootloader_random_enable() before generating random numbers and then call - * bootloader_random_disable() before using any APIs for Bluetooth, Wi-Fi, ADC, or I2S. Consult the - * bootloader_random.h header for more details. - * * @return Random value between 0 and UINT32_MAX */ uint32_t esp_random(void); @@ -53,7 +38,8 @@ 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() + * @note This function is implemented via calls to esp_random(), so the same + * constraints apply. * * @param buf Pointer to buffer to fill with random numbers. * @param len Length of buffer in bytes diff --git a/docs/doxygen/Doxyfile_common b/docs/doxygen/Doxyfile_common index 985e6cde9f..004c48370e 100644 --- a/docs/doxygen/Doxyfile_common +++ b/docs/doxygen/Doxyfile_common @@ -142,6 +142,7 @@ INPUT = \ $(IDF_PATH)/components/spi_flash/include/esp_flash.h \ $(IDF_PATH)/components/spi_flash/include/esp_partition.h \ $(IDF_PATH)/components/bootloader_support/include/esp_flash_encrypt.h \ + $(IDF_PATH)/components/bootloader_support/include/bootloader_random.h \ $(IDF_PATH)/components/spiffs/include/esp_spiffs.h \ $(IDF_PATH)/components/driver/include/driver/sdmmc_types.h \ $(IDF_PATH)/components/sdmmc/include/sdmmc_cmd.h \ @@ -179,8 +180,9 @@ INPUT = \ $(IDF_PATH)/components/esp_system/include/esp_expression_with_stack.h \ $(IDF_PATH)/components/app_update/include/esp_ota_ops.h \ $(IDF_PATH)/components/esp_https_ota/include/esp_https_ota.h \ - $(IDF_PATH)/components/esp_hw_support/include/esp_sleep.h \ $(IDF_PATH)/components/esp_hw_support/include/esp_async_memcpy.h \ + $(IDF_PATH)/components/esp_hw_support/include/esp_random.h \ + $(IDF_PATH)/components/esp_hw_support/include/esp_sleep.h \ $(IDF_PATH)/components/log/include/esp_log.h \ $(IDF_PATH)/components/esp_rom/include/esp_rom_sys.h \ $(IDF_PATH)/components/esp_system/include/esp_system.h \ diff --git a/docs/en/api-reference/system/index.rst b/docs/en/api-reference/system/index.rst index 3fa360854b..adc4a2930e 100644 --- a/docs/en/api-reference/system/index.rst +++ b/docs/en/api-reference/system/index.rst @@ -27,6 +27,7 @@ System API Over The Air Updates (OTA) :CONFIG_IDF_TARGET_ARCH_XTENSA: Performance Monitor Power Management + Random Number Generation Sleep Modes Watchdogs System Time diff --git a/docs/en/api-reference/system/random.rst b/docs/en/api-reference/system/random.rst new file mode 100644 index 0000000000..a25f65946f --- /dev/null +++ b/docs/en/api-reference/system/random.rst @@ -0,0 +1,49 @@ +Random Number Generation +======================== + +{IDF_TARGET_RF_NAME: default="Wi-Fi or Bluetooth", esp32s2="Wi-Fi"} +{IDF_TARGET_RF_IS: default="are", esp32s2="is"} +{IDF_TARGET_BOOTLOADER_RANDOM_INCOMPATIBLE: default="", esp32="I2S, "} + +{IDF_TARGET_NAME} contains a hardware random number generator, values from it can be obtained using the APIs :cpp:func:`esp_random` and :cpp:func:`esp_fill_random`. + +The hardware RNG produces true random numbers under any of the following conditions: + +- RF subsystem is enabled (i.e. {IDF_TARGET_RF_NAME} {IDF_TARGET_RF_IS} enabled). +- An internal entropy source has been enabled by calling :cpp:func:`bootloader_random_enable` and not yet disabled by calling :cpp:func:`bootloader_random_disable`. +- While the ESP-IDF :ref:`second-stage-bootloader` is running. This is because the default ESP-IDF bootloader implementation calls :cpp:func:`bootloader_random_enable` when the bootloader starts, and :cpp:func:`bootloader_random_disable` before executing the app. + +When any of these conditions are true, samples of physical noise are continuously mixed into the internal hardware RNG state to provide entropy. Consult the *{IDF_TARGET_NAME} Technical Reference Manual* > *Random Number Generator (RNG)* [`PDF <{IDF_TARGET_TRM_EN_URL}#rng>`__] chapter for more details. + +If none of the above conditions are true, the output of the RNG should be considered pseudo-random only. + +Startup +------- + +During startup, ESP-IDF bootloader temporarily enables a non-RF entropy source (internal reference voltage noise) that provides entropy for any first boot key generation. However, after the app starts executing then normally only pseudo-random numbers are available until {IDF_TARGET_RF_NAME} {IDF_TARGET_RF_IS} initialized. + +To re-enable the entropy source temporarily during app startup, or for an application that does not use {IDF_TARGET_RF_NAME}, call the function :cpp:func:`bootloader_random_enable` to re-enable the internal entropy source. The function :cpp:func:`bootloader_random_disable` must be called to disable the entropy source again before using ADC, {IDF_TARGET_BOOTLOADER_RANDOM_INCOMPATIBLE}{IDF_TARGET_RF_NAME}. + +.. note:: + + The entropy source enabled during the boot process by the ESP-IDF Second Stage Bootloader will seed the internal RNG state with some entropy. However, the internal hardware RNG state is not large enough to provide a continuous stream of true random numbers. This is why a continuous entropy source must be enabled whenever true random numbers are required. + +.. note:: + + If an application requires a source of true random numbers but it is not possible to permanently enable a hardware entropy source, consider using a strong software DRBG implementation such as the mbedTLS CTR-DRBG or HMAC-DRBG, with an initial seed of entropy from hardware RNG true random numbers. + +.. only:: not esp32 + + Secondary Entropy + ----------------- + + {IDF_TARGET_NAME} RNG contains a secondary entropy source, based on sampling an asynchronous 8MHz internal oscillator (see the Technical Reference Manual for details). This entropy source is always enabled in ESP-IDF and continuously mixed into the RNG state by hardware. In testing, this secondary entropy source was sufficient to pass the `Dieharder`_ random number test suite without the main entropy source enabled (test input was created by concatenating short samples from a continuously resetting {IDF_TARGET_NAME}). However, it is currently only guaranteed that true random numbers will be produced when the main entropy source is also enabled as described above. + +API Reference +------------- + +.. include-build-file:: inc/esp_random.inc +.. include-build-file:: inc/bootloader_random.inc + +.. _Dieharder: https://webhome.phy.duke.edu/~rgb/General/dieharder.php + diff --git a/docs/en/api-reference/system/system.rst b/docs/en/api-reference/system/system.rst index 5038f99dd5..194a401ea7 100644 --- a/docs/en/api-reference/system/system.rst +++ b/docs/en/api-reference/system/system.rst @@ -25,13 +25,6 @@ Two heap memory related functions are provided: Note that ESP-IDF supports multiple heaps with different capabilities. Functions mentioned in this section return the size of heap memory which can be allocated using ``malloc`` family of functions. For further information about heap memory see :doc:`Heap Memory Allocation `. -Random number generation ------------------------- - -{IDF_TARGET_NAME} contains a hardware random number generator, values from it can be obtained using :cpp:func:`esp_random`. - -When Wi-Fi or Bluetooth are enabled, numbers returned by hardware random number generator (RNG) can be considered true random numbers. Without Wi-Fi or Bluetooth enabled, hardware RNG is a pseudo-random number generator. At startup, ESP-IDF bootloader seeds the hardware RNG with entropy, but care must be taken when reading random values between the start of ``app_main`` and initialization of Wi-Fi or Bluetooth drivers. - .. _MAC-Address-Allocation: MAC Address @@ -189,12 +182,9 @@ To set version in your project manually you need to set ``PROJECT_VER`` variable If :ref:`CONFIG_APP_PROJECT_VER_FROM_CONFIG` option is set, the value of :ref:`CONFIG_APP_PROJECT_VER` will be used. Otherwise if ``PROJECT_VER`` variable is not set in the project then it will be retrieved from either ``$(PROJECT_PATH)/version.txt`` file (if present) else using git command ``git describe``. If neither is available then ``PROJECT_VER`` will be set to "1". Application can make use of this by calling :cpp:func:`esp_ota_get_app_description` or :cpp:func:`esp_ota_get_partition_description` functions. - - API Reference ------------- .. include-build-file:: inc/esp_system.inc .. include-build-file:: inc/esp_idf_version.inc - diff --git a/docs/zh_CN/api-guides/startup.rst b/docs/zh_CN/api-guides/startup.rst index a8155d8737..58e4760197 100644 --- a/docs/zh_CN/api-guides/startup.rst +++ b/docs/zh_CN/api-guides/startup.rst @@ -2,13 +2,15 @@ =================== :link_to_translation:`en:[English]` +{IDF_TARGET_BOOTLOADER_OFFSET:default="0x0", esp32="0x1000", esp32s2="0x1000"} + 本文将会介绍 {IDF_TARGET_NAME} 从上电到运行 ``app_main`` 函数中间所经历的步骤(即启动流程)。 宏观上,该启动流程可以分为如下 3 个步骤: 1. 一级引导程序被固化在了 {IDF_TARGET_NAME} 内部的 ROM 中,它会从 Flash 的 - ``0x1000`` 偏移地址处加载二级引导程序至 RAM(IRAM & DRAM) 中。 + {IDF_TARGET_BOOTLOADER_OFFSET} 偏移地址处加载二级引导程序至 RAM(IRAM & DRAM) 中。 2. 二级引导程序从 Flash 中加载分区表和主程序镜像至内存中,主程序中包含了 RAM 段和通过 Flash 高速缓存映射的只读段。 @@ -53,20 +55,22 @@ SoC 复位后,PRO CPU 会立即开始运行,执行复位向量代码,而 A SoC,重复整个过程。如果解析器收到了来自 UART 的输入,程序会关闭看门狗。 -应用程序的二进制镜像会从 Flash 的 ``0x1000`` 地址处加载。Flash 的第一个 +应用程序的二进制镜像会从 Flash 的 {IDF_TARGET_BOOTLOADER_OFFSET} 地址处加载。Flash 的第一个 4kB 扇区用于存储安全引导程序和应用程序镜像的签名。有关详细信息,请查看安全启动文档。 .. TODO: describe application binary image format, describe optional flash configuration commands. +.. _second-stage-bootloader: + 二级引导程序 ~~~~~~~~~~~~ -在 ESP-IDF 中,存放在 Flash 的 ``0x1000`` +在 ESP-IDF 中,存放在 Flash 的 {IDF_TARGET_BOOTLOADER_OFFSET} 偏移地址处的二进制镜像就是二级引导程序。二级引导程序的源码可以在 ESP-IDF 的 components/bootloader 目录下找到。请注意,对于 {IDF_TARGET_NAME} 芯片来说,这并不是唯一的安排程序镜像的方式。事实上用户完全可以把一个功能齐全的应用程序烧写到 -Flash 的 ``0x1000`` 偏移地址处运行,但这超出本文档的范围。ESP-IDF +Flash 的 {IDF_TARGET_BOOTLOADER_OFFSET} 偏移地址处运行,但这超出本文档的范围。ESP-IDF 使用二级引导程序可以增加 Flash 分区的灵活性(使用分区表),并且方便实现 Flash 加密,安全引导和空中升级(OTA)等功能。 diff --git a/docs/zh_CN/api-reference/system/random.rst b/docs/zh_CN/api-reference/system/random.rst new file mode 100644 index 0000000000..bcd4592e10 --- /dev/null +++ b/docs/zh_CN/api-reference/system/random.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/system/random.rst