# Flash Encryption

[中文]

This is a quick start guide to ESP32-C5's flash encryption feature. Using application code as an example, it demonstrates how to test and verify flash encryption operations during development and production.

Note

In this guide, most used commands are in the form of `idf.py secure-<command>`, which is a wrapper around corresponding `espsecure <command>`. The `idf.py` based commands provide a more user-friendly experience, although may lack some of the advanced functionality of their `espsecure` based counterparts.

## Introduction

Flash encryption is intended for encrypting the contents of the ESP32-C5's off-chip flash memory. Once this feature is enabled, firmware is flashed as plaintext, and then the data is encrypted in place on the first boot. As a result, physical readout of flash will not be sufficient to recover most flash contents.

Important

For production use, flash encryption should be enabled in the release mode only.

Important

Enabling flash encryption limits the options for further updates of ESP32-C5. Before using this feature, read the document and make sure to understand the implications.

## Encrypted Partitions

With flash encryption enabled, the following types of data are encrypted by default:

- Second Stage Bootloader

- Partition Table

- NVS Key Partition

- Otadata

- All `app` type partitions

Other types of data can be encrypted conditionally:

- Any partition marked with the `encrypted` flag in the partition table. For details, see Encrypted Partition Flag.

- Secure Boot bootloader digest if Secure Boot is enabled (see below).

## Relevant eFuses

The flash encryption operation is controlled by various eFuses available on ESP32-C5. The list of eFuses and their descriptions is given in the table below. The names in eFuse column are also used by `espefuse` tool and `idf.py` based eFuse commands. For usage in the eFuse API, modify the name by adding `ESP_EFUSE_`, for example: esp_efuse_read_field_bit (ESP_EFUSE_DISABLE_DL_ENCRYPT).

eFuses Used in Flash Encryption
eFuse | Description | Bit Depth
`BLOCK_KEYN` | AES key storage. N is between 0 and 5. When using a Key Manager-based key, this eFuse is not used. | One 256-bit key block for XTS_AES_128; two 256-bit key blocks for XTS_AES_256 (512-bit total).
`KEY_PURPOSE_N` | Controls the purpose of eFuse block `BLOCK_KEYN`, where N is between 0 and 5. Possible values: `2` for `XTS_AES_256_KEY_1`, `3` for `XTS_AES_256_KEY_2`, and `4` for `XTS_AES_128_KEY`. Final AES key is derived based on the value of one or two of these purpose eFuses. For a detailed description of the possible combinations, see ESP32-C5 Technical Reference Manual > External Memory Encryption and Decryption (XTS_AES) [PDF]. When enabling Flash Encryption using a Key Manager-based key, this eFuse is not used. | 4
`KM_XTS_KEY_LENGTH_256` | When enabling Flash Encryption using a Key Manager-based key, this eFuse is used to control the length of the XTS-AES key. Set this eFuse to 1 to use a 128-bit key, and to 0 to use a 256-bit key. This eFuse field is unused when enabling Flash Encryption using an eFuse-based key. | 1
`FORCE_USE_KEY_MANAGER_KEY` | When enabling Flash Encryption using a Key Manager-based key, this eFuse is used to force the Key Manager to use the XTS-AES key. Set the bit 1 of this eFuse to use the Key Manager-based key. This eFuse field is unused when enabling Flash Encryption using an eFuse-based key. | 1
`DIS_DOWNLOAD_MANUAL_ENCRYPT` | If set, disables Flash Encryption when in download bootmodes. | 1
`SPI_BOOT_CRYPT_CNT` | Enables encryption and decryption, when an SPI boot mode is set. Feature is enabled if 1 or 3 bits are set in the eFuse, disabled otherwise. | 3

Note

- R/W access control is available for all the eFuse bits listed in the table above.

- The default value of these bits is 0 after manufacturing.

Read and write access to eFuse bits is controlled by appropriate fields in the registers `WR_DIS` and `RD_DIS`. For more information on ESP32-C5 eFuses, see eFuse manager. To change protection bits of eFuse field using `idf.py`, use these two commands: efuse-read-protect and efuse-write-protect (idf.py based aliases of espefuse commands write-protect-efuse and read-protect-efuse). Example `idf.py efuse-write-protect DISABLE_DL_ENCRYPT`.

## Flash Encryption Process

Assuming that the eFuse values are in their default states and the second stage bootloader is compiled to support flash encryption, the flash encryption process executes as shown below:

1. On the first power-on reset, all data in flash is un-encrypted (plaintext). The first stage (ROM) bootloader loads the second stage bootloader.

2. Second stage bootloader reads the `SPI_BOOT_CRYPT_CNT` eFuse value (`0b000`). Since the value is `0` (even number of bits set), it configures and enables the flash encryption block. For more information on the flash encryption block, see ESP32-C5 Technical Reference Manual > eFuse Controller (eFuse) > Manual Encryption Block [PDF].

3. Second stage bootloader first checks if a valid key already exists, to decide whether to skip the key generation step:

> - If Flash Encryption is intended to be enabled using an eFuse-based key, it checks if a valid key is already present in the eFuse (e.g., burned using espefuse tool).

> - If Flash Encryption is intended to be enabled using a Key Manager-based key, it checks if there exists a valid key recovery info in the flash memory at the addresses: 0x0 and 0x1000.

> If the check passes, the process of key generation is skipped and the same key is used for the flash encryption process.

4. Otherwise, if using an eFuse-based key, second stage bootloader uses RNG (random) module to generate an 256-bit or 512-bit key, depending on the value of Size of generated XTS-AES key, and then writes it into respectively one or two `BLOCK_KEYN` eFuses. The software also updates the `KEY_PURPOSE_N` for the blocks where the keys were stored. The key cannot be accessed via software as the write and read protection bits for one or two `BLOCK_KEYN` eFuses are set. `KEY_PURPOSE_N` field is write-protected as well. Whereas if using a Key Manager-based key, second stage bootloader writes the key recovery info to the flash memory at the address 0x0, followed by programming the `KM_XTS_KEY_LENGTH_256` and the `FORCE_USE_KEY_MANAGER_KEY` eFuses. The flash encryption operations happen entirely by hardware, and the key cannot be accessed via software.

5. Flash encryption block encrypts the flash contents – the second stage bootloader, applications and partitions marked as `encrypted`. Encrypting in-place can take time, up to a minute for large partitions.

6. Second stage bootloader sets the first available bit in `SPI_BOOT_CRYPT_CNT` (0b001) to mark the flash contents as encrypted. Odd number of bits is set.

7. For Development Mode, the second stage bootloader allows the UART bootloader to re-flash encrypted binaries. Also, the `SPI_BOOT_CRYPT_CNT` eFuse bits are NOT write-protected. In addition, the second stage bootloader by default sets the following eFuse bits:

> - `DIS_DOWNLOAD_ICACHE`

