flash encryption (pre-generated key) procedure flow

davdav
Posts: 208
Joined: Thu Nov 17, 2016 2:33 pm

flash encryption (pre-generated key) procedure flow

Postby davdav » Thu Sep 20, 2018 12:42 pm

Hi, I'm trying to develop our internal production process to flash device with a pre-generated key and pre-encrypted files (not plaintext) without waiting for first boot and esp32 encryption.

This is my process:

Erase all content flash of module

Code: Select all

make -j8 erase_flash

Code: Select all

make menuconfig
enabled Flash encryption(no secure boot)

-Then I compile (please note I have a factory APP and 1 OTA partition so this step is done for two project folders)

Code: Select all

make -j8 clean

Code: Select all

make -j8 all

-Pre-generate encryption KEY

Code: Select all

espsecure.py generate_flash_encryption_key My_encryption_key.bin

-Encrpyt all file to flash (bootloader, partition table, firmware, firmware_factory) using pre-generated KEY

Code: Select all

espsecure.py encrypt_flash_data --keyfile My_encryption_key.bin --address 0x1000 -o bootloader-encrypted.bin C:/msys32/home/Davide/esp/Avior_ESP32_WiFi/build/bootloader/bootloader.bin

espsecure.py encrypt_flash_data --keyfile My_encryption_key.bin --address 0x8000 -o my_partition_table-encrypted.bin C:/msys32/home/Davide/esp/Avior_ESP32_WiFi/build/my_partition_table.bin

espsecure.py encrypt_flash_data --keyfile My_encryption_key.bin --address 0x60000 -o Avior_ESP32_WiFi_v2-encrypted.bin C:/msys32/home/Davide/esp/Avior_ESP32_WiFi/build/Avior_ESP32_WiFi_v2.bin

espsecure.py encrypt_flash_data --keyfile My_encryption_key.bin --address 0x10000 -o Avior_ESP32_WiFi_OTAfactory-encrypted.bin C:/msys32/home/Davide/esp/Avior_ESP32_WiFi_OTAfactory/build/Avior_ESP32_WiFi_OTAfactory.bin

- Fuse the pre-generated KEY to device

Code: Select all

espefuse.py --port COM17 burn_key flash_encryption AVIOR_encryption_key.bin

- program flash with pre-encrypted files (please note bootloader-encpyted file is 27.856 bytes so it is below the limit of 0x7000 bytes).

Code: Select all

esptool.py --chip esp32 --port COM17 --baud 460800 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader-encrypted.bin 0x8000 my_partition_table-encrypted.bin 0x10000 Avior_ESP32_WiFi_OTAfactory-encrypted.bin  0x60000 Avior_ESP32_WiFi_v2-encrypted.bin

- program fuse FLASH_CRYPT_CNT

Code: Select all

espefuse.py --port COM17 burn_efuse FLASH_CRYPT_CNT



After reset I get 4 times the below debug, but PRO_CPU and APP_CPU are not started and my program is not executed

Code: Select all

