1
$\begingroup$

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:

  1. The computer that is building a new firmware version would generate a random private key (Apvt) and then derive a public key (Apub).
  2. 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).
  3. 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.
  4. The firmware update file would then be assembled, consisting of Apub, followed by the firmware cipher.
  5. 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.

$\endgroup$
9
  • 1
    $\begingroup$ This is just a comment: have you considered whether this approach is really what you need? I mean, is your customer so untrustworthy that if you don't protect this update then it will steal your code? In addition, is your software so "special" that it needs to be protected? I mean, if your core business is selling the device then just having the FW the customer cannot do much. If on the other hand the FW is what makes the device unique then your approach is ok $\endgroup$
    – frarugi87
    Nov 13, 2023 at 17:16
  • 1
    $\begingroup$ I really can't imagine creating and maintaining individual keys for 1000's of products. If someone really wants to dump the flash, they will, and can bypass any scheme. What would seem more important is that the end device can't run any code but yours, which can be accomplished with a public key in flash, which does prevent imposter code from being installed by your bootloader, which is basically what fgrieu recommends. $\endgroup$ Nov 13, 2023 at 17:43
  • 1
    $\begingroup$ The usual encoding of the points is structured and non-uniform since it must satisfy the curve equation. Therefore KDF is always advised after ECDH. $\endgroup$
    – kelalaka
    Nov 14, 2023 at 2:03
  • 1
    $\begingroup$ @frarugi87 I haven't been exact. It's not the direct customer that we're worried about, but the end customer. Our direct customer is the one that requested we incorporate encrypted firmware updates into our products, because someone tampering with software might end up being a liability for them. $\endgroup$
    – MDude
    Nov 14, 2023 at 7:14
  • $\begingroup$ @ErikFriesen The original plan was to have the same Bpvt baked into every device, so we would be building just one single update file that could be used on all our devices. As mentioned in another comment, we will be adding cryptographic signatures for secure booting in the future. The original plan wasn't the best, as I am still a novice in the field of cybersecurity, and the best approaches to tackle certain problems are still unknown to me. I will indeed end up implementing what fgrieu recommended. $\endgroup$
    – MDude
    Nov 14, 2023 at 7:22

1 Answer 1

2
$\begingroup$

The theory is to use a key derivation function after Diffie-Hellman key exchange. A truncated hash would do if a single key is nedded. As DJB puts it (emphasis mine):

Given someone else's Curve25519 public key hispublic[0], hispublic[1], …, hispublic[31], call

curve25519(shared,mysecret,hispublic);

to generate a 32-byte secret shared[0], shared[1], ..., shared[31]. The other user can compute the same secret by applying his secret key to your public key. Both of you can then hash this shared secret and use the result as a key for, e.g., Poly1305-AES.

On the other hand, there is no security issue in directly using the bytes at start of a Curve25519 shared secret as a key for a symmetric algorithm unrelated to Curve25519, especially if the rest is thrown away: they are computationally indistinguishable from uniformly random.


The overall strategy in the question:

  1. Does not insure integrity of the firmware; this is a most serious issue.
  2. Does not insure confidentiality of the firmware w.r.t. a party that extracted Bpvt.
  3. Requires the firmware update to be tailored to the device(s) that hold Bpvt. That's a feature or a drawback.

I recommend fixing 1 by signing the firmware, with the check and public key in ROM or other assumed unalterable part of the device's firmware. Authenticated encryption is not as good (as it's broken by key extraction, when signature is not since the verification key is public).

Cryptography can't fix 2. The best that's achievable is that a confidentiality breach requires key extraction before the upgrade, or firmware extraction afterwards.

If we want the firmware update to be a static file, I stand unconvinced that DH key exchange is useful for confidentiality in firmware upgrade. Plain symmetric key derivation seems to give the same security service, with less complexity.

$\endgroup$
2
  • $\begingroup$ Thank you very much for your response! Secure boot with signed firmware is indeed something we plan on implementing in the future. To address the last paragraph, yes, the firmware update file will be static. Suppose we throw out DH key exchange, would you recommend using HMAC based on SHA-1 as the key derivation function? I was thinking of sending a random string (along with the firmware cipher), which is then concatenated with a static key inside the bootloader and running that through HMAC, with the result then used as the AES decryption key. Would this be a good approach? $\endgroup$
    – MDude
    Nov 13, 2023 at 11:46
  • 2
    $\begingroup$ @MDude: Using HMAC to derive per-firmware encryption keys or/and authenticators is fine. While HMAC-SHA-1 is unbroken and will likely remain so, there's the issue that SHA-1 is deprecated, so I'd recommend HMAC-SHA-256 for a new design (or HMAC-SHA-512 if it's faster on the platform). $\endgroup$
    – fgrieu
    Nov 13, 2023 at 11:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.