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
Can I use esp_flash_read to get a secret, unique identification or encryption key?
Re: Can I use esp_flash_read to get a secret, unique identification or encryption key?
Well is it "secret" if you are just reading the raw flash bytes? Anyone who can dump the flash chip can recover it.
-
- Posts: 9757
- Joined: Thu Nov 26, 2015 4:08 am
Re: Can I use esp_flash_read to get a secret, unique identification or encryption key?
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:
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)also FFs repeated 32 times is a big mistake.
Re: Can I use esp_flash_read to get a secret, unique identification or encryption key?
@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?
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?
-
- Posts: 9757
- Joined: Thu Nov 26, 2015 4:08 am
Re: Can I use esp_flash_read to get a secret, unique identification or encryption key?
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.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.
This is used by SecureBoot v1 at least; I'm decently sure SecureBoot v2 does not need it anymore.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?)
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.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?
Again, why not simply add your own partition, something which you have complete control over, and use that?
Re: Can I use esp_flash_read to get a secret, unique identification or encryption key?
> 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?
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?
Re: Can I use esp_flash_read to get a secret, unique identification or encryption key?
Interesting topic. Guess thats why secure bootloader v2 was introduced.
https://limitedresults.com/2019/11/pwn- ... xtraction/
https://limitedresults.com/2019/11/pwn- ... xtraction/
Who is online
Users browsing this forum: No registered users and 353 guests