Using Secure Boot and Flash Encryption Together on ESP32 for Full Firmware Protection
You’re using Secure Boot V2 with your ESP32’s 3.0+ revision chip to verify the bootloader via a public key hash burned into EFUSE BLK2, paired with flash encryption-development mode allows reflashing, while release mode locks down SPI_BOOT_CRYPT_CNT and disables JTAG. Combine both for hardware-level protection, sign 3072-bit RSA-PSS images, and use HSM-backed keys to prevent exposure; testers confirm fewer boot failures when padding OTA apps to 4 KB with secure-pad-v2. Keep going to get the exact signing workflow that avoids bricking.
We are supported by our audience. When you purchase through links on our site, we may earn an affiliate commission, at no extra cost for you. Learn more. Last update on 30th May 2026 / Images from Amazon Product Advertising API.
Notable Insights
- Enable both Secure Boot V2 and flash encryption in menuconfig for comprehensive firmware protection on ESP32.
- Use a 3072-bit RSA signing key generated with idf.py and store the private key securely, preferably in an HSM.
- Burn the public key digest to EFUSE BLK2 and set ABS_DONE_1 to activate Secure Boot V2 permanently.
- In Release Mode, flash encryption locks eFuses and disables JTAG and UART download for enhanced security.
- Sign and encrypt firmware using idf.py secure-sign-data and idf.py encrypted-flash for secure deployment and OTA updates.
Use Secure Boot V2 to Verify ESP32 Firmware at Boot
Security starts at boot, and with Secure Boot V2 on the ESP32, you’re locking things down right from power-on. You’ll need an ESP32 with chip revision v3.0 or later-older ones won’t support it. When Secure Boot is enabled, the ROM bootloader performs signature verification on the second stage bootloader using a public key hash stored in eFuse BLK2. It checks the signature block’s magic byte (0xe7) and SHA-256 hash; mismatch, and boot halts. The block, 1216 bytes long, includes the RSA-PSS signature and key data. Using RSA-PSS with a 3072-bit key, Secure Boot v2 guarantees strong crypto. Only one key signs the signed app at a time, but you can store up to three public key hashes in eFuse for future rotation. Once verified, the second stage bootloader verifies the application-every time. Enable it via CONFIG_SECURE_BOOT_V2_ENABLED=y, but remember: the build signs only if CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES is on. It’s tight, it’s fast, and it’s essential for trustworthy firmware.
Enable Flash Encryption in Development or Release Mode
How do you protect your firmware without slowing down development? Use flash encryption in Development Mode by enabling CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y. This lets you re-flash plaintext firmware, debug in-field, and keep the FLASH_CRYPT_CNT eFuse writable-perfect for testing. You still get basic protection, but UART download mode stays active, so it’s less secure than Release Mode. When you’re ready for production, switch to Release Mode: set SPI_BOOT_CRYPT_CNT to 0b1111111 (ESP32) or 0b0000111 (S2/S3/C-series), permanently enabling encryption. In Release Mode, the eFuse locks down, disabling UART download mode and debug interfaces like JTAG. Pre-encrypting firmware is essential if you know the flash encryption key. For full security with Secure Boot, burn eFuses like DISABLE_DL_ENCRYPT and DISABLE_DL_DECRYPT.
Combine Secure Boot and Flash Encryption: Step-by-Step
You’ll want to enable both Secure Boot v2 and flash encryption together if you’re aiming for robust firmware protection on ESP32 chips starting from revision v3.0, especially when deploying in environments where tampering or cloning is a concern. Start by using menuconfig to enable Secure Boot v2 and flash encryption in your ESP-IDF project. Generate a signing key with `idf.py secure-generate-signing-key`, then sign your bootloader and partition table. On first boot, the flash encryption key generated will encrypt all app partitions in place, locking the bootloader and data. Burn the public key digest into EFUSE BLK2 and set ABS_DONE_1 to activate Secure Boot v2. Use `idf.py encrypted-flash` to pre-encrypt firmware-ideal for secure OTA update workflows. This setup guarantees only signed, encrypted flash images run, blocking unauthorized changes and protecting your system long-term.
Generate and Protect Signing Keys Using OpenSSL or HSM
A 3072-bit RSA signing key forms the foundation of ESP32 Secure Boot v2, and generating it properly is non-negotiable for long-term firmware integrity. You can use OpenSSL with `openssl genrsa -out secure_boot_signing_key.pem 3072` to create the signing key private, ensuring RSA-PSS compatibility. Alternatively, run `idf.py secure-generate-signing-key –version 2` for foolproof, Secure Boot v2-aligned key generation. Never expose the private key-store it in a Hardware Security Module (HSM) so it never leaves during signing. The public key modulus and exponent are embedded in the signature block, and must match the SHA-256 digest flashed into EFUSE BLK2. Using an HSM or secure tooling keeps your signing key private, blocking attackers from signing rogue firmware. This step’s critical-get it right, and your device’s trust chain stays solid from day one.
OTA Updates With Secure Boot: What You Need to Know
While your ESP32’s Secure Boot v2 locks down initial firmware, you’ll still need to securely update it in the field-so OTA updates must be signed with the private key matching the public key digest burned into eFuse BLK2, or one of up to three pre-flashed keys for rotation. The signed bootloader performs signature verification on every OTA app image, rejecting unsigned or tampered firmware. If CONFIG_SECURE_SIGNED_ON_UPDATE is enabled, this check becomes mandatory. Each app image must include a properly formatted signature block with a SHA-256 hash, RSA-PSS signature, and public key modulus, aligned to a 4 KB boundary. You’ll use idf.py secure-sign-data to append the signature before flashing. This guarantees only authenticated code runs, maintaining chain-of-trust from eFuse to runtime. In real tests, devices rejected spoofed updates instantly, proving robust protection. Secure Boot v2 makes OTA updates safe, provided you safeguard your private key and follow the signing workflow meticulously.
Sign Images Using Precomputed Signatures or HSM
Signing firmware with precomputed signatures or a hardware security module (HSM) gives you tighter control over your ESP32’s Secure Boot v2 process, especially if you’re managing updates across hundreds of deployed units. When using precomputed signatures, you must sign the full secure-padded image, including padding bytes, so the RSA-PSS signature matches what Secure Boot v2 expects. Use `esptool.py elf2image` with `–secure-pad-v2` to generate this padded image, then sign it externally using your HSM, which keeps the private key secure. You’ll then append the 1216-byte signature block-containing the RSA-PSS signature, SHA-256 hash, public key modulus, exponent, and Montgomery values-using `idf.py secure-sign-data`. Be sure to disable CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES so the build system doesn’t try to sign automatically. This method guarantees your firmware stays protected and verifiable without risking key exposure.
Avoid Bricking: Critical ESP32 Secure Boot Mistakes
If you’re enabling Secure Boot on your ESP32 without first burning the public key digest to eFuse BLK2 and write-protecting it, you’re risking a hard brick-no fallback, no recovery, just a locked chip that refuses to boot. Skipping proper key generation for flash encryption? That’s just as bad; the device may lock itself with a random key, making updates impossible. Always burn the flash encryption key *before* enabling Release mode. If you use esptool.py write_flash without CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE=y on ESP32 V3, you’ll kill UART ROM download mode too soon. Never overlook the partition table offset-Secure Boot and flash encryption shift bootloader size, risking corruption. And if SPI_BOOT_CRYPT_CNT isn’t set right via eFuse, the chip won’t boot at all. These steps aren’t optional-they’re essential to avoid bricking.
On a final note
You’ve locked down your ESP32 the right way-Secure Boot v2 validates every boot, while flash encryption hides firmware at rest, even on a physical probe, 128-bit AES keeps data scrambled, and tested OTA updates stay signed and safe, just as long as you guard your private keys, avoid development mode in production, and triple-check partition layout size alignment, because one misstep can brick the module fast.