I (14) boot: ESP-IDF v3.1 2nd stage bootloader
I (14) boot: compile time 11:46:04
I (14) boot: Enabling RNG early entropy source...
D (15) boot: magic e9
D (17) boot: segments 04
D (19) boot: spi_mode 02
D (21) boot: spi_speed 00
D (23) boot: spi_size 02
I (26) boot: SPI Speed      : 40MHz
I (29) boot: SPI Mode       : DIO
I (32) boot: SPI Flash Size : 4MB
D (35) bootloader_flash: mmu set paddr=00000000 count=1
D (40) boot: mapped partition table 0x8000 at 0x3f408000
D (45) flash_parts: partition table verified, 8 entries
I (50) boot: Partition Table:
I (53) boot: ## Label            Usage          Type ST Offset   Length
D (59) boot: load partition table entry 0x3f408000
D (63) boot: type=1 subtype=2
I (66) boot:  0 nvs              WiFi data        01 02 00009000 00004000
D (73) boot: load partition table entry 0x3f408020
D (77) boot: type=1 subtype=0
I (80) boot:  1 otadata          OTA data         01 00 0000d000 00002000
D (86) boot: load partition table entry 0x3f408040
D (91) boot: type=0 subtype=0
I (94) boot:  2 factory          factory app      00 00 00010000 00050000
D (100) boot: load partition table entry 0x3f408060
D (105) boot: type=0 subtype=10
I (108) boot:  3 ota_0            OTA app          00 10 00060000 001f0000
D (114) boot: load partition table entry 0x3f408080
D (119) boot: type=1 subtype=82
I (122) boot:  4 sys              Unknown data     01 82 00250000 00050000
D (128) boot: load partition table entry 0x3f4080a0
D (133) boot: type=1 subtype=82
I (136) boot:  5 users            Unknown data     01 82 002a0000 000b0000
D (142) boot: load partition table entry 0x3f4080c0
D (147) boot: type=1 subtype=82
I (150) boot:  6 rules            Unknown data     01 82 00350000 000b0000
I (156) boot: End of partition table
D (160) boot: OTA data offset 0xd000
D (163) bootloader_flash: mmu set paddr=00000000 count=1
D (168) boot: OTA sequence values A 0xbcca56f6 B 0xaaf631d5
E (173) boot: ota data partition invalid, falling back to factory
D (179) boot: Trying partition index -1 offs 0x10000 size 0x50000
D (185) esp_image: reading image header @ 0x10000
D (189) bootloader_flash: mmu set block paddr=0x00010000 (was 0xffffffff)
D (196) esp_image: image header: 0xe9 0x09 0x02 0x02 40080fc4
I (201) esp_image: segment 0: paddr=0x00010020 vaddr=0x3f400020 size=0x0b180 ( 45440) map
D (209) bootloader_flash: mmu set paddr=00010000 count=1
D (224) bootloader_flash: mmu set block paddr=0x00010000 (was 0xffffffff)
I (224) esp_image: segment 1: paddr=0x0001b1a8 vaddr=0x3ffb0000 size=0x02134 (  8500) load
D (229) bootloader_flash: mmu set paddr=00010000 count=1
D (236) bootloader_flash: mmu set block paddr=0x00010000 (was 0xffffffff)
I (240) esp_image: segment 2: paddr=0x0001d2e4 vaddr=0x3ffb2134 size=0x00000 (     0) load
D (248) bootloader_flash: mmu set paddr=00010000 count=1
D (253) bootloader_flash: mmu set block paddr=0x00010000 (was 0xffffffff)
I (260) esp_image: segment 3: paddr=0x0001d2ec vaddr=0x40080000 size=0x00400 (  1024) load
D (268) bootloader_flash: mmu set paddr=00010000 count=1
D (273) bootloader_flash: mmu set block paddr=0x00010000 (was 0xffffffff)
I (279) esp_image: segment 4: paddr=0x0001d6f4 vaddr=0x40080400 size=0x0291c ( 10524) load
D (287) bootloader_flash: mmu set paddr=00010000 count=2
D (295) bootloader_flash: mmu set block paddr=0x00020000 (was 0xffffffff)
I (299) esp_image: segment 5: paddr=0x00020018 vaddr=0x400d0018 size=0x21da4 (138660) map
D (307) bootloader_flash: mmu set paddr=00020000 count=3
D (341) bootloader_flash: mmu set block paddr=0x00040000 (was 0xffffffff)
I (341) esp_image: segment 6: paddr=0x00041dc4 vaddr=0x40082d1c size=0x06890 ( 26768) load
D (344) bootloader_flash: mmu set paddr=00040000 count=1
D (355) bootloader_flash: mmu set block paddr=0x00040000 (was 0xffffffff)
I (356) esp_image: segment 7: paddr=0x0004865c vaddr=0x400c0000 size=0x00000 (     0) load
D (364) bootloader_flash: mmu set paddr=00040000 count=1
D (369) bootloader_flash: mmu set block paddr=0x00040000 (was 0xffffffff)
I (375) esp_image: segment 8: paddr=0x00048664 vaddr=0x50000000 size=0x00000 (     0) load
D (383) bootloader_flash: mmu set paddr=00040000 count=1
D (388) bootloader_flash: mmu set block paddr=0x00040000 (was 0xffffffff)
D (395) esp_image: Calculated hash: 9d0aa322
D (399) bootloader_flash: mmu set paddr=00040000 count=1
I (406) boot: Loaded app from partition at offset 0x10000
I (409) boot: Checking flash encryption...
I (413) flash_encrypt: flash encryption is enabled (3 plaintext flashes left)
I (420) boot: Disabling RNG early entropy source...
D (424) boot: Mapping segment 0 as IROM
D (428) boot: Mapping segment 5 as DROM
D (431) boot: calling set_cache_and_start_app
D (435) boot: configure drom and irom and start
D (440) boot: start: 0x40080fc4

If I disable flash-encryption everything works.

I'm using v3.1

Code: Select all

git rev-parse HEAD
22da5f6de9ff3657fa7613fc06ad2eca1d1fe14a

Where am I wrong?

Thanks

davdav
Posts: 208
Joined: Thu Nov 17, 2016 2:33 pm

Re: flash encryption (pre-generated key) procedure flow

Postby davdav » Sun Sep 23, 2018 8:08 pm

Sorry guys to bother but I'm stuck on this..

Checking the bootloader log, this error comes out

Code: Select all

E (173) boot: ota data partition invalid, falling back to factory
Is necessary to encrypt also the otadata partition? How to do that?

