Encryption via espsecure.py

ESPecially_Embedded
Posts: 6
Joined: Wed Mar 06, 2024 1:04 pm

Encryption via espsecure.py

Postby ESPecially_Embedded » Fri Mar 08, 2024 10:07 am

Hello fellow ESP enthusiasts. I'm fairly new to this game and I'm struggling to attain some detail around encryption from the datasheets, as thorough as they are! I'm using a ESP32-WROOM-32, chip revision 1, my company is intending to start production in a few weeks, I need to use the following process (or similar) to protect our firmware.

What I'm trying to do
1. BURN a known encryption key to BLOCK1 from file via espefuse.py burn_key so that it is not auto-generated on boot
2. Enable encryption in development mode via menuconfig, then build and upload as normal (via PIO)
3. Use espsecure.py to encrypt binaries via encrypt_flash_data
4. Flash encrypted data via esptool.py write_flash
5. BURN write protection on FLASH_CRYPT_CNT via CONFIG_FLASH_ENCRYPTION_DISABLE_PLAINTEXT so encryption can't be disabled.

The reason for this workaround is I want to protect my firmware from being read or modified, wireless comms are disabled so no OTA, but I also need to update it if necessary (3 plain text flashes aren't sufficient as in release mode). My preference would have been a straightforward read/write protect system but it doesn't seem like that's an option.

Issues / Misunderstandings
1. Do I need to first combine the (firmware?)bootloader and firmware binaries and then encrypt them as one? The link below doesn't make this clear.
https://docs.espressif.com/projects/esp ... erated-key

2. When in production, it is not professional or convenient to use VS Code and PIO for uploading. Can I replace step 2 by combining the bootloader.bin and firmware.bin files and flashing them using write_flash to initialise the encryption?

Thanks in advance, appreciate your support team :mrgreen:
:geek:

ESPecially_Embedded
Posts: 6
Joined: Wed Mar 06, 2024 1:04 pm

Re: Encryption via espsecure.py

Postby ESPecially_Embedded » Mon Mar 18, 2024 10:32 am

I've resolved this after much reading of documentation and forums, so I thought I'd post my findings for anyone else in the same situation. To clarify, I'm using PlatformIO VS code extension and the esp-idf platform with Arduino as a component, so I'm unable to encrypt firmware on my HOST machine and flash without first compiling the unencrypted binaries.

Step one is to build the project and any file images (in my case, bootloader, firmware, partitions, spiffs). Originally I was trying to merge my .bin files and then encrypt them. This doesn't work, each one must be encrypted individually using espesecure and then flashed using esptool. In my case I have a SPIFFS partition for fonts, SPIFFS does not support encryption so was flashed unencrypted.

For production flashing, I have created a script which:
- Exports the appropriate files from our repository (SVN)
- Burns the encryption key and other associated efuses to reduce attack possibilities(e.g. DISABLE_DL_DECRYPT 1, FLASH_CRYPT_CNT 0x7F)
- Flashes the encrypted bins and unencrypted spiffs
- Read/Write protects some efuses
- Checks for efuse errors

I think for cases where each product is identical and contains no personal data, this is more than sufficient. I do think that the ESP32 would benefit from a more straightforward read/write protect option similar to a PIC though.
:geek:

Nespressif
Posts: 76
Joined: Tue Sep 12, 2017 11:25 am

Re: Encryption via espsecure.py

Postby Nespressif » Tue Mar 19, 2024 1:19 pm

Hi ESPecially_Embedded, thanks for sharing the process with us. I also have some project that does not have any active communication system, neither wifi nor BT, therefore it also does not have OTA scheme implemented.

I think that for this kind of projects where you can only access via UART, it is not necessary to implement Secure Boot. To protect them it would be enough to encrypt the flash and disable UART ROM download mode.

Although it would be nice to implement a simpler method to protect our code, as you say. I think the same as you.

If you could share with us the espsecure and esptool commands you use in your script, I would appreciate it very much.

Best regards and thank you very much.

ESP_flying_raijin
Posts: 25
Joined: Tue Aug 13, 2019 2:03 pm

Re: Encryption via espsecure.py

Postby ESP_flying_raijin » Wed Mar 20, 2024 3:44 am

Hi Especially_Embedded,
Thanks for the issue, sorry for the delayed reply.

In the steps that you have mentioned below
. BURN a known encryption key to BLOCK1 from file via espefuse.py burn_key so that it is not auto-generated on boot
2. Enable encryption in development mode via menuconfig, then build and upload as normal (via PIO)
3. Use espsecure.py to encrypt binaries via encrypt_flash_data
4. Flash encrypted data via esptool.py write_flash
5. BURN write protection on FLASH_CRYPT_CNT via CONFIG_FLASH_ENCRYPTION_DISABLE_PLAINTEXT so encryption can't be disabled.
What is the main reason for enable Flash Encryption in development mode?
Is the ability to flash new binaries afterwards the only reason?
I think that should be already solved for you since you generate the key outside so you have access to the keys outside and can encrypt a plaintext binaries.
Due to this in your Step2. I think you can simply select the Release mode of Flash encryption. Development mode does not burn all the security related eFuses so the configuration is not best suitable for production scenario.
If you are using development mode because you dont want the bootloader to burn some specific eFuse then let me know.

Have you tried the guide to enable flash encryption externally ? https://docs.espressif.com/projects/esp ... externally
This gives detailed instructions about all relevant eFuses to be burned for production scenario.
Do I need to first combine the (firmware?)bootloader and firmware binaries and then encrypt them as one?
Both options are possible.
You can either encrypt them before merging or you can merge them and then encrypt.
The only thing to take care of merging is that the offset of the data does not change. So for e.g. you merge to binaries into one but the physical offset of the binaries in the partition table has an empty gap in between, then you need to also consider that gap while merging the binaries.

Can you explain more about READ/Write protection option and your requirements?
We have one option Disable ROM DL mode which disables the download mode for the chip and then nothing can be flashed. This has a limitation that nothing can be flashed afterwards and the only option is to OTA the firmware.
This has been resolved in chips later than esp32 by introducing Secure ROM DL mode which only allows very limited commands when enabled.

Thanks,
Aditya

ESPecially_Embedded
Posts: 6
Joined: Wed Mar 06, 2024 1:04 pm

Re: Encryption via espsecure.py

Postby ESPecially_Embedded » Wed Mar 20, 2024 3:09 pm

Thanks for your reply Aditya. I've learned some more since this post, see answers below.
What is the main reason for enable Flash Encryption in development mode?
My understanding was that this is the only way to allow flashing of unlimited encrypted binaries via a known key, but maybe I misunderstood.

Is the ability to flash new binaries afterwards the only reason?
I think that should be already solved for you since you generate the key outside so you have access to the keys outside and can encrypt a plaintext binaries.
Due to this in your Step2. I think you can simply select the Release mode of Flash encryption. Development mode does not burn all the security related eFuses so the configuration is not best suitable for production scenario.
If you are using development mode because you dont want the bootloader to burn some specific eFuse then let me know.
You're exactly right that my requirement is to allow flashing of encrypted bins while not limiting use of the bootloader functionality if required. I did use the enable-flash-encryption-externally instruction, does this essentially set all bits required for "release" mode?

The only thing to take care of merging is that the offset of the data does not change.
Interesting, I imagine I wasn't taking account of the blank partition buffers hence why it wasn't working.

Can you explain more about READ/Write protection option and your requirements?
We have one option Disable ROM DL mode which disables the download mode for the chip and then nothing can be flashed. This has a limitation that nothing can be flashed afterwards and the only option is to OTA the firmware.
This has been resolved in chips later than esp32 by introducing Secure ROM DL mode which only allows very limited commands when enabled.
The read/write option I would like is where the whole firmware cannot be read or modified unless the whole thing is erased first. I can see that this would be more complicated for the ESP32 as it's commonplace to flash individual partitions at custom location as opposed to a PIC where you usually flash everything at once. I guess this could only be achieved if everything was flashed as a merged bin, otherwise an attacker could flash a modified bootloader and then pull the firmware.

The Disable ROM DL option is no good as I'm not using OTA. The Secure ROM DL sounds interesting though, I'll look into that when we move to ESP32-S2 or S3.


Here's a portion of my script:

Code: Select all


:enter_com

REM Prompt the user for the COM port
set /p COM_PORT=Enter the COM port for the "USB to UART" device (e.g. COM4):


:flash_device

REM Encryption key XOR manipulation is not required (XOR all)
espefuse -p %COM_PORT% --chip esp32 --do-not-confirm burn_efuse FLASH_CRYPT_CONFIG 0xF FLASH_CRYPT_CNT 0x7F

REM Burn the encryption key
espefuse -p %COM_PORT% --chip esp32 burn_key flash_encryption nothing_in_here.bin

REM Write encrypted binaries
esptool -p %COM_PORT% -b 921600 --chip esp32 --after no_reset write_flash ^
0x1234 %PRODUCT%\encrypted-bootloader.bin ^
0x12345 %PRODUCT%\encrypted-partitions.bin ^
0x23456 %PRODUCT%\encrypted-firmware.bin ^
0x123456 %PRODUCT%\spiffs.bin

REM Disable decryption (encryption could otherwise be reversed via bootloader)
REM and write protect efuses to reduce risk of compromise
espefuse -p %COM_PORT% --chip esp32 --do-not-confirm burn_efuse DISABLE_DL_DECRYPT 1 write_protect_efuse FLASH_CRYPT_CNT DISABLE_DL_ENCRYPT DISABLE_DL_DECRYPT

espefuse -p %COM_PORT% --chip esp32 check_error

REM Ask the user if they want to flash another device
set /p CONTINUE=Do you want to flash and secure another device? (y/n):
if /i "%CONTINUE%"=="y" goto flash_device
if /i "%CONTINUE%"=="n" goto clean_up

:clean_up
:geek:

ESP_flying_raijin
Posts: 25
Joined: Tue Aug 13, 2019 2:03 pm

Re: Encryption via espsecure.py

Postby ESP_flying_raijin » Mon Mar 25, 2024 1:42 am

Hi Especially_Embedded,
I did use the enable-flash-encryption-externally instruction, does this essentially set all bits required for "release" mode?
Yes, the instructions are provided for the release mode. The step related to burning security related eFuses in https://docs.espressif.com/projects/esp ... externally lists all the necessary eFuses for enabling Flash Encryption release mode.
You can verify this by calling the esp_flash_encryption_verify_release_mode() API in your firmware (ref - https://github.com/espressif/esp-idf/bl ... ypt.h#L199)
The read/write option I would like is where the whole firmware cannot be read or modified unless the whole thing is erased first.
I see. From the accessibility perspective this is made possible with help of the Secure ROM DL mode where the flash read operation is disabled. Only flash_write operation is supported but if Secure boot and Flash encryption are enabled then you need to process the firmware correctly before flashing so only the authenticated user shall be able to do that.

For the esp32, I think enable Flash Encryption feature in release mode should be enough for this purpose. as any unauthenticated user would need to know the flash encryption key to actually write or read the plaintext firmware. It is recommended to encrypt all the files which have some sensitive data.

Thanks,
Aditya

Who is online

Users browsing this forum: Bing [Bot], tomy983 and 123 guests