Secure Boot and Flash Encryption
ESP32 chips have hardware-level security features controlled by eFuses — one-time-programmable bits burned into silicon. Once burned, they cannot be reversed. This guide covers assessing a device’s current security posture, enabling flash encryption, and understanding the secure boot workflow.
Assess current security posture
Section titled “Assess current security posture”Before changing anything, audit the device to understand what is already configured.
esp_security_audit({ "port": "/dev/ttyUSB0"})The audit returns a structured report including:
- Chip identity and chip ID
- Security posture summary: flash encryption (enabled/disabled), secure boot (enabled/disabled), JTAG (enabled/disabled)
- Security-relevant eFuses:
FLASH_CRYPT_CNT,ABS_DONE_0,JTAG_DISABLE, and others
If the posture section shows everything as “disabled”, the device is in its factory default state with no security features active.
Read individual eFuses
Section titled “Read individual eFuses”To inspect a specific eFuse value:
esp_efuse_read({ "port": "/dev/ttyUSB0", "efuse_name": "FLASH_CRYPT_CNT"})Omit efuse_name to get the full eFuse summary.
Enable flash encryption
Section titled “Enable flash encryption”Flash encryption prevents reading firmware from the flash chip. The process involves checking the current state, then burning the appropriate eFuses.
-
Check current flash encryption status:
esp_enable_flash_encryption({"port": "/dev/ttyUSB0"})If encryption is already enabled, the response reports the current state and no further action is needed. If disabled, it returns guidance on the required eFuse burns.
-
On a QEMU instance (for testing), burn the encryption eFuses:
esp_efuse_burn({"port": "socket://localhost:5555","efuse_name": "FLASH_CRYPT_CNT","value": "0x1"}) -
Verify the change took effect:
esp_efuse_read({"port": "socket://localhost:5555","efuse_name": "FLASH_CRYPT_CNT"})The response shows
value_beforeandvalue_afterto confirm the burn.
Secure boot workflow
Section titled “Secure boot workflow”Secure boot ensures only signed firmware can execute on the device. It is controlled by the ABS_DONE_0 eFuse.
-
Run a security audit to confirm secure boot is not already enabled:
esp_security_audit({"port": "/dev/ttyUSB0"})Look for
secure_boot: "disabled"in the posture section. -
Build your firmware with secure boot enabled in the ESP-IDF menuconfig. This generates signing keys and embeds the public key in the bootloader.
-
Flash the signed bootloader, partition table, and application using
esp_flash_multi. -
Burn the secure boot eFuse to lock it in:
esp_efuse_burn({"port": "/dev/ttyUSB0","efuse_name": "ABS_DONE_0","value": "0x1"}) -
Optionally disable JTAG to prevent debug-port attacks:
esp_efuse_burn({"port": "/dev/ttyUSB0","efuse_name": "JTAG_DISABLE","value": "0x1"})
Common security eFuses
Section titled “Common security eFuses”| eFuse Name | Purpose | Reversible |
|---|---|---|
FLASH_CRYPT_CNT | Controls flash encryption enable/disable | No |
FLASH_CRYPT_CONFIG | Encryption configuration bits | No |
ABS_DONE_0 | Enables secure boot v1 | No |
ABS_DONE_1 | Enables secure boot v2 (ESP32-V3+) | No |
JTAG_DISABLE | Disables JTAG debug interface | No |
DISABLE_DL_ENCRYPT | Disables flash encryption in download mode | No |
DISABLE_DL_DECRYPT | Disables flash decryption in download mode | No |
DISABLE_DL_CACHE | Disables flash cache in download mode | No |
Test on QEMU first
Section titled “Test on QEMU first”QEMU emulates eFuses in a file on disk. When you destroy and recreate a QEMU instance, the eFuse file is regenerated from defaults — effectively giving you a fresh, unburnished chip.
-
Start a QEMU instance:
esp_qemu_start({"chip_type": "esp32","boot_mode": "download"}) -
Run your entire security configuration workflow against the socket URI.
-
Verify with
esp_security_auditthat the posture matches expectations. -
Stop and delete the instance. Start a fresh one to repeat the test or try a different configuration.
See the Security reference for full parameter details on esp_security_audit, esp_efuse_read, esp_efuse_burn, and esp_enable_flash_encryption.