> - `DIS_DOWNLOAD_DCACHE`

> - `HARD_DIS_JTAG`

> - `DIS_LEGACY_SPI_BOOT`

8. For Release Mode, the second stage bootloader sets all the eFuse bits set under development mode as well as `DIS_DOWNLOAD_MANUAL_ENCRYPT`. It also write-protects the `SPI_BOOT_CRYPT_CNT` eFuse bits. To modify this behavior, see Enabling UART Bootloader Encryption/Decryption.

9. The device is then rebooted to start executing the encrypted image. The second stage bootloader calls the flash decryption block to decrypt the flash contents and then loads the decrypted contents into IRAM.

During the development stage, there is a frequent need to program different plaintext flash images and test the flash encryption process. This requires that Firmware Download mode is able to load new plaintext images as many times as it might be needed. However, during manufacturing or production stages, Firmware Download mode should not be allowed to access flash contents for security reasons.

Hence, two different flash encryption configurations were created: for development and for production. For details on these configurations, see Section Flash Encryption Configuration.

## Flash Encryption Configuration

The following flash encryption modes are available:

- Development Mode - recommended for use only during development. In this mode, it is still possible to flash new plaintext firmware to the device, and the bootloader will transparently encrypt this firmware using the key stored in hardware. This allows, indirectly, to read out the plaintext of the firmware in flash.

- Release Mode - recommended for manufacturing and production. In this mode, flashing plaintext firmware to the device without knowing the encryption key is no longer possible.

This section provides information on the mentioned flash encryption modes and step by step instructions on how to use them.

### Development Mode

During development, you can encrypt flash using either an ESP32-C5 generated key or external host-generated key.

#### Using ESP32-C5 Generated Key

Development mode allows you to download multiple plaintext images using Firmware Download mode.

To test flash encryption process, take the following steps:

1. Ensure that you have an ESP32-C5 device with default flash encryption eFuse settings as shown in Relevant eFuses.

> See how to check ESP32-C5 Flash Encryption Status.

2. In Editing the Configuration, do the following:

> - Enable flash encryption on boot.

> - Select encryption mode (development mode by default).

> - Select UART ROM download mode (enabled by default).

> - Set Size of generated XTS-AES key.

> - Select the key source for the Flash Encryption key.

> - Select the appropriate bootloader log verbosity.

> - Save the configuration and exit.

> Enabling flash encryption will increase the size of bootloader, which might require updating partition table offset. See Bootloader Size.

3. Run the command given below to build and flash the complete images.

>     idf.py flash monitor

> Note

> This command does not include any user files which should be written to the partitions on the flash memory. Please write them manually before running this command otherwise the files should be encrypted separately before writing.

> This command will write to flash memory unencrypted images: the second stage bootloader, the partition table and applications. Once the flashing is complete, ESP32-C5 will reset. On the next boot, the second stage bootloader encrypts: the second stage bootloader, application partitions and partitions marked as `encrypted` then resets. Encrypting in-place can take time, up to a minute for large partitions. After that, the application is decrypted at runtime and executed.

A sample output of the first ESP32-C5 boot after enabling flash encryption using a Key Manager-based key is given below:

    ESP-ROM:esp32c5-eco3-20250704
    Build:Jul  4 2025
    rst:0x1 (POWERON),boot:0x18 (SPI_FAST_FLASH_BOOT)
    SPI mode:DIO, clock div:1
    load:0x40855820,len:0x3a60
    load:0x4084bba0,len:0xdf4
    load:0x4084e5a0,len:0x566c
    entry 0x4084bbaa
    I (23) boot: ESP-IDF v6.0-dev-3140-ge16a2fb13ad-dirt 2nd stage bootloader
    I (24) boot: compile time Oct 27 2025 15:35:09
    I (67) boot: chip revision: v1.1
    I (70) boot: efuse block revision: v0.3
    I (88) boot.esp32c5: SPI Speed      : 80MHz
    I (92) boot.esp32c5: SPI Mode       : DIO
    I (96) boot.esp32c5: SPI Flash Size : 2MB
    I (103) boot: Enabling RNG early entropy source...
    I (138) boot: Partition Table:
    I (141) boot: ## Label            Usage          Type ST Offset   Length
    I (154) boot:  0 nvs              WiFi data        01 02 0000e000 00006000
    I (168) boot:  1 phy_init         RF data          01 01 00014000 00001000
    I (182) boot:  2 factory          factory app      00 00 00020000 00100000
    I (189) boot: End of partition table
    I (283) esp_image: segment 0: paddr=00020020 vaddr=42070020 size=32f1ch (208668) map
    I (377) esp_image: segment 1: paddr=00052f44 vaddr=40800000 size=0a2a4h ( 41636) load
    I (445) esp_image: segment 2: paddr=0005d1f0 vaddr=4080a300 size=02ccch ( 11468) load
    I (512) esp_image: segment 3: paddr=0005fec4 vaddr=00000000 size=00154h (   340)
    I (580) esp_image: segment 4: paddr=00060020 vaddr=42000020 size=63804h (407556) map
    I (761) boot: Loaded app from partition at offset 0x20000
    I (764) boot: Checking flash encryption...
    I (788) efuse: Batch mode of writing fields is enabled
    I (807) flash_encrypt: Deploying new flash encryption key using Key Manager
    W (898) flash_encrypt: Not disabling UART bootloader encryption
    I (904) flash_encrypt: Disable UART bootloader cache...
    W (917) flash_encrypt: Not disabling JTAG - SECURITY COMPROMISED
    I (930) efuse: BURN BLOCK0
    I (935) efuse: BURN BLOCK0 - OK (all write block bits are set)
    I (938) efuse: Batch mode. Prepared fields are committed
    I (1028) esp_image: segment 0: paddr=00002020 vaddr=40855820 size=03a60h ( 14944)
    I (1096) esp_image: segment 1: paddr=00005a88 vaddr=4084bba0 size=00df4h (  3572)
    I (1165) esp_image: segment 2: paddr=00006884 vaddr=4084e5a0 size=0566ch ( 22124)
    I (1508) flash_encrypt: bootloader encrypted successfully
    I (1535) flash_encrypt: partition table encrypted and loaded successfully
    I (1616) esp_image: segment 0: paddr=00020020 vaddr=42070020 size=32f1ch (208668) map
    I (1711) esp_image: segment 1: paddr=00052f44 vaddr=40800000 size=0a2a4h ( 41636)
    I (1779) esp_image: segment 2: paddr=0005d1f0 vaddr=4080a300 size=02ccch ( 11468)
    I (1847) esp_image: segment 3: paddr=0005fec4 vaddr=00000000 size=00154h (   340)
    I (1916) esp_image: segment 4: paddr=00060020 vaddr=42000020 size=63804h (407556) map
    I (2096) flash_encrypt: Encrypting partition 2 at offset 0x20000 (length 0xa3850)...
    I (5652) flash_encrypt: Done encrypting
    I (5667) efuse: BURN BLOCK0
    I (5671) efuse: BURN BLOCK0 - OK (all write block bits are set)
    I (5675) flash_encrypt: Flash encryption completed
    I (5679) boot: Resetting with flash encryption enabled...

