Can I use esp_flash_read to get a secret, unique identification or encryption key?

jhnlmn
Posts: 15
Joined: Wed Mar 03, 2021 4:22 am

Can I use esp_flash_read to get a secret, unique identification or encryption key?

Postby jhnlmn » Sun Feb 06, 2022 5:09 am

How to get a secret, unique key for ESP32 chip (when flash encryption is enabled)?
A unique, secret AES key is already generated on every chip and saved in BLK1, but we have no access to it.

Can I use esp_flash_read(NULL, CONFIG_BOOTLOADER_OFFSET_IN_FLASH, ...) to get a derived key?


I see this post
https://www.esp32.com/viewtopic.php?t=2671
"
The closest you can get is the approach used in Mongoose, where they derive the encryption key from flash encryption key by reading a block of flash filled with 0xff, and then use that key with the AES hardware
"
This code for esp32_fs_crypt_init is here:
https://github.com/mongoose-os-libs/vfs ... fs_crypt.c
but I do not like it: it performs read of entire flash looking for FFs, also FFs repeated 32 times is a big mistake.

Another similar option is to use nvs_flash_read_security_cfg/nvs_flash_generate_keys, which does this:
fills a buffer with constants, writes this buffer with esp_partition_write_raw and then reads with esp_partition_read.
But I do not want to write anything anywhere.

It appears that if I simply call:
esp_flash_read_encrypted(NULL, CONFIG_BOOTLOADER_OFFSET_IN_FLASH, key_buffer_encr, sizeof(key_buffer_encr));
then I get first raw, unencrypted, bytes of the bootloader (CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000):
e90302306c070840 ee00000000000300 0000000000000001 3000ff3f202c0000

But if I call:
esp_flash_read(NULL, key_buffer_raw, CONFIG_BOOTLOADER_OFFSET_IN_FLASH, sizeof(key_buffer_raw));
Then I get the same thing encrypted:
d6d9a2f8b05352d8 fafcbc3720493445 22a08b76f82f0ead fdfb6e59dbd92a12
which is what I want: a secret, unique key for my chip.

This sounds suspiciously simple - it is much simpler than nvs_flash_generate_keys or esp32_fs_crypt_init,
but does, essentially, the same thing: retrieves an encrypted version of a constant string.

Am I missing something? Is there a flaw with my simple approach?

Thank you

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

Re: Can I use esp_flash_read to get a secret, unique identification or encryption key?

Postby WiFive » Sun Feb 06, 2022 8:00 am

Well is it "secret" if you are just reading the raw flash bytes? Anyone who can dump the flash chip can recover it.

ESP_Sprite
Posts: 9746
Joined: Thu Nov 26, 2015 4:08 am

Re: Can I use esp_flash_read to get a secret, unique identification or encryption key?

Postby ESP_Sprite » Mon Feb 07, 2022 1:00 am

WiFive has a point. You need to read something in flash that is unencrypted, as if it were encrypted flash; the other way around does not make your key secret anymore. If you don't like looking for 0xFFs or writing to flash, how about creating a small partition that never is written to (and as such is always 0xff; you could even make sure of that in your code), marking that as encrypted, and reading that?