My partition table is as follow (spiffs partition not needed to be encrypted):

Code: Select all

# Espressif ESP32 Partition Table
# Name,		Type,	SubType,	Offset,		Size,	Flags
nvs,data,nvs,0x9000,16K,
otadata,data,ota,0xd000,8K,
factory,app,factory,0x10000,320K,
ota_0,app,ota_0,,1984K,
sys,data,spiffs,,320K,
users,data,spiffs,,704K,
rules,data,spiffs,,704K,

@ESP_Angus, do you have any hint on this?

Thanks

ESP_Angus
Posts: 2344
Joined: Sun May 08, 2016 4:11 am

Re: flash encryption (pre-generated key) procedure flow

Postby ESP_Angus » Mon Sep 24, 2018 2:16 am

Hi davdav,

Please also see this reply to you in this other thread about a couple of other required details for pre-generated keys and flash encryption:
https://esp32.com/viewtopic.php?f=2&t=7 ... 207#p31207
davdav wrote: Checking the bootloader log, this error comes out

Code: Select all
E (173) boot: ota data partition invalid, falling back to factory

Is necessary to encrypt also the otadata partition? How to do that?
Yes, ota_data partition is encrypted if flash encryption is enabled. So after flash is erased, ota data partition is all 0xFFs in the physical flash. This will decrypt to essentially random values, hence the "invalid" error.

This error shouldn't matter, if the "factory" app updates ota_data then the update will write the data encrypted and everything will be valid after this. The error message could be avoided by pre-encrypting an empty ota_data partition as well, but it's not really necessary.

Code: Select all

...
D (435) boot: configure drom and irom and start
D (440) boot: start: 0x40080fc4
The log output suggests that the encrypted factory app (at offset 0x10000) is successfully parsed and loaded, and then the bootloader goes to load it from the start address. But then nothing else happens for some reason.

Does the ESP32 reset after this? Does the ROM log a reset reason?

FWIW, I was able to use the posted workflow (plus FLASH_CRYPT_CNT as mentioned in linked post above) on ESP-IDF V3.1 to build the ESP-IDF hello world example as factory app using your attached partition table, and also able to build the https_request example with the default "OTA" partition table layout.

Both worked as expected, so it may be something with your sdkconfig or some other app-specific factor which is causing the weird behaviour.

Can you increase the default log level of the factory app, and see if you get any additional output?

Can you post the output of "espefuse.py summary" as well, please?

davdav
Posts: 208
Joined: Thu Nov 17, 2016 2:33 pm

Re: flash encryption (pre-generated key) procedure flow

Postby davdav » Mon Sep 24, 2018 8:06 am

Thank you @ESP_Angus,

I will review your suggestion and efuse burn reported in thread link. And I will let you know my results and logs.

Regards

davdav
Posts: 208
Joined: Thu Nov 17, 2016 2:33 pm

Re: flash encryption (pre-generated key) procedure flow

Postby davdav » Mon Sep 24, 2018 1:06 pm

Hi @ESP_Angus,

Problem seems to be solved. If you remember in another thread

https://esp32.com/viewtopic.php?f=2&t=7 ... YPT#p31033

I have copied the "app_update" component in my application changing the "esp_write_partition" API in esp_ota_ops.c file: the intent was to write encrypted bin file directly to flash in case of OTA from an SD card.

I realized that in "rewrite_ota_esp" function I have to call the original "esp_partition_write" and not my modified version.

Now I'm able to boot factory and ota0 application successfully. I will do more test but I think to have figured out most of the process.

Thank you for help!

ESP_Angus
Posts: 2344
Joined: Sun May 08, 2016 4:11 am

Re: flash encryption (pre-generated key) procedure flow

Postby ESP_Angus » Mon Sep 24, 2018 11:38 pm

Fantastic, glad you were able to figure out the problem.

davdav
Posts: 208
Joined: Thu Nov 17, 2016 2:33 pm

Re: flash encryption (pre-generated key) procedure flow

Postby davdav » Wed Apr 24, 2019 9:48 pm

ESP_Angus wrote:
Mon Sep 24, 2018 11:38 pm
Fantastic, glad you were able to figure out the problem.
Hello Angus,

I have to retrieve this post to understand if I can apply a fw upgrade between two OTA partitions using pre-generated key
encrypted firmware.


I resume our current state:
-we have ESP_wroom_32 module with 4MB flash. Because we need space for some spiffs partitions we don't have 2 ota partitions, BUT
-we have a factory partition which only read from SD card a pre-encrypted fw bin file and write to the same ota_0 partition
-everytime I release an upgrade of our firmware I lauch command

Code: Select all

