Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
---|
This example demonstrates OTA updates with pre-encrypted binary using esp_encrypted_img
component's APIs and tool.
Pre-encrypted firmware binary must be hosted on OTA update server.
This firmware will be fetched and then decrypted on device before being flashed.
This allows firmware to remain confidential
on the OTA update channel irrespective of underlying transport (e.g., non-TLS).
Caution
Using the Pre-encrypted Binary OTA provides confidentiality of the firmware, but it does not ensure authenticity of the firmware. For ensuring that the firmware is coming from trusted source, please consider enabling secure boot feature along with the Pre-encrypted binary OTA. Please refer to security guide in the ESP-IDF docs for more details.
This example uses esp_encrypted_img
component hosted at idf-extra-components/esp_encrypted_img and available though the IDF component manager.
Please refer to its documentation here for more details.
This example can use either RSA or ECIES-P256 for pre-encrypted OTA. You must first select your desired scheme:
idf.py menuconfig
.Component config
-> Pre Encrypted OTA Configuration
.Pre-encrypted OTA Scheme
to your choice:RSA-3072 encryption
ECIES encryption
ECIES encryption
and will be using the HMAC-derived key, ensure HMAC EFUSE KEY ID
is set to the eFuse block where ecc_key/device_hmac_key.bin
will be burned.Once the scheme is selected, follow the relevant sub-section below for key generation and specific setup.
You can generate a public and private RSA key pair using the esp_enc_img_gen.py
tool or openssl
.
Using esp_enc_img_gen.py
:
Bash
python esp_enc_img_gen.py --generate_rsa_key
This will create rsa_pub_key.pem
and rsa_priv_key.pem
in the current directory.
Using openssl
:
openssl genrsa -out rsa_key/private.pem 3072
This generates a 3072-bit RSA key pair, and writes them to a file.
Private key is required for decryption process and is used as input to the esp_encrypted_img
component. Private key can either be embedded into the firmware or stored in NVS.
Encrypted image generation tool will derive public key (from private key) and use it for encryption purpose.
To test the ECIES-based encryption scheme:
Configure for ECIES (Ensure ECIES encryption
is selected in menuconfig
as described above):
idf.py menuconfig
(if not already done, or to verify).Component config
-> Pre Encrypted OTA Configuration
.ECIES encryption
for the Pre-encrypted OTA Scheme
.HMAC EFUSE KEY ID
to the eFuse block number (0-5) where you will burn the ecc_key/device_hmac_key.bin
. The default is -1 (disabled), so this must be changed.Key Management:
ecc_key/
directory (relative to this example).ecc_key/device_hmac_key.bin
: The HMAC key that needs to be burned into the device's eFuse.ecc_key/public.pem
: The device public key, derived from device_hmac_key.bin
. This key will be used by the build system to encrypt the firmware.idf.py efuse-burn-key
command to burn the ecc_key/device_hmac_key.bin
to the eFuse block you configured in menuconfig
.
For example, if you set HMAC EFUSE KEY ID
to 0:Bash
idf.py efuse-burn-key BLOCK_KEY0 ecc_key/device_hmac_key.bin HMAC_UP
Replace BLOCK_KEY0
with the correct eFuse block if you chose a different ID (e.g., BLOCK_KEY1
for ID 1).
* (Alternative) Generate New Keys: If you prefer not to use the provided keys, you can generate a new set:
bash python <path_to_esp_encrypted_img>/tools/esp_enc_img_gen.py --generate_ecc_key
This will create device_hmac_key.bin
and device_pub_key.pem
in the current directory. You would then need to:
1. Replace ecc_key/device_hmac_key.bin
and ecc_key/public.pem
with these new files (or update the example to point to them).
2. Burn the new device_hmac_key.bin
to the eFuse.
ecc_key/public.pem
) to generate build/pre_encrypted_ota_secure.bin
.ecc_key/
directory are for demonstration purposes only. We recommend creating a new key pair for production applications.Plaintext
idf.py build flash
build/pre_encrypted_ota_secure.bin
) to a server for performing OTA update.After a successful build, we need to create a self-signed certificate and run a simple HTTPS server as follows:
cd server_certs
.openssl req -x509 -newkey rsa:2048 -keyout ca_key.pem -out ca_cert.pem -days 365 -nodes
.Common Name (CN)
, enter the name of the server that the "ESP-Dev-Board" will connect to. When running this example from a development machine, this is probably the IP address. The HTTPS client will check that the CN
matches the address given in the HTTPS URL.You can start the server using following instructions:
After the successful build, start the local python based HTTPS server using the certificate and key present in the 'server_certs' directory (certificate: ca_cert.pem and key: ca_key.pem).
To start the server use the following command -
Plaintext
python pytest_pre_encrypted_ota.py build 8070 server_certs
pytest_pre_encrypted_ota.py
without passing server_certs
directory, the server will use the hardcoded certificates present in pytest_pre_encrypted_ota.py
Refer the README.md in the parent directory for the setup details.
To create a project from this example, run:
idf.py create-project-from-example "espressif/esp_encrypted_img=2.4.0:pre_encrypted_ota"