A sample output of subsequent ESP32-C5 boot mentions that Flash Encryption is already enabled (ESP-ROM log mentions that the Key Manager-based key is being used):

    ESP-ROM:esp32c5-eco3-20250704
    Build:Jul  4 2025
    rst:0x1 (POWERON),boot:0x18 (SPI_FAST_FLASH_BOOT)
    use sector0 for km info
    use KM derived key
    SPI mode:DIO, clock div:1
    load:0x40855820,len:0x3a94
    load:0x4084bba0,len:0xd84
    load:0x4084e5a0,len:0x5670
    entry 0x4084bbaa
    I (27) boot: ESP-IDF v6.0-dev-3139-gb813f413096-dirt 2nd stage bootloader
    I (28) boot: compile time Oct 27 2025 18:14:49
    W (39) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1
    W (53) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1
    W (67) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1
    W (80) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1
    W (94) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1
    W (108) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1
    I (116) boot: chip revision: v1.1
    I (119) boot: efuse block revision: v0.3
    I (137) boot.esp32c5: SPI Speed      : 80MHz
    I (141) boot.esp32c5: SPI Mode       : DIO
    I (145) boot.esp32c5: SPI Flash Size : 2MB
    I (149) boot: Enabling RNG early entropy source...
    W (163) MMU: mmu_ll_write_entry mmu_id=0, entry_id=0, mmu_val=0x00000000, target=1
    I (191) boot: Partition Table:
    I (194) boot: ## Label            Usage          Type ST Offset   Length
    I (208) boot:  0 nvs              WiFi data        01 02 0000e000 00006000
    I (222) boot:  1 phy_init         RF data          01 01 00014000 00001000
    I (235) boot:  2 factory          factory app      00 00 00020000 00100000
    I (242) boot: End of partition table
    I (396) esp_image: segment 0: paddr=00020020 vaddr=42070020 size=32f1ch (208668) map
    I (539) esp_image: segment 1: paddr=00052f44 vaddr=40800000 size=0a2a4h ( 41636) load
    I (629) esp_image: segment 2: paddr=0005d1f0 vaddr=4080a300 size=02ccch ( 11468) load
    I (719) esp_image: segment 3: paddr=0005fec4 vaddr=00000000 size=00154h (   340)
    I (816) esp_image: segment 4: paddr=00060020 vaddr=42000020 size=6378ch (407436) map
    I (1114) boot: Loaded app from partition at offset 0x20000
    I (1116) boot: Checking flash encryption...
    I (1133) flash_encrypt: flash encryption is enabled (1 plaintext flashes left)
    I (1140) boot: Disabling RNG early entropy source...
    I (1301) MSPI Timing: Enter flash timing tuning
    I (1434) cpu_start: Unicore app
    I (1468) cpu_start: GPIO 12 and 11 are used as console UART I/O pins
    I (1479) cpu_start: Pro cpu start user code
    I (1483) cpu_start: cpu freq: 240000000 Hz
    I (1493) app_init: Application information:
    I (1496) app_init: Project name:     mbedtls_test
    I (1501) app_init: App version:      qa-test-esp32c61-master-2025070
    I (1507) app_init: Compile time:     Oct 27 2025 15:56:18
    I (1512) app_init: ELF file SHA256:  c5f7f520c...
    I (1517) app_init: ESP-IDF:          v6.0-dev-3140-ge16a2fb13ad-dirt
    I (1528) efuse_init: Min chip rev:     v1.0
    I (1532) efuse_init: Max chip rev:     v1.99
    I (1536) efuse_init: Chip rev:         v1.1
    I (1669) heap_init: Initializing. RAM available for dynamic allocation:
    I (1680) heap_init: At 4080FCB0 len 0004C8F0 (306 KiB): RAM
    I (1685) heap_init: At 4085C5A0 len 00002F58 (11 KiB): RAM
    I (1695) heap_init: At 50000000 len 00003FE8 (15 KiB): RTCRAM
    I (1800) spi_flash: detected chip: generic
    I (1804) spi_flash: flash io: dio
    W (1807) spi_flash: Detected size(8192k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
    W (1833) flash_encrypt: Flash encryption mode is DEVELOPMENT (not secure)
    I (1867) sleep_gpio: Configure to isolate all GPIO pins in sleep state
    I (1873) sleep_gpio: Enable automatic switching of GPIO sleep configuration
    I (1926) main_task: Started on CPU0
    I (1926) main_task: Calling app_main()
    I (1936) main_task: Returned from app_main()

A sample output of the first ESP32-C5 boot after enabling flash encryption using an eFuse-based key is given below:

    rst:0x1 (POWERON),boot:0x3d (SPI_FAST_FLASH_BOOT)
    SPI mode:DIO, clock div:2
    load:0x40855c10,len:0x2c34
    load:0x4084c7a0,len:0x6f8
    load:0x4084e9a0,len:0x41c4
    entry 0x4084c804
    I (32) boot: ESP-IDF v5.3-dev-3860-g5d36288649-dirty 2nd stage bootloader
    I (33) boot: compile time May  7 2024 17:31:13
    I (34) boot: chip revision: v0.0
    I (37) boot.esp32c5: SPI Speed      : 40MHz
    I (42) boot.esp32c5: SPI Mode       : DIO
    I (47) boot.esp32c5: SPI Flash Size : 2MB
    I (52) boot: Enabling RNG early entropy source...
    I (64) boot: Partition Table:
    I (68) boot: ## Label            Usage          Type ST Offset   Length
    I (75) boot:  0 nvs              WiFi data        01 02 0000e000 00006000
    I (82) boot:  1 storage          Unknown data     01 ff 00014000 00001000
    I (90) boot:  2 factory          factory app      00 00 00020000 00100000
    I (97) boot:  3 nvs_key          NVS keys         01 04 00120000 00001000
    I (105) boot:  4 custom_nvs       WiFi data        01 02 00121000 00006000
    I (113) boot: End of partition table
    I (117) esp_image: segment 0: paddr=00020020 vaddr=42010020 size=09674h ( 38516) map
    I (169) esp_image: segment 1: paddr=0002969c vaddr=40800000 size=0697ch ( 27004) load
    I (197) esp_image: segment 2: paddr=00030020 vaddr=42000020 size=0f4fch ( 62716) map
    I (256) esp_image: segment 3: paddr=0003f524 vaddr=4080697c size=00c28h (  3112) load
    I (261) esp_image: segment 4: paddr=00040154 vaddr=408075b0 size=00d18h (  3352) load
    I (269) boot: Loaded app from partition at offset 0x20000
    I (270) boot: Checking flash encryption...
    I (273) efuse: Batch mode of writing fields is enabled
    I (279) flash_encrypt: Generating new flash encryption key...
    I (297) efuse: Writing EFUSE_BLK_KEY0 with purpose 4
    I (300) flash_encrypt: Disable UART bootloader encryption...
    I (306) flash_encrypt: Disable JTAG...
    I (312) efuse: BURN BLOCK4
    I (317) efuse: BURN BLOCK4 - OK (write block == read block)
    I (320) efuse: BURN BLOCK0
    I (326) efuse: BURN BLOCK0 - OK (write block == read block)
    I (330) efuse: Batch mode. Prepared fields are committed
    I (335) esp_image: segment 0: paddr=00002020 vaddr=40855c10 size=02c34h ( 11316)
    I (353) esp_image: segment 1: paddr=00004c5c vaddr=4084c7a0 size=006f8h (  1784)
    I (356) esp_image: segment 2: paddr=0000535c vaddr=4084e9a0 size=041c4h ( 16836)
    I (1091) flash_encrypt: bootloader encrypted successfully
    I (1182) flash_encrypt: partition table encrypted and loaded successfully
    I (1183) flash_encrypt: Encrypting partition 1 at offset 0x14000 (length 0x1000)...
    I (1271) flash_encrypt: Done encrypting
    I (1272) esp_image: segment 0: paddr=00020020 vaddr=42010020 size=09674h ( 38516) map
    I (1309) esp_image: segment 1: paddr=0002969c vaddr=40800000 size=0697ch ( 27004)
    I (1336) esp_image: segment 2: paddr=00030020 vaddr=42000020 size=0f4fch ( 62716) map
    I (1395) esp_image: segment 3: paddr=0003f524 vaddr=4080697c size=00c28h (  3112)
    I (1400) esp_image: segment 4: paddr=00040154 vaddr=408075b0 size=00d18h (  3352)
    I (1405) flash_encrypt: Encrypting partition 2 at offset 0x20000 (length 0x100000)...
    I (24123) flash_encrypt: Done encrypting
    I (24124) flash_encrypt: Encrypting partition 3 at offset 0x120000 (length 0x1000)...
    I (24215) flash_encrypt: Done encrypting
    I (24216) flash_encrypt: Setting CRYPT_CNT for permanent encryption
    I (24217) efuse: BURN BLOCK0
    I (24221) efuse: BURN BLOCK0 - OK (all write block bits are set)
    I (24226) flash_encrypt: Flash encryption completed
    I (24231) boot: Resetting with flash encryption enabled...

A sample output of subsequent ESP32-C5 boot mentions that Flash Encryption is already enabled:

    ESP-ROM:esp32c5-20240329
    Build:Mar 29 2024
    rst:0x3 (RTC_SW_HPSYS),boot:0x3d (SPI_FAST_FLASH_BOOT)
    Core0 Saved PC:0x4084fe1c
    use legacy efuse key
    SPI mode:DIO, clock div:2
    load:0x40855c10,len:0x2be8
    load:0x4084c7a0,len:0x6f8
    load:0x4084e9a0,len:0x418c
    entry 0x4084c804
    I (39) boot: ESP-IDF v5.3-dev-3860-g5d36288649 2nd stage bootloader
    I (40) boot: compile time May  7 2024 17:24:43
    I (41) boot: chip revision: v0.0
    I (44) boot.esp32c5: SPI Speed      : 40MHz
    I (48) boot.esp32c5: SPI Mode       : DIO
    I (53) boot.esp32c5: SPI Flash Size : 2MB
    I (58) boot: Enabling RNG early entropy source...
    I (70) boot: Partition Table:
    I (74) boot: ## Label            Usage          Type ST Offset   Length
    I (81) boot:  0 nvs              WiFi data        01 02 0000e000 00006000
    I (89) boot:  1 storage          Unknown data     01 ff 00014000 00001000
    I (96) boot:  2 factory          factory app      00 00 00020000 00100000
    I (103) boot:  3 nvs_key          NVS keys         01 04 00120000 00001000
    I (111) boot:  4 custom_nvs       WiFi data        01 02 00121000 00006000
    I (119) boot: End of partition table
    I (123) esp_image: segment 0: paddr=00020020 vaddr=42010020 size=095c4h ( 38340) map
    I (177) esp_image: segment 1: paddr=000295ec vaddr=40800000 size=06a2ch ( 27180) load
    I (207) esp_image: segment 2: paddr=00030020 vaddr=42000020 size=0f4d4h ( 62676) map
    I (269) esp_image: segment 3: paddr=0003f4fc vaddr=40806a2c size=00b78h (  2936) load
    I (274) esp_image: segment 4: paddr=0004007c vaddr=408075b0 size=00d18h (  3352) load
    I (283) boot: Loaded app from partition at offset 0x20000
    I (283) boot: Checking flash encryption...
    I (286) flash_encrypt: flash encryption is enabled (1 plaintext flashes left)
    I (294) boot: Disabling RNG early entropy source...
    I (318) cpu_start: Unicore app
    I (326) cpu_start: Pro cpu start user code
    I (330) cpu_start: cpu freq: 40000000 Hz
    I (335) app_init: Application information:
    I (340) app_init: Project name:     flash_encryption
    I (345) app_init: App version:      qa-test-v5.3-20240419-267-g5d36
    I (352) app_init: Compile time:     May  7 2024 17:24:35
    I (358) app_init: ELF file SHA256:  712933cde...
    I (364) app_init: ESP-IDF:          v5.3-dev-3860-g5d36288649
    I (370) efuse_init: Min chip rev:     v0.0
    I (375) efuse_init: Max chip rev:     v0.99
    I (380) efuse_init: Chip rev:         v0.0
    I (385) heap_init: Initializing. RAM available for dynamic allocation:
    I (392) heap_init: At 408091A0 len 00051730 (325 KiB): RAM
    I (398) heap_init: At 4085A8D0 len 00004C30 (19 KiB): RAM
    I (404) heap_init: At 50000000 len 00003FE8 (15 KiB): RTCRAM
    I (426) spi_flash: detected chip: generic
    I (427) spi_flash: flash io: dio
    W (431) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
    W (445) flash_encrypt: Flash encryption mode is DEVELOPMENT (not secure)
    I (452) nvs_sec_provider: NVS Encryption - Registering Flash encryption-based scheme...
    I (466) main_task: Started on CPU0
    I (466) main_task: Calling app_main()

    Example to check Flash Encryption status
    This is esp32c5 chip with 1 CPU core(s), WiFi/BLE, silicon revision v0.0, 2MB external flash
    FLASH_CRYPT_CNT eFuse value is 1
    Flash encryption feature is enabled in DEVELOPMENT mode

At this stage, if you need to update and re-flash binaries, see Re-flashing Updated Partitions.

#### Using Host Generated Key

It is possible to pre-generate a flash encryption key on the host computer and program it into the device. This allows you to pre-encrypt data on the host and flash already encrypted data without needing a plaintext flash update. This feature can be used in both Development Mode and Release Mode. Without a pre-generated key, data is flashed in plaintext and then ESP32-C5 encrypts the data in-place.

Note

This option is not recommended for production, unless a separate key is generated for each individual device.

To use a host generated key and program it into the eFuses of the device, take the following steps:

1. Ensure that you have an ESP32-C5 device with default flash encryption eFuse settings as shown in Relevant eFuses.

> See how to check ESP32-C5 Flash Encryption Status.

2. Generate a random key by running:

> If Size of generated XTS-AES key is AES-128 (256-bit key):

>     idf.py secure-generate-flash-encryption-key my_flash_encryption_key.bin

> else if Size of generated XTS-AES key is AES-256 (512-bit key):

>     idf.py secure-generate-flash-encryption-key --keylen 512 my_flash_encryption_key.bin

3. Before the first encrypted boot, burn the key into your device's eFuse using the command below. This action can be done only once.

>     idf.py --port PORT efuse-burn-key BLOCK my_flash_encryption_key.bin KEYPURPOSE

> where `BLOCK` is a free keyblock between `BLOCK_KEY0` and `BLOCK_KEY5`. And `KEYPURPOSE` is either `XTS_AES_256_KEY_1`, `XTS_AES_256_KEY_2`, `XTS_AES_128_KEY`. See ESP32-C5 Technical Reference Manual for a description of the key purposes.

> For AES-128 (256-bit key) - `XTS_AES_128_KEY`:

>     idf.py --port PORT efuse-burn-key BLOCK my_flash_encryption_key.bin XTS_AES_128_KEY

> For AES-256 (512-bit key) - `XTS_AES_256_KEY_1` and `XTS_AES_256_KEY_2`. `idf.py` supports burning both these two key purposes together with a 512 bit key to two separate key blocks via the virtual key purpose `XTS_AES_256_KEY`. When this is used `idf.py` will burn the first 256 bits of the key to the specified `BLOCK` and burn the corresponding block key purpose to `XTS_AES_256_KEY_1`. The last 256 bits of the key will be burned to the first free key block after `BLOCK` and the corresponding block key purpose to `XTS_AES_256_KEY_2`

>     idf.py --port PORT efuse-burn-key BLOCK my_flash_encryption_key.bin XTS_AES_256_KEY

> If you wish to specify exactly which two blocks are used then it is possible to divide key into two 256-bit keys, and manually burn each half with `XTS_AES_256_KEY_1` and `XTS_AES_256_KEY_2` as key purposes:

>     split -b 32 my_flash_encryption_key.bin my_flash_encryption_key.bin.
>     idf.py --port PORT efuse-burn-key BLOCK my_flash_encryption_key.bin.aa XTS_AES_256_KEY_1
>     idf.py --port PORT efuse-burn-key BLOCK+1 my_flash_encryption_key.bin.ab XTS_AES_256_KEY_2

> If the key is not burned and the device is started after enabling flash encryption, the ESP32-C5 will generate a random key that software cannot access or modify.

4. In Editing the Configuration, do the following:

   - Enable flash encryption on boot

   - Select encryption mode (development mode by default)

   - Select the appropriate bootloader log verbosity

   - Save the configuration and exit.

> Enabling flash encryption will increase the size of bootloader, which might require updating partition table offset. See Bootloader Size.

5. Run the command given below to build and flash the complete images.

>     idf.py flash monitor

> Note

> This command does not include any user files which should be written to the partitions on the flash memory. Please write them manually before running this command otherwise the files should be encrypted separately before writing.

> This command will write to flash memory unencrypted images: the second stage bootloader, the partition table and applications. Once the flashing is complete, ESP32-C5 will reset. On the next boot, the second stage bootloader encrypts: the second stage bootloader, application partitions and partitions marked as `encrypted` then resets. Encrypting in-place can take time, up to a minute for large partitions. After that, the application is decrypted at runtime and executed.

To use a host generated key and deploy it into the device's Key Manager of the device, take the following steps:

1. Ensure that you have an ESP32-C5 device with default flash encryption eFuse settings as shown in Relevant eFuses.

> See how to check ESP32-C5 Flash Encryption Status.

2. Generate a random key by running:

> If Size of generated XTS-AES key is AES-128 (256-bit key):

>     idf.py secure-generate-flash-encryption-key my_flash_encryption_key.bin

> else if Size of generated XTS-AES key is AES-256 (512-bit key):

>     idf.py secure-generate-flash-encryption-key --keylen 512 my_flash_encryption_key.bin

3. Before the first encrypted boot, deploy the key into your device's Key Manager via its AES-deploy mode, using an init key and an auxiliary key.

4. The deployment process will generate key recovery information for the deployed key. Store the information at the flash address 0x0 using the following command:

>     esptool --port PORT --baud BAUD write-flash 0x0 key_recovery_info.bin

> If the key is not deployed and the device is started after enabling Flash Encryption, the ESP32-C5 will generate and deploy a random key that software cannot access or modify.

> Note

> This command does not include any user files which should be written to the partitions on the flash memory. Please write them manually before running this command. Otherwise, the files should be encrypted separately before writing.

5. In Editing the Configuration, do the following:

   - Enable Flash Encryption on boot

   - Select encryption mode (development mode by default)

   - Select Flash Encryption key source as the Key Manager

   - Select the appropriate bootloader log verbosity

   - Save the configuration and exit.

> Enabling flash encryption will increase the size of bootloader, which might require updating partition table offset. See Bootloader Size.

6. Run the command given below to build and flash the complete images.

>     idf.py flash monitor

> Note

> This command does not include any user files which should be written to the partitions on the flash memory. Please write them manually before running this command. Otherwise, the files should be encrypted separately before writing.

If using development mode, then the easiest way to update and re-flash binaries is Re-flashing Updated Partitions.

If using release mode, then it is possible to pre-encrypt the binaries on the host and then flash them as ciphertext. See Manually Encrypting Files.

#### Re-flashing Updated Partitions

If you update your application code (done in plaintext) and want to re-flash it, you will need to encrypt it before flashing. To encrypt the application and flash it in one step, run:

    idf.py encrypted-app-flash monitor

If all partitions need to be updated in encrypted format, run:

    idf.py encrypted-flash monitor

Note

The above operations are only applicable when the `DIS_DOWNLOAD_MANUAL_ENCRYPT` eFuse bit has not been programmed. If this eFuse bit has been programmed, you must flash the pre-encrypted ciphertext image instead.

### Release Mode

In release mode, UART bootloader cannot perform flash encryption operations. New plaintext images can ONLY be downloaded using the over-the-air (OTA) scheme which will encrypt the plaintext image before writing to flash.

To use this mode, take the following steps:

1. Ensure that you have an ESP32-C5 device with default flash encryption eFuse settings as shown in Relevant eFuses.

> See how to check ESP32-C5 Flash Encryption Status.

2. In Editing the Configuration, do the following:

> - Enable Flash Encryption on boot.

> - Select release mode. (Note that once release mode is selected, the `EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT` eFuse bit will be burned to disable flash encryption hardware in ROM Download Mode.)

> - Select UART ROM download mode (Permanently switch to Secure mode (recommended)). This is the default option, and is recommended. It is also possible to change this configuration setting to permanently disable UART ROM download mode, if this mode is not needed.

> - Select enable XTS-AES's pseudo rounds function. This option is selected by default and its strength is configured to level low considering the performance impact on the flash encryption/decryption operations. Please refer to Pseudo-Round Function for more information regarding the performance impact per security level.

> - Select the appropriate bootloader log verbosity.

> - Save the configuration and exit.

> Enabling flash encryption will increase the size of bootloader, which might require updating partition table offset. See Bootloader Size.

3. Run the command given below to build and flash the complete images.

>     idf.py flash monitor

> Note

> This command does not include any user files which should be written to the partitions on the flash memory. Please write them manually before running this command otherwise the files should be encrypted separately before writing.

> This command will write to flash memory unencrypted images: the second stage bootloader, the partition table and applications. Once the flashing is complete, ESP32-C5 will reset. On the next boot, the second stage bootloader encrypts: the second stage bootloader, application partitions and partitions marked as `encrypted` then resets. Encrypting in-place can take time, up to a minute for large partitions. After that, the application is decrypted at runtime and executed.

Once the flash encryption is enabled in release mode, the bootloader will write-protect the `SPI_BOOT_CRYPT_CNT` eFuse.

For subsequent plaintext field updates, use OTA scheme.

Note

If you have pre-generated the flash encryption key and stored a copy, and the UART download mode is not permanently disabled via CONFIG_SECURE_UART_ROM_DL_MODE , then it is possible to update the flash locally by pre-encrypting the files and then flashing the ciphertext. See Manually Encrypting Files.

### Best Practices

When using Flash Encryption in production:

- Do not reuse the same flash encryption key between multiple devices. This means that an attacker who copies encrypted data from one device cannot transfer it to a second device.

- The UART ROM Download Mode should be disabled entirely if it is not needed, or permanently set to "Secure Download Mode" otherwise. Secure Download Mode permanently limits the available commands to updating SPI config, changing baud rate, basic flash write, and returning a summary of the currently enabled security features with the get-security-info command. The default behaviour is to set Secure Download Mode on first boot in release mode. To disable Download Mode entirely, select CONFIG_SECURE_UART_ROM_DL_MODE to "Permanently disable ROM Download Mode (recommended)" or call `esp_efuse_disable_rom_download_mode()` at runtime.

- Enable Secure Boot as an extra layer of protection, and to prevent an attacker from selectively corrupting any part of the flash before boot.

## Enable Flash Encryption Externally

In the process mentioned above, flash encryption related eFuses which ultimately enable flash encryption are programmed through the second stage bootloader. Alternatively, all the eFuses can be programmed with the help of `espefuse` tool. Please refer Enable Flash Encryption Externally for more details.

## Possible Failures

Once flash encryption is enabled, the `SPI_BOOT_CRYPT_CNT` eFuse value will have an odd number of bits set. It means that all the partitions marked with the encryption flag are expected to contain encrypted ciphertext. Below are the three typical failure cases if the ESP32-C5 is erroneously loaded with plaintext data:

1. If the bootloader partition is re-flashed with a plaintext second stage bootloader image, the first stage (ROM) bootloader will fail to load the second stage bootloader resulting in the following failure:

>     rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
>     invalid header: 0xb414f76b
>     invalid header: 0xb414f76b
>     invalid header: 0xb414f76b
>     invalid header: 0xb414f76b
>     invalid header: 0xb414f76b
>     invalid header: 0xb414f76b
>     invalid header: 0xb414f76b

> Note

> The value of invalid header will be different for every application.

> Note

> This error also appears if the flash contents are erased or corrupted.

2. If the second stage bootloader is encrypted, but the partition table is re-flashed with a plaintext partition table image, the bootloader will fail to read the partition table resulting in the following failure:

>     rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
>     configsip: 0, SPIWP:0xee
>     clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
>     mode:DIO, clock div:2
>     load:0x3fff0018,len:4
>     load:0x3fff001c,len:10464
>     ho 0 tail 12 room 4
>     load:0x40078000,len:19168
>     load:0x40080400,len:6664
>     entry 0x40080764
>     I (60) boot: ESP-IDF v4.0-dev-763-g2c55fae6c-dirty 2nd stage bootloader
>     I (60) boot: compile time 19:15:54
>     I (62) boot: Enabling RNG early entropy source...
>     I (67) boot: SPI Speed      : 40MHz
>     I (72) boot: SPI Mode       : DIO
>     I (76) boot: SPI Flash Size : 4MB
>     E (80) flash_parts: partition 0 invalid magic number 0x94f6
>     E (86) boot: Failed to verify partition table
>     E (91) boot: load partition table error!

3. If the bootloader and partition table are encrypted, but the application is re-flashed with a plaintext application image, the bootloader will fail to load the application resulting in the following failure:

>     rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
>     configsip: 0, SPIWP:0xee
>     clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
>     mode:DIO, clock div:2
>     load:0x3fff0018,len:4
>     load:0x3fff001c,len:8452
>     load:0x40078000,len:13616
>     load:0x40080400,len:6664
>     entry 0x40080764
>     I (56) boot: ESP-IDF v4.0-dev-850-gc4447462d-dirty 2nd stage bootloader
>     I (56) boot: compile time 15:37:14
>     I (58) boot: Enabling RNG early entropy source...
>     I (64) boot: SPI Speed      : 40MHz
>     I (68) boot: SPI Mode       : DIO
>     I (72) boot: SPI Flash Size : 4MB
>     I (76) boot: Partition Table:
>     I (79) boot: ## Label            Usage          Type ST Offset   Length
>     I (87) boot:  0 nvs              WiFi data        01 02 0000a000 00006000
>     I (94) boot:  1 phy_init         RF data          01 01 00010000 00001000
>     I (102) boot:  2 factory          factory app      00 00 00020000 00100000
>     I (109) boot: End of partition table
>     E (113) esp_image: image at 0x20000 has invalid magic byte
>     W (120) esp_image: image at 0x20000 has invalid SPI mode 108
>     W (126) esp_image: image at 0x20000 has invalid SPI size 11
>     E (132) boot: Factory app partition is not bootable
>     E (138) boot: No bootable app partitions in the partition table

## ESP32-C5 Flash Encryption Status

Ensure that you have an ESP32-C5 device with default flash encryption eFuse settings as shown in Relevant eFuses.

To check if flash encryption on your ESP32-C5 device is enabled, do one of the following:

- flash the application example security/flash_encryption onto your device. This application prints the `SPI_BOOT_CRYPT_CNT` eFuse value and if flash encryption is enabled or disabled.

- Find the serial port name under which your ESP32-C5 device is connected, replace `PORT` with your port name in the following command, and run it:

      idf.py efuse-summary

## Reading and Writing Data in Encrypted Flash

ESP32-C5 application code can check if flash encryption is currently enabled by calling `esp_efuse_is_flash_encryption_enabled()`. Also, a device can identify the flash encryption mode by calling `esp_get_flash_encryption_mode()`.

Once flash encryption is enabled, be more careful with accessing flash contents from code.

### Scope of Flash Encryption

Whenever the `SPI_BOOT_CRYPT_CNT` eFuse is set to a value with an odd number of bits, all flash content accessed via the MMU's flash cache is transparently decrypted. It includes:

- Executable application code in flash (IROM).

- All read-only data stored in flash (DROM).

- Any data accessed via `spi_flash_mmap()`.

- The second stage bootloader image when it is read by the first stage (ROM) bootloader.

Important

The MMU flash cache unconditionally decrypts all existing data. Data which is stored unencrypted in flash memory will also be "transparently decrypted" via the flash cache and will appear to software as random garbage.

### Reading from Encrypted Flash

To read data without using a flash cache MMU mapping, you can use the partition read function `esp_partition_read()`. This function will only decrypt data when it is read from an encrypted partition. Data read from unencrypted partitions will not be decrypted. In this way, software can access encrypted and non-encrypted flash in the same way.

You can also use the following SPI flash API functions:

- `esp_flash_read()` to read raw (encrypted) data which will not be decrypted

- `esp_flash_read_encrypted()` to read and decrypt data

Data stored using the Non-Volatile Storage (NVS) API is always stored and read decrypted from the perspective of flash encryption. It is up to the library to provide encryption feature if required. Refer to NVS Encryption for more details.

### Writing to Encrypted Flash

It is recommended to use the partition write function `esp_partition_write()`. This function will only encrypt data when it is written to an encrypted partition. Data written to unencrypted partitions will not be encrypted. In this way, software can access encrypted and non-encrypted flash in the same way.

You can also pre-encrypt and write data using the function `esp_flash_write_encrypted()`

Also, the following ROM functions exist but are not supported in ESP-IDF applications:

- `esp_rom_spiflash_write_encrypted` pre-encrypts and writes data to flash

- `SPIWrite` writes unencrypted data to flash

Since data is encrypted in blocks, the minimum write size for encrypted data is 16 bytes and the alignment is also 16 bytes.

## Updating Encrypted Flash

### OTA Updates

OTA updates to encrypted partitions will automatically write encrypted data if the function `esp_partition_write()` is used.

Before building the application image for OTA updating of an already encrypted device, enable the option Enable flash encryption on boot in project configuration menu.

For general information about ESP-IDF OTA updates, please refer to OTA.

### Updating Encrypted Flash via Serial

Flashing an encrypted device via serial bootloader requires that the serial bootloader download interface has not been permanently disabled via eFuse.

In development mode, the recommended method is Re-flashing Updated Partitions.

In release mode, if a copy of the same key stored in eFuse is available on the host then it is possible to pre-encrypt files on the host and then flash them. See Manually Encrypting Files.

## Disabling Flash Encryption

If flash encryption was enabled accidentally, flashing of plaintext data will soft-brick the ESP32-C5. The device will reboot continuously, printing the error `flash read err, 1000` or `invalid header: 0xXXXXXX`.

For flash encryption in development mode, encryption can be disabled by burning the `SPI_BOOT_CRYPT_CNT` eFuse. It can only be done one time per chip by taking the following steps:

1. In Editing the Configuration, disable Enable flash encryption on boot, then save and exit.

2. Open project configuration menu again and double-check that you have disabled this option! If this option is left enabled, the bootloader will immediately re-enable encryption when it boots.

3. With flash encryption disabled, build and flash the new bootloader and application by running `idf.py flash`.

4. Use `idf.py` to disable the `SPI_BOOT_CRYPT_CNT` by running:

>     idf.py efuse-burn SPI_BOOT_CRYPT_CNT

Reset the ESP32-C5. Flash encryption will be disabled, and the bootloader will boot as usual.

## Key Points About Flash Encryption

- Flash memory contents are encrypted using XTS-AES-128 or XTS-AES-256. The flash encryption key is 256 bits and 512 bits respectively and stored in one or two `BLOCK_KEYN` eFuses internal to the chip and, by default, is protected from software access.

- Flash access is transparent via the flash cache mapping feature of ESP32-C5 - any flash regions which are mapped to the address space will be transparently decrypted when read.

  Some data partitions might need to remain unencrypted for ease of access or might require the use of flash-friendly update algorithms which are ineffective if the data is encrypted. NVS partitions for non-volatile storage cannot be encrypted since the NVS library is not directly compatible with flash encryption. For details, refer to NVS Encryption.

- If flash encryption might be used in future, the programmer must keep it in mind and take certain precautions when writing code that uses encrypted flash.

- If secure boot is enabled, re-flashing the bootloader of an encrypted device requires a "Re-flashable" secure boot digest (see Flash Encryption and Secure Boot).

Enabling flash encryption will increase the size of bootloader, which might require updating partition table offset. See Bootloader Size.

Important

Do not interrupt power to the ESP32-C5 while the first boot encryption pass is running. If power is interrupted, the flash contents will be corrupted and will require flashing with unencrypted data again. In this case, re-flashing will not count towards the flashing limit.

## Limitations of Flash Encryption

Flash encryption protects firmware against unauthorised readout and modification. It is important to understand the limitations of the flash encryption feature:

- Flash encryption is only as strong as the key. For this reason, we recommend keys are generated on the device during first boot (default behaviour). If generating keys off-device, ensure proper procedure is followed and do not share the same key between all production devices.

- Not all data is stored encrypted. If storing data on flash, check if the method you are using (library, API, etc.) supports flash encryption.

- Flash encryption does not prevent an attacker from understanding the high-level layout of the flash. This is because the same AES key is used for every pair of adjacent 16 byte AES blocks. When these adjacent 16 byte blocks contain identical content (such as empty or padding areas), these blocks will encrypt to produce matching pairs of encrypted blocks. This may allow an attacker to make high-level comparisons between encrypted devices (i.e., to tell if two devices are probably running the same firmware version).

- Flash encryption alone may not prevent an attacker from modifying the firmware of the device. To prevent unauthorised firmware from running on the device, use flash encryption in combination with Secure Boot.

## Flash Encryption and Secure Boot

It is recommended to use flash encryption in combination with Secure Boot. However, if Secure Boot is enabled, additional restrictions apply to device re-flashing:

- OTA Updates are not restricted, provided that the new app is signed correctly with the Secure Boot signing key.

- It is recommended that the required strength of the Pseudo-Round Function should be set during the first boot when flash encryption release mode is enabled. If your workflow needs to update the function's strength after the first boot, you should enable CONFIG_SECURE_BOOT_SKIP_WRITE_PROTECTION_SCA to avoid write-protecting this bit during boot.

## Advanced Features

The following section covers advanced features of flash encryption.

### Encrypted Partition Flag

Some partitions are encrypted by default. Other partitions can be marked in the partition table description as requiring encryption by adding the flag `encrypted` to the partitions' flag field. As a result, data in these marked partitions will be treated as encrypted in the same manner as an app partition.

    # Name,   Type, SubType, Offset,  Size, Flags
    nvs,      data, nvs,     0x9000,  0x6000
    phy_init, data, phy,     0xf000,  0x1000
    factory,  app,  factory, 0x10000, 1M
    secret_data, 0x40, 0x01, 0x20000, 256K, encrypted

For details on partition table description, see partition table.

Further information about encryption of partitions:

- Default partition tables do not include any encrypted data partitions.

- With flash encryption enabled, the `app` partition is always treated as encrypted and does not require marking.

- If flash encryption is not enabled, the flag "encrypted" has no effect.

- You can also consider protecting `phy_init` data from physical access, readout, or modification, by marking the optional `phy` partition with the flag `encrypted`.

- The `nvs` partition cannot be encrypted, because the NVS library is not directly compatible with flash encryption.

### Enabling UART Bootloader Encryption/Decryption

On the first boot, the flash encryption process burns by default the following eFuses:

- `DIS_DOWNLOAD_MANUAL_ENCRYPT` which disables flash encryption operation when running in UART bootloader boot mode.

- `DIS_PAD_JTAG` and `DIS_USB_JTAG` which disables JTAG.

- `DIS_DIRECT_BOOT` (old name `DIS_LEGACY_SPI_BOOT`) which disables direct boot mode

However, before the first boot you can choose to keep any of these features enabled by burning only selected eFuses and write-protect the rest of eFuses with unset value 0. For example:

    idf.py --port PORT efuse-burn DIS_DOWNLOAD_MANUAL_ENCRYPT
    idf.py --port PORT efuse-write-protect DIS_DOWNLOAD_MANUAL_ENCRYPT

Note

Set all appropriate bits before write-protecting!

Write protection of all the three eFuses is controlled by one bit. It means that write-protecting one eFuse bit will inevitably write-protect all unset eFuse bits.

Write protecting these eFuses to keep them unset is not currently very useful, as `esptool` does not support reading encrypted flash.

### JTAG Debugging

By default, when Flash Encryption is enabled (in either development or release mode) then JTAG debugging is disabled via eFuse. The bootloader does this on first boot, at the same time it enables flash encryption.

See JTAG with Flash Encryption or Secure Boot for more information about using JTAG Debugging with Flash Encryption.

### Manually Encrypting Files

Manually encrypting or decrypting files require the flash encryption key to be deployed in the Key Manager or pre-burned in eFuses (see Using Host Generated Key) and a copy to be kept on the host. If the flash encryption is configured in development mode, then it is not necessary to keep a copy of the key or follow these steps. The simpler Re-flashing Updated Partitions steps can be used.

The key file should be a single raw binary file (example: `key.bin`).

For example, these are the steps to encrypt the file `my-app.bin` to flash at offset 0x10000. Run `idf.py` as follows:

    idf.py secure-encrypt-flash-data --aes-xts --keyfile /path/to/key.bin --address 0x10000 --output my-app-ciphertext.bin my-app.bin

The file `my-app-ciphertext.bin` can then be flashed to offset 0x10000 using `esptool`. To see all of the command line options recommended for `esptool`, see the output printed when `idf.py build` succeeds.

Note

If the flashed ciphertext file is not recognized by the ESP32-C5 when it boots, check that the keys match and that the command line arguments match exactly, including the correct offset.

The command `idf.py decrypt-flash-data` can be used with the same options (and different input/output files), to decrypt ciphertext flash contents or a previously encrypted file.

## External RAM

When Flash Encryption is enabled any data read from and written to external SPI RAM through the cache can also be encrypted/decrypted. On ESP32-C5, PSRAM encryption can be controlled on a per-MMU-page basis, allowing individual PSRAM pages to be selectively encrypted or left unencrypted. However, in the default configuration, all PSRAM pages are encrypted when flash encryption is enabled.

On ESP32-C5, PSRAM encryption can use an independent encryption key. If the PSRAM encryption key is not programmed, the flash encryption key will be used as the PSRAM encryption key.

## Technical Details

The following sections provide some reference information about the operation of flash encryption.

### Flash Encryption Algorithm

- ESP32-C5 use the XTS-AES block cipher mode with 256-bit or 512-bit key size for flash encryption.

- XTS-AES is a block cipher mode specifically designed for disc encryption and addresses the weaknesses other potential modes (e.g., AES-CTR) have for this use case. A detailed description of the XTS-AES algorithm can be found in IEEE Std 1619-2007.

- The flash encryption key is stored in one or two `BLOCK_KEYN` eFuses and, by default, is protected from further writes or software readout.

- To see the full flash encryption algorithm implemented in Python, refer to the `_flash_encryption_operation()` function in the `espsecure` source code.

## Protection Against Side-Channel Attacks

### Pseudo-Round Function

ESP32-C5 incorporates a pseudo-round function in the XTS-AES peripheral, thus enabling the peripheral to randomly insert pseudo-rounds before and after the original operation rounds and also generate a pseudo key to perform these dummy operations. These operations do not alter the original result, but they increase the complexity to perform side channel analysis attacks by randomizing the power profile.

CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC_STRENGTH can be used to select the strength of the pseudo-round function. Increasing the strength improves the security provided, but would slow down the XTS-AES operations.

Performance impact on XTS-AES operations per strength level
Strength | Performance Impact [1]
--- | ---
Low | < 0.5 %
Medium | 6.2 %
High | 18 %

[1]

The above performance numbers have been calculated using the XTS-AES test of the HAL crypto test app test_xts_aes.c .

You can configure the strength of the pseudo rounds functions according to your use cases. For example, increasing the strength would provide higher security but would slow down the flash encryption/decryption operations.

Considering the above performance impact, ESP-IDF by-default enables low strength configuration for the pseudo-round function for minimal performance impact.

Was this page helpful?

- Thank you! We received your feedback.
- If you have any comments, fill in Espressif Documentation Feedback Form.

- We value your feedback.
- Let us know how we can improve this page by filling in Espressif Documentation Feedback Form.