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. The length of binary key depends on the key purpose option.

  • Key purpose. The purpose of this key.

It can be list of key blocks and keyfiles and key purposes (like BLOCK_KEY1 file1.bin USER BLOCK_KEY2 file2.bin USER etc.).

Optional arguments:

  • --no-write-protect. Disable write-protecting of the key. The key remains writable. The keys use the RS coding scheme that does not support post-write data changes. Forced write can damage RS encoding bits. The write-protecting of keypurposes does not depend on the option, it will be set anyway.

  • --no-read-protect. Disable read-protecting of the key. The key remains readable software. The key with keypurpose [USER, RESERVED and .._DIGEST] will remain readable anyway, but for the rest keypurposes the read-protection will be defined by this option (Read-protect by default).

  • --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-C2 has only one eFuse key block (256 bits long). It is block #3 - BLOCK_KEY0. This block can have user, flash encryption, secure boot keys. This chip does not have any eFuse key purpose fields, but we use the key purpose option to distinguish between such keys. The key purpose option determines protection and byte order for key.

  • USER

  • XTS_AES_128_KEY. 256 bits flash encryption key. The secure boot key can not be used with this option. In addition, eFuse XTS_KEY_LENGTH_256 is set to 1, which means that the flash encryption key is 256 bits long.

  • XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS. 128 bits flash encryption key. The 128 bits of this key will be burned to the low part of the eFuse block. These bits will be read protected.

  • SECURE_BOOT_DIGEST. Secure boot key. The first 128 bits of key will be burned to the high part of the eFuse block.

ESP32-C2 can have in eFuse block the following combination of keys:

  1. Both, Flash encryption (low 128 bits of eFuse block) and Secure boot key (high 128 bits of eFuse block).

  2. only Flash encryption (low 128 bits of eFuse block), rest part of eFuse block is not possible to use in future.

  3. only Flash encryption key (256 bits long), whole eFuse key block.

  4. only Secure boot key (high 128 bits of eFuse block).

  5. no keys, used for user purposes. Chip does not have security features.

All keys will be burned with write protection if --no-write-protect is not used.

Only flash encryption key is read protected if --no-read-protect is not used.

All keys, except flash encryption, will be burned in direct byte order. The encryption key is written in reverse byte order for compatibility with encryption hardware.

Unprotected Keys

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

The --no-read-protect and --no-write-protect options 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

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 -c esp32c2  \
                        burn_key_digest secure_images/ecdsa256_secure_boot_signing_key_v2.pem \
                        burn_key BLOCK_KEY0 images/efuse/128bit_key.bin XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS

=== 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...