1、You can baes on the esp-idf/examples/security/flash_encryption exmaple for testing
2、Partition-table Setting:
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, , 0x6000,
# Extra partition to demonstrate reading/writing of encrypted flash
storage, data, 0xff, , 0x1000, encrypted
factory, app, factory, , 1M,
# nvs_key partition contains the key that encrypts the NVS partition named nvs. The nvs_key partition needs to be encrypted.
nvs_key, data, nvs_keys, , 0x1000, encrypted,
# Custom NVS data partition
custom_nvs, data, nvs, , 0x6000,
# FATFS partitions, one non-encrypted, one encrypted
fat_encrypted, data, fat, , 600k, encrypted
fat_not_encr, data, fat, , 600k,
3、Generate various Key files
Since ESP32-C2 has only one 256-bit eFuse BLOCK
, when the Secure Boot V2 and Flash encryption functions are enabled simultaneously, Only support use of 128-bit Secure Boot Key
and 128-bit Flash encryption Key
.
① Generate 128-bit Secure Book V2
private Key
-
Generate
ECDSA256
Secure Boot V2 keyespsecure.py generate_signing_key --version 2 --scheme ecdsa256 ecdsa256_secure_boot_signing_key.pem
- And setting use
ECDSA256(128-bit)
Key
② Base on the 128-bit Secure Boot V2
private Key to generate summary of public key
- Generate
ECDSA256
Secure Boot V2 key summary of public key
espsecure.py digest_sbv2_public_key --keyfile ecdsa256_secure_boot_signing_key.pem --output 256_public_key_digest.bin
③ Generate Flash Encryption
Key
- Generate
SHA256(128-bit)
Flash Encryption key
espsecure.py generate_flash_encryption_key --keylen 128 128_flash_encryption_key.bin
- And setting use 128-bits Flash Encryption key.
④ Generate the NVS encryption key
If you want to encrypt the NVS partition , then you need to do it.
python E:\esp2\Espressif\frameworks\esp-idf-v5.4\esp-idf\components\nvs_flash\nvs_partition_generator\nvs_partition_gen.py generate-key --keyfile nvs_key.bin
4、Software Setting:
-
→ Flash Size Setting:
The value of Flash Size must not be larger than the hardware Flash Size and must not be smaller than the total partition size set in the partition table.
-
→ Partition Table setting:
Enabling flash encryption will increase the size of bootloader, which might require updating partition table offset. See Bootloader Size.
-
Chip version setting:
Select the chip version as needed
-
Flash encryption and Secure Boot V2 mode Settings
- Secure Boot V2 use
ECDSA256(128-bit)
Key - Flash Encryption use
SHA256(128-bit)
key
→ Security features
- Secure Boot V2 use
-
The download mode setting:Retain the download mode
If you want to retain the download mode, yoou needto do it.
→ Security features → UART ROM download mode → (X) UART ROM download mode (Enabled (not recommended))
-
NVS Encryption Setting
If you want Encryption the NVS partition, you need to it.
→ Component config → NVS → [*] Enable NVS encryption
5、Compile the project
idf.py build
- Check the compilation log to obtain the download addresses of each partition:
*******************************************************************************
# ESP-IDF Partition Table
# Name, Type, SubType, Offset, Size, Flags
nvs,data,nvs,0xe000,24K,
storage,data,255,0x14000,4K,encrypted
factory,app,factory,0x20000,1M,
nvs_key,data,nvs_keys,0x120000,4K,encrypted
custom_nvs,data,nvs,0x121000,24K,
fat_encrypted,data,fat,0x127000,600K,encrypted
fat_not_encr,data,fat,0x1bd000,600K,
*******************************************************************************
- Check the compilation log to obtain the firmware to be downloaded:
0x0 build\bootloader\bootloader.bin
0xd000 build\partition_table\partition-table.bin
0x20000 build\flash_encryption.bin
Because NVS encryption is enabled, therefore nvs_key.bin
needs to be downloaded together with the application firmware
0x0 : bootloadet.bin
0xd000 :partition-table.bin
0x20000 : flash_encryption.bin
0x120000 : nvs_key.bin
6、Use the Flash encryption Key to encrypt the firmware to be downloaded
Note: According to the corresponding bin files that need to be burned to use encryption commands
The firmware that needs to be encrypted are as follows:
- Signed
bootloader.bin
partition-table.bin
- signed
app.bin
- Used for
nvs partition
Encryptionnvs_key.bin
: Since the nvs_key partition is marked withencrypted
, it is necessary to encrypt thenvs_key.bin
using the Flash encryption key.
The esptool command as follows:
- Use
128_flash_encryption_key.bin
to encrypt the signedbootloader.bin
to get the encryptedbootloader.bin
espsecure.py encrypt_flash_data --aes_xts --keyfile E:\esp2\Espressif\frameworks\esp-idf-v5.4\esp-idf\examples\security\flash_encryption\128_flash_encryption_key.bin --output E:\esp2\Espressif\frameworks\esp-idf-v5.4\esp-idf\examples\security\flash_encryption\0x0-bootloader-encrypted.bin --address 0x0 E:\esp2\Espressif\frameworks\esp-idf-v5.4\esp-idf\examples\security\flash_encryption\build\bootloader\bootloader.bin
- Use
128_flash_encryption_key.bin
to encryptpartition-table.bin
to get the encryptedpartition-table.bin
espsecure.py encrypt_flash_data --aes_xts --keyfile E:\esp2\Espressif\frameworks\esp-idf-v5.4\esp-idf\examples\security\flash_encryption\128_flash_encryption_key.bin --output 0xd000-partition-encrypted.bin --address 0xd000 E:\esp2\Espressif\frameworks\esp-idf-v5.4\esp-idf\examples\security\flash_encryption\build\partition_table\partition-table.bin
- Use
128_flash_encryption_key.bin
to encryptflash_encryption.bin
to get the encryptedapp.bin
espsecure.py encrypt_flash_data --aes_xts --keyfile E:\esp2\Espressif\frameworks\esp-idf-v5.4\esp-idf\examples\security\flash_encryption\128_flash_encryption_key.bin --output 0x20000-flash-encryption-encrypted.bin --address 0x20000 E:\esp2\Espressif\frameworks\esp-idf-v5.4\esp-idf\examples\security\flash_encryption\build\flash_encryption.bin
- Use
128_flash_encryption_key.bin
to encryptnvs_key.bin
to get the encryptednvs_key.bin
Since thenvs_key
partition is marked withencrypted
, it is necessary to encrypt thenvs_key.bin
using the Flash encryption key.
espsecure.py encrypt_flash_data --aes_xts --keyfile E:\esp2\Espressif\frameworks\esp-idf-v5.4\esp-idf\examples\security\flash_encryption\128_flash_encryption_key.bin --output 0x120000-nvs-key-encrypted.bin --address 0x120000 E:\esp2\Espressif\frameworks\esp-idf-v5.4\esp-idf\examples\security\flash_encryption\keys\nvs_key.bin
7、Write the encrypted firmware to Flash
esptool.py -p COM69 write_flash 0x0 0x0-bootloader-encrypted.bin 0xd000 0xd000-partition-encrypted.bin 0x20000 0x20000-flash-encryption-encrypted.bin 0x120000 0x120000-nvs-key-encrypted.bin
Log:
E:\esp2\Espressif\frameworks\esp-idf-v5.4\esp-idf\examples\security\flash_encryption>esptool.py -p COM69 write_flash 0x0 0x0-bootloader-encrypted.bin 0xd000 0xd000-partition-encrypted.bin 0x20000 0x20000-flash-encryption-encrypted.bin 0x120000 0x120000-nvs-key-encrypted.bin
esptool.py v4.8.1
Serial port COM69
Connecting....
Detecting chip type... ESP32-C2
Chip is ESP32-C2 (revision v1.0)
Features: WiFi, BLE
Crystal is 26MHz
MAC: 08:3a:8d:40:9e:c0
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Flash will be erased from 0x00000000 to 0x00007fff...
Flash will be erased from 0x0000d000 to 0x0000dfff...
Flash will be erased from 0x00020000 to 0x00060fff...
Flash will be erased from 0x00120000 to 0x00120fff...
Compressed 29984 bytes to 30000...
Wrote 29984 bytes (30000 compressed) at 0x00000000 in 3.0 seconds (effective 80.7 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 3083...
Wrote 3072 bytes (3083 compressed) at 0x0000d000 in 0.3 seconds (effective 76.2 kbit/s)...
Hash of data verified.
Compressed 266240 bytes to 266331...
Wrote 266240 bytes (266331 compressed) at 0x00020000 in 70.0 seconds (effective 30.4 kbit/s)...
Hash of data verified.
Compressed 4096 bytes to 4107...
Wrote 4096 bytes (4107 compressed) at 0x00120000 in 0.4 seconds (effective 82.1 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
8、Write the key to eFuse BLOCK
- Wrute
Secure Boot V2
public key to efuse - Write
Flash Encryption
Key to efuse
espefuse.py -p COM69 burn_key_digest ecdsa256_secure_boot_signing_key.pem burn_key BLOCK_KEY0 128_flash_encryption_key.bin XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS
Log:
E:\esp2\Espressif\frameworks\esp-idf-v5.4\esp-idf\examples\security\flash_encryption>espefuse.py -p COM69 burn_key_digest ecdsa256_secure_boot_signing_key.pem burn_key BLOCK_KEY0 128_flash_encryption_key.bin XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS
espefuse.py v4.8.1
Connecting....
Detecting chip type... ESP32-C2
=== Run "burn_key_digest" command ===
Sensitive data will be hidden (see --show-sensitive-info)
Burn keys to blocks:
- BLOCK_KEY0_HI_128 -> [?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??]
Disabling write to key block
Batch mode is enabled, the burn will be done at the end of the command.
=== Run "burn_key" command ===
Sensitive data will be hidden (see --show-sensitive-info)
Burn keys to blocks:
- BLOCK_KEY0_LOW_128 -> [?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??]
Reversing byte order for AES-XTS hardware peripheral
Disabling read to key block
Disabling write to key block
The same value for WR_DIS is already burned. Do not change the efuse.
Batch mode is enabled, the burn will be done at the end of the command.
Check all blocks for burn...
idx, BLOCK_NAME, Conclusion
[00] BLOCK0 is empty, will burn the new value
[03] BLOCK_KEY0 is empty, will burn the new value
.
This is an irreversible operation!
Type 'BURN' (all capitals) to continue.
BURN
BURN BLOCK3 - OK (write block == read block)
BURN BLOCK0 - OK (write block == read block)
Reading updated efuses...
Successful
9、Write various efuse control bits as required
-
When set the Flash Encrypption Development mode on the software,need to write the follows efuse bits:
→ Security features → Enable flash encryption on boot (READ DOCS FIRST) → Enable usage mode
In here , we are set the Flash Encrypption Development mode on the software.
espefuse.py -p COM69 burn_efuse DIS_DOWNLOAD_ICACHE 0x1 DIS_PAD_JTAG 0x1 DIS_DIRECT_BOOT 0x1 SPI_BOOT_CRYPT_CNT 0x1 SECURE_BOOT_EN 0x1
- When set the Flash Encrypption Release mode onthe software,need to write the follows efuse bits:
→ Security features → Enable flash encryption on boot (READ DOCS FIRST) → Enable usage mode
espefuse.py -p COM69 burn_efuse DIS_DOWNLOAD_ICACHE 0x1 DIS_PAD_JTAG 0x1 DIS_DIRECT_BOOT 0x1 DIS_DOWNLOAD_MANUAL_ENCRYPT 0x1 SPI_BOOT_CRYPT_CNT 0x7 SECURE_BOOT_EN 0x1
Log:
E:\esp2\Espressif\frameworks\esp-idf-v5.4\esp-idf\examples\security\flash_encryption>espefuse.py -p COM69 burn_efuse DIS_DOWNLOAD_ICACHE 0x1 DIS_PAD_JTAG 0x1 DIS_DIRECT_BOOT 0x1 SPI_BOOT_CRYPT_CNT 0x1 SECURE_BOOT_EN 0x1
espefuse.py v4.8.1
Connecting....
Detecting chip type... ESP32-C2
=== Run "burn_efuse" command ===
The efuses to burn:
from BLOCK0
- DIS_DOWNLOAD_ICACHE
- DIS_PAD_JTAG
- DIS_DIRECT_BOOT
- SPI_BOOT_CRYPT_CNT
- SECURE_BOOT_EN
Burning efuses:
- 'DIS_DOWNLOAD_ICACHE' (The bit be set to disable icache in download mode) 0b0 -> 0b1
- 'DIS_PAD_JTAG' (Set this bit to disable pad jtag) 0b0 -> 0b1
- 'DIS_DIRECT_BOOT' (This bit set means disable direct_boot mode) 0b0 -> 0b1
- 'SPI_BOOT_CRYPT_CNT' (Enables flash encryption when 1 or 3 bits are set and disables otherwise) 0b000 -> 0b001
- 'SECURE_BOOT_EN' (The bit be set to enable secure boot) 0b0 -> 0b1
Check all blocks for burn...
idx, BLOCK_NAME, Conclusion
[00] BLOCK0 is not empty
(written ): 0x0000000100000080
(to write): 0x002080b000000000
(coding scheme = NONE)
.
This is an irreversible operation!
Type 'BURN' (all capitals) to continue.
BURN
BURN BLOCK0 - OK (all write block bits are set)
Reading updated efuses...
Checking efuses...
Successful
10、Firmware running:
ESP-ROM:esp8684-api2-20220127
Build:Jan 27 2022
rst:0x1 (POWERON),boot:0xc (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
Valid secure boot key blocks: 0
ECDSA secure boot verification succeeded
load:0x3fcd5d00,len:0x3164
load:0x403acb70,len:0xbb0
load:0x403aeb70,len:0x5430
entry 0x403acb7a
I (112) boot: ESP-IDF v5.4 2nd stage bootloader
I (113) boot: compile time Mar 25 2025 17:52:24
I (113) boot: chip revision: v1.0
I (113) boot: efuse block revision: v0.1
I (116) boot.esp32c2: MMU Page Size : 64K
I (120) boot.esp32c2: SPI Speed : 60MHz
I (124) boot.esp32c2: SPI Mode : DIO
I (128) boot.esp32c2: SPI Flash Size : 4MB
I (132) boot: Enabling RNG early entropy source...
I (137) boot: Partition Table:
I (139) boot: ## Label Usage Type ST Offset Length
I (146) boot: 0 nvs WiFi data 01 02 0000e000 00006000
I (152) boot: 1 storage Unknown data 01 ff 00014000 00001000
I (159) boot: 2 factory factory app 00 00 00020000 00100000
I (165) boot: 3 nvs_key NVS keys 01 04 00120000 00001000
I (172) boot: 4 custom_nvs WiFi data 01 02 00121000 00006000
I (179) boot: 5 fat_encrypted Unknown data 01 81 00127000 00096000
I (185) boot: 6 fat_not_encr Unknown data 01 81 001bd000 00096000
I (192) boot: End of partition table
I (195) esp_image: segment 0: paddr=00020020 vaddr=3c020020 size=0c000h ( 49152) map
I (215) esp_image: segment 1: paddr=0002c028 vaddr=3fcaa460 size=01484h ( 5252) load
I (216) esp_image: segment 2: paddr=0002d4b4 vaddr=40380000 size=02b64h ( 11108) load
I (222) esp_image: segment 3: paddr=00030020 vaddr=42000020 size=1be04h (114180) map
I (254) esp_image: segment 4: paddr=0004be2c vaddr=40382b64 size=078fch ( 30972) load
I (263) esp_image: segment 5: paddr=00053730 vaddr=00000000 size=0c8a0h ( 51360)
I (276) esp_image: Verifying image signature...
I (276) secure_boot_v2: Verifying with ECDSA...
ECDSA I (318) secure_boot_v2: Signature verified successfully!
I (322) boot: Loaded app from partition at offset 0x20000
I (322) secure_boot_v2: enabling secure boot v2...
I (322) secure_boot_v2: secure boot v2 is already enabled, continuing..
I (328) boot: Checking flash encryption...
I (332) flash_encrypt: flash encryption is enabled (1 plaintext flashes left)
I (339) boot: Disabling RNG early entropy source...
I (355) cpu_start: Unicore app
I (363) cpu_start: Pro cpu start user code
I (364) cpu_start: cpu freq: 120000000 Hz
I (364) app_init: Application information:
I (364) app_init: Project name: flash_encryption
I (368) app_init: App version: v5.4
I (372) app_init: Compile time: Mar 25 2025 17:52:06
I (377) app_init: ELF file SHA256: 428b02c86...
I (381) app_init: ESP-IDF: v5.4
I (385) efuse_init: Min chip rev: v1.0
I (389) efuse_init: Max chip rev: v2.99
I (393) efuse_init: Chip rev: v1.0
I (397) heap_init: Initializing. RAM available for dynamic allocation:
I (403) heap_init: At 3FCAC960 len 00030210 (192 KiB): RAM
I (408) heap_init: At 3FCDCB70 len 0000294C (10 KiB): RAM
I (414) spi_flash: detected chip: gd
I (417) spi_flash: flash io: dio
W (420) flash_encrypt: Flash encryption mode is DEVELOPMENT (not secure)
I (426) sleep_gpio: Configure to isolate all GPIO pins in sleep state
I (432) sleep_gpio: Enable automatic switching of GPIO sleep configuration
I (439) nvs_sec_provider: NVS Encryption - Registering Flash encryption-based scheme...
I (447) main_task: Started on CPU0
I (447) main_task: Calling app_main()
Example to check Flash Encryption status
This is esp32c2 chip with 1 CPU core(s), WiFi/BLE, silicon revision v1.0, 4MB embedded flash
FLASH_CRYPT_CNT eFuse value is 1
Flash encryption feature is enabled in DEVELOPMENT mode
Erasing partition "storage" (0x1000 bytes)
Writing data with esp_partition_write:
I (487) example: 0x3fcaf540 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................|
I (487) example: 0x3fcaf550 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f |................|
Reading with esp_partition_read:
I (497) example: 0x3fcaf560 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................|
I (507) example: 0x3fcaf570 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f |................|
Reading with esp_flash_read:
I (517) example: 0x3fcaf560 bf 82 77 6d 31 54 f0 46 87 0b 9d af 2c 65 a9 fd |..wm1T.F....,e..|
I (527) example: 0x3fcaf570 2f 72 77 1b 73 f4 51 73 09 73 bd 49 a6 7a 3f 09 |/rw.s.Qs.s.I.z?.|
I (537) example: Partitions fat_not_encr and fat_encrypted for FATFS example are present
I (547) example_fatfs: FAT partition "fat_not_encr" is not encrypted. Size is (0x96000 bytes)
I (557) example_fatfs: Formatting FAT filesystem
W (657) vfs_fat_spiflash: f_mount failed (13)
I (657) vfs_fat_spiflash: Formatting FATFS partition, allocation unit size=4096
I (927) vfs_fat_spiflash: Mounting again
I (997) example_fatfs: Mounting FAT filesystem
I (997) example_fatfs: Opening file
I (1197) example_fatfs: Written to file: 'the quick brown fox jumped over the lazy dog'
I (1197) example_fatfs: Reading file
I (1207) example_fatfs: Read from file: 'the quick brown fox jumped over the lazy dog'
I (1207) example_fatfs: Unmounting FAT filesystem
I (1277) example_fatfs: Read partition using esp_flash_read until test string is found
I (1327) example_fatfs: 0x3fcaf514 74 68 65 20 71 75 69 63 6b 20 62 72 6f 77 6e 20 |the quick brown |
I (1327) example_fatfs: 0x3fcaf524 66 6f 78 20 6a 75 6d 70 65 64 20 6f 76 65 72 20 |fox jumped over |
I (1337) example_fatfs: 0x3fcaf534 74 68 65 20 6c 61 7a 79 20 64 6f 67 |the lazy dog|
I (1347) example_fatfs: Test string was found at offset (0x8000)
I (1357) example_fatfs: FAT partition "fat_encrypted" is encrypted. Size is (0x96000 bytes)
I (1357) example_fatfs: Formatting FAT filesystem
W (1447) vfs_fat_spiflash: f_mount failed (13)
I (1447) vfs_fat_spiflash: Formatting FATFS partition, allocation unit size=4096
I (1657) vfs_fat_spiflash: Mounting again
I (1717) example_fatfs: Mounting FAT filesystem
I (1727) example_fatfs: Opening file
I (1927) example_fatfs: Written to file: 'the quick brown fox jumped over the lazy dog'
I (1927) example_fatfs: Reading file
I (1927) example_fatfs: Read from file: 'the quick brown fox jumped over the lazy dog'
I (1937) example_fatfs: Unmounting FAT filesystem
I (1987) example_fatfs: Read partition using esp_flash_read at expected offset (0x8000)
I (1987) example_fatfs: 0x3fcaf50c 12 a9 5f e0 fc 6a fd 4d 66 55 52 e1 a0 ba 94 65 |.._..j.MfUR....e|
I (1997) example_fatfs: 0x3fcaf51c 3b b3 ff 23 1f a6 d1 7e 5f 29 2f 2b 46 17 2c f1 |;..#...~_)/+F.,.|
I (2007) example_fatfs: 0x3fcaf52c 32 97 86 8e 13 c1 ab c8 f7 e6 d0 f8 |2...........|
I (2017) example_fatfs: Data does not match test string
I (2027) nvs: NVS partition "nvs" is encrypted.
I (2027) example: NVS partition "custom_nvs" is encrypted.
I (2027) main_task: Returned from app_main()