Also:
also FFs repeated 32 times is a big mistake.
Note that you're using the FFs as a nonce here. Cryptography-wise, there's nothing wrong with that in particular as far as I can tell (but do note I'm not a cryptographerologist)

jhnlmn
Posts: 15
Joined: Wed Mar 03, 2021 4:22 am

Re: Can I use esp_flash_read to get a secret, unique identification or encryption key?

Postby jhnlmn » Mon Feb 07, 2022 2:59 am

@WiFive and @ESP_Sprite
Yes, thank you, I forgot that bootloader is also encrypted in flash.

> Note that you're using the FFs as a nonce here. Cryptography-wise, there's nothing wrong with that in particular as far as I can tell

No, as "nvs_flash_generate_keys" code says:
https://github.com/espressif/esp-idf/bl ... i.cpp#L590
"Adjacent 16-byte blocks should be different", that's why they are filling the first 16 bytes with 0xff and the second with 0x99.

But the code in mongoose appears to be buggy: they use "32 x 0xff processed with the flash encryption key", which produces only 16 unique bytes repeated twice.

Next question: can I use flash offset 0? I cannot find any explanation of it in the docs.
Is this block mutable by anybody? if not, then can I use it?

It appears to be all filled with FFs, which is perfect ( only "Adjacent 16-byte blocks should be different",
but I can easily read non-adjacent, right?)

Let's read 64 bytes raw first:

esp_flash_read(NULL, key_buffer_raw, 0, sizeof(key_buffer_raw));
this returns:
ffffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffff

and then encrypted:
esp_flash_read_encrypted(NULL, 0, key_buffer_encr, sizeof(key_buffer_encr));
this returns:
5b89a53a84b3c596 b46c296da4aac92b 5b89a53a84b3c596 b46c296da4aac92b bad4a9450f655518 69565603f7ba4bc3 bad4a9450f655518 69565603f7ba4bc3
As expected, adjacent 16-bytes blocks are repeated, but non-adjacent are not, so this looks good for a key (assuming this area is unmutable).

If offset 0 is a bad idea, then what about nvs_key?
I see that only the first 0x50 bytes of it are used, but the rest are FFs

nvs_key, data, nvs_keys, 0x7FC000, 0x1000, encrypted
esptool.py -p /dev/ttyUSB1 -b 460800 read_flash 0x7FC000 0x1000 test.bin
00000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
00000010 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 |................|
00000020 ee ee ee ee ee ee ee ee ee ee ee ee ee ee ee ee |................|
00000030 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 |................|
00000040 e2 90 5f b0 d5 e5 fa f2 3f 56 a2 84 f7 70 02 22 |.._.....?V...p."|
00000050 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00001000
Of course, I do not want to expose NVS key by re-using these 0x50 bytes, but the rest is a fair game, is it?


Any comments?

ESP_Sprite
Posts: 9746
Joined: Thu Nov 26, 2015 4:08 am

Re: Can I use esp_flash_read to get a secret, unique identification or encryption key?

Postby ESP_Sprite » Mon Feb 07, 2022 4:45 am

jhnlmn wrote:
Mon Feb 07, 2022 2:59 am
@WiFive and @ESP_Sprite
Yes, thank you, I forgot that bootloader is also encrypted in flash.

> Note that you're using the FFs as a nonce here. Cryptography-wise, there's nothing wrong with that in particular as far as I can tell

No, as "nvs_flash_generate_keys" code says:
https://github.com/espressif/esp-idf/bl ... i.cpp#L590
"Adjacent 16-byte blocks should be different", that's why they are filling the first 16 bytes with 0xff and the second with 0x99.

But the code in mongoose appears to be buggy: they use "32 x 0xff processed with the flash encryption key", which produces only 16 unique bytes repeated twice.
Ah, you're right; the ESP32 encryption process encrypts every adjacent 16-byte block with the same key, so if you read 32 bytes from an all-FF partition, you'd get the same 16-bit key repeated twice.
Next question: can I use flash offset 0? I cannot find any explanation of it in the docs.
Is this block mutable by anybody? if not, then can I use it?

It appears to be all filled with FFs, which is perfect ( only "Adjacent 16-byte blocks should be different",
but I can easily read non-adjacent, right?)
This is used by SecureBoot v1 at least; I'm decently sure SecureBoot v2 does not need it anymore.
If offset 0 is a bad idea, then what about nvs_key?
I see that only the first 0x50 bytes of it are used, but the rest are FFs

nvs_key, data, nvs_keys, 0x7FC000, 0x1000, encrypted
esptool.py -p /dev/ttyUSB1 -b 460800 read_flash 0x7FC000 0x1000 test.bin
00000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
00000010 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 |................|
00000020 ee ee ee ee ee ee ee ee ee ee ee ee ee ee ee ee |................|
00000030 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 |................|
00000040 e2 90 5f b0 d5 e5 fa f2 3f 56 a2 84 f7 70 02 22 |.._.....?V...p."|
00000050 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00001000
Of course, I do not want to expose NVS key by re-using these 0x50 bytes, but the rest is a fair game, is it?


Any comments?
Possibly, at this point in time it is. However, I doubt we guarantee the format of that partition, so what now is unused may be used in the future.

Again, why not simply add your own partition, something which you have complete control over, and use that?

jhnlmn
Posts: 15
Joined: Wed Mar 03, 2021 4:22 am

Re: Can I use esp_flash_read to get a secret, unique identification or encryption key?

Postby jhnlmn » Mon Feb 07, 2022 6:53 pm

> Again, why not simply add your own partition, something which you have complete control over, and use that?

Yes, this is what I will do.
Still, I have a nagging thought that wasting 4 KB of flash just to get 32 bytes for a key is not a perfect idea.
NVS reserved 4 KB for its keys, I will reserve another 4 KB, mongoose also wants unused flash, soon every library, which needs a key, will reserve its own 4 KB partition and where it will end?

Remyhx
Posts: 23
Joined: Thu Jun 17, 2021 8:22 pm

Re: Can I use esp_flash_read to get a secret, unique identification or encryption key?

Postby Remyhx » Tue Feb 15, 2022 8:41 pm

Interesting topic. Guess thats why secure bootloader v2 was introduced.

https://limitedresults.com/2019/11/pwn- ... xtraction/

Who is online

Users browsing this forum: No registered users and 97 guests