I'm trying to implement encrypted firmware update functionality for an embedded device. The goal is to prevent reverse engineering of our firmware when the update files are shared with our customers.
The approach that I've chosen is to encrypt the firmware using AES-128 with CTR block mode. What I'm pondering right now is how to store the symmetric decryption key that will be used to decrypt the firmware.
Based on what I've read on the internet, it wouldn't be the best idea to store a static key in the bootloader's flash. As this post (One key per bootloader, one key per release) suggests, I was thinking of using a unique AES-128 key for each software release, with the key being encrypted asymmetrically and prepended to the firmware payload. So the key would first be decrypted using a private key stored inside the microcontroller and then used for symmetric decryption. Does this approach make sense?
I was thinking of using Curve25519 and Diffie-Hellman key exchange algorithm to achieve this. My current plan is as follows:
- The computer that is building a new firmware version would generate a random private key (Apvt) and then derive a public key (Apub).
- The bootloader on the microcontroller would have a static private key (Bpvt) and its respective public key would be stored on the computer that's building the new firmware (Bpub).
- During building, Curve25519(Apvt,Bpub) would be used to generate a shared secret, which would be used as the 128-bit encryption key used for AES-128.
- The firmware update file would then be assembled, consisting of Apub, followed by the firmware cipher.
- On the microcontroller, during a firmware update, first Curve25519(Bpvt,Apub) would be calculated to get the symmetric key, then AES-128 would be used to decrypt the firmware.
One thing that I still haven't figured out: The shared secret would be a 256-bit key, whereas AES-128 key would be just half that. Would simply using 128 most significant bits of the shared secret be sufficient, or do I need some sort of key derivation function to do that? If so, which would you recommend?
Are there any glaring holes in my plan? Can you recommend any improvements? Please keep in mind that the processing power on the microcontroller side is limited.
Update:
As fgrieu recommends below, I have decided to drop ECDH and instead opt to use HMAC-SHA-256 as the key derivation function, to generate the key for the AES decryption algorithm.
A random string of bytes will be prepended to the firmware, which will then be used as the message to calculate the HMAC, in combination with a dedicated static key, stored inside the bootloader. The resulting HMAC will be used as the key for the symmetric decryption.