espsecure.py encrypt_flash_data --keyfile My_encryption_key.bin --address 0x60000 -o Avior_ESP32_WiFi_v2-encrypted.bin C:/msys32/home/Davide/esp/Avior_ESP32_WiFi/build/Avior_ESP32_WiFi_v2.bin
(please note address 0x60000 which is address of ota_0 partition). Then .bin file is put in SD card and upgrade is performed (by the factory app).
-Please note that I have modified "app_update" components to write the .bin file as "plaintext" in flash because it
is already encrypted.
-so far so good and it is currently working perfectly.

NOW: we have moved to ESP32_WROOM_32D module with 8MB flash and in our plan we would like to remove factory partition and having two ota partition to allow upgrade from internet as well (maybe using esp_https_ota component).

Before I start moving I have a doubt: the "address" parameter of "espsecure.py" command.
Since we need to encrypt the firmware with our "pre-generated" encryption key (My_encryption_key.bin) AND the two ota partitions will have two different
start address in partition_table (in our case they will 0x10000 for ota_0 and 0x1d0000 for ota_1) I would like to understand if I
need to encrypt the bin file for both addresses (and therefore release two .bin file depending if my application is running in ota_0 or ota_1 partition).

What is the purpose of the "address" parameter in "espsecure.py" command? I have looked the python code and it seems that the address is needed for some tweaking...
Do you have any idea if I can avoid to release the two encrypted file (maybe with another modify on "app_update" components OR choosing a particular start address for the ota_0 and ota_1)?

Thanks

WiFive
Posts: 3529
Joined: Tue Dec 01, 2015 7:35 am

Re: flash encryption (pre-generated key) procedure flow

Postby WiFive » Thu Apr 25, 2019 12:10 am

The flash encryption algorithm is AES-256, where the key is “tweaked” with the offset address of each 32 byte block of flash. This means every 32 byte block (two consecutive 16 byte AES blocks) is encrypted with a unique key derived from the flash encryption key.
So yes the encrypted binary content will be different based on flash address.

boarchuz
Posts: 566
Joined: Tue Aug 21, 2018 5:28 am

Re: flash encryption (pre-generated key) procedure flow

Postby boarchuz » Thu Apr 25, 2019 8:01 am

davdav wrote:
Wed Apr 24, 2019 9:48 pm
Do you have any idea if I can avoid to release the two encrypted file (maybe with another modify on "app_update" components OR choosing a particular start address for the ota_0 and ota_1)?
I'm at this point myself and obviously want to avoid having multiple firmware files depending on the flash address. Here are my ideas but I would like to hear if there are better:
  • Include metadata in the firmware download request so that the server can determine which firmware file to deliver. Eg. a header or json object containing something like esp_ota_get_running_partition()->address and/or esp_ota_get_next_update_partition(NULL)->address. This is easy on the ESP-side but still requires maintaining multiple separate files (far from ideal if users are expected to install firmware, such as by uploading via a html page).
  • Combine the encrypted firmwares into one file, and allow the ESP32 to iterate through them based on the address it needs (either 'dumb', based simply on skipping x bytes where x = (desired_ota_partition_index * single_firmware_size) / total_file_size, then writing single_firmware_size bytes; or by using some kind of metadata either provided by the server (via headers) or in the file itself in some standardised way. I think this is much better but multiplies the download size by the number of ota partitions you have.
  • Here's a silly one that I don't like but here it is anyway (also it briefly exposes sectors of the firmware in plaintext so not entirely secure)... Treat one of the ota partitions as a kind of temporary buffer where downloaded firmware is flashed then booted from. On boot, if this partition is the running one, copy its contents to the main ota partition (doing frequent esp_flash_encrypt_region() as you go), effectively doing an ota update from one partition to another, then restart to boot from the main one as normal. In terms of firmware management, you could basically treat it as if there is only that one partition, never needing to worry about encrypting for multiple addresses.

davdav
Posts: 208
Joined: Thu Nov 17, 2016 2:33 pm

Re: flash encryption (pre-generated key) procedure flow

Postby davdav » Thu Apr 25, 2019 1:30 pm

boarchuz wrote:
Thu Apr 25, 2019 8:01 am
I'm at this point myself and obviously want to avoid having multiple firmware files depending on the flash address.
Hello @boarchuz,

I was thinking the same workaround (expect the last one) you wrote down.
I think that first option is probably the most straightforward: when the device contact the server it will pass its current running partition number and server will provide the corresponding bin file.

I have to figure out how to allow compatibility between our first production lot (which has only 1 ota_0 address at 0x60000) and new production lot (which in the plan will have 2 ota partitions, which it is not mandatory but it is cool). Meanwhile if we want to leave the opportunity to upgrade also via SD card (as in first production lot), the correct bin file should be provided.
The matter seems to be become a little complex: we will see internally how and if going forward with this, unless there is a another solution at "esp-idf" level...

Thanks

Who is online

Users browsing this forum: Google [Bot] and 96 guests