Burn Key

The espefuse.py burn_key command burns keys to eFuse blocks:

Positional arguments:

  • block - Name of key block.

  • Keyfile. It is a raw binary file. It must contain 256 bits of binary key if the coding scheme is None and 128 bits if 3/4.

It can be list of key blocks and keyfiles (like BLOCK1 file1.bin BLOCK2 file2.bin etc.).

Optional arguments:

  • --no-protect-key. Disable default read and write protecting of the key. If this option is not set, once the key is flashed it can not be read back.

  • --force-write-always. Write the eFuse key even if it looks like it is already been written, or is write protected. Note that this option can’t disable write protection, or clear any bit which has already been set.

  • --show-sensitive-info. Show data to be burned (may expose sensitive data). Enabled if –debug is used. Use this option to see the byte order of the data being written.

ESP32 supports keys:

  • Secure boot key. Use secure_boot_v1 or secure_boot_v2 as block name. The key is placed in BLOCK2.

  • Flash encryption key. Use flash_encryption as block name. The key is placed in BLOCK1.

Keys for flash_encryption and secure_boot_v1 will be burned as read and write protected. The hardware will still have access to them. These keys are burned in reversed byte order.

Key for secure_boot_v2 will be burned only as write protected. The key must be readable because the software need access to it.

Warning

Do not use the names BLOCK1 and BLOCK2 to burn flash encryption and secure boot v2 keys because byte order will be incorrect and read protection will not meet security requirements.

Key Coding Scheme

When the None coding scheme is in use, keys are 256-bits (32 bytes) long. When 3/4 Coding Scheme is in use (CODING_SCHEME eFuse has value 1 not 0), keys are 192-bits (24 bytes) long and an additional 64 bits of error correction data are also written. espefuse v2.6 or newer supports the 3/4 Coding Scheme. The key file must be the appropriate length for the coding scheme currently in use.

Unprotected Keys

By default, when an encryption key block is burned it is also read and write protected.

The --no-protect-key option will disable this behaviour (you can separately read or write protect the key later).

Note

Leaving a key unprotected may compromise its use as a security feature.

espefuse.py burn_key secure_boot_v1 secure_boot_key_v1.bin

Note that the hardware flash encryption and secure boot v1 features require the key to be written to the eFuse block in reversed byte order, compared to the order used by the AES algorithm on the host. Using corresponding block name, the tool automatically reverses the bytes when writing. For this reason, an unprotected key will read back in the reverse order.

Force Writing a Key

Normally, a key will only be burned if the efuse block has not been previously written to. The --force-write-always option can be used to ignore this and try to burn the key anyhow.

Note that this option is still limited by the eFuse hardware - hardware does not allow any eFuse bits to be cleared 1->0, and can not write anything to write protected eFuse blocks.

Usage

> espefuse.py burn_key flash_encryption  256bit_fe_key.bin

=== Run "burn_key" command ===
Sensitive data will be hidden (see --show-sensitive-info)
Burn keys to blocks:
- BLOCK1 -> [?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??]
        Reversing the byte order
        Disabling read to key block
        Disabling write to key block

Burn keys in efuse blocks.
The key block will be read and write protected

Check all blocks for burn...
idx, BLOCK_NAME,          Conclusion
[00] BLOCK0               is empty, will burn the new value
[01] BLOCK1               is empty, will burn the new value
.
This is an irreversible operation!
Type 'BURN' (all capitals) to continue.
BURN
BURN BLOCK1  - OK (write block == read block)
BURN BLOCK0  - OK (write block == read block)
Reading updated efuses...
Successful
> espefuse.py summary
...
BLOCK1 (BLOCK1):                                   Flash encryption key
= ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? -/-

Byte order for flash encryption key is reversed. Content of flash encryption key file (“256bit_fe_key.bin”):

0001 0203 0405 0607 0809 0a0b 0c0d 0e0f  1011 1213 1415 1617 1819 1a1b 1c1d 1e1f

When the no protection option is used then you can see the burned key:

> espefuse.py burn_key flash_encryption  256bit_fe_key.bin --no-protect-key

=== Run "burn_key" command ===
Sensitive data will be hidden (see --show-sensitive-info)
Burn keys to blocks:
- BLOCK1 -> [?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??]
        Reversing the byte order

Key is left unprotected as per --no-protect-key argument.
Burn keys in efuse blocks.
The key block will left readable and writeable (due to --no-protect-key)

Check all blocks for burn...
idx, BLOCK_NAME,          Conclusion
[01] BLOCK1               is empty, will burn the new value
.
This is an irreversible operation!
Type 'BURN' (all capitals) to continue.
BURN
BURN BLOCK1  - OK (write block == read block)
Reading updated efuses...
Successful
> espefuse.py summary
...
BLOCK1 (BLOCK1):                                   Flash encryption key
= 1f 1e 1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10 0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 R/W