To provide confidentiality of image data while in transport to the device or while residing on an external flash, MCUBoot has support for encrypting/decrypting images on-the-fly while upgrading.

The image header needs to flag this image as ENCRYPTED (0x04) and a TLV with the key must be present in the image. When upgrading the image from slot1 to slot0 it is automatically decrypted (after validation). If swap upgrades are enabled, the image located in slot0, also having the ENCRYPTED flag set and the TLV present, is re-encrypted while swapping to slot1.

Threat model

The encrypted image support is supposed to allow for confidentiality if the image is not residing on the device or is written to external storage, eg a SPI flash being used for slot1.

It does not protect against the possibility of attaching a JTAG and reading the internal flash memory, or using some attack vector that enables dumping the internal flash in any way.

Since decrypting requires a private key (or secret if using symetric crypto) to reside inside the device, it is the responsibility of the device manufacturer to guarantee that this key is already in the device and not possible to extract.


When encrypting an image, only the payload (FW) is encrypted. The header, TLVs are still sent as plain data.

Hashing and signing also remain functionally the same way as before, applied over the un-encrypted data. Validation on encrypted images, checks that the encrypted flag is set and TLV data is OK, then it decrypts each image block before sending the data to the hash routines.

The image is encrypted using AES-CTR-128, with a counter that starts from zero (over the payload blocks) and increments by 1 for each 16-byte block. AES-CTR-128 was chosen for speed/simplicity and allowing for any block to be encrypted/decrypted without requiring knowledge of any other block (allowing for simple resume operations on swap interruptions).

The key used is a randomized when creating a new image, by imgtool or newt. This key should never be reused and no checks are done for this, but randomizing a 16-byte block with a TRNG should make it highly improbable that duplicates ever happen.

To distribute this AES-CTR-128 key, new TLVs were defined. The key can be encrypted using either RSA-OAEP or AES-KW-128. Also in the future support for EICES (using EC) can be added.

For RSA-OAEP a new TLV with value 0x30 is added to the image, for AES-KW-128 a new TLV with value 0x31 is added to the image. The contents of both TLVs are the results of applying the given operations over the AES-CTR-128 key.

Upgrade process

When starting a new upgrade process, MCUBoot checks that the image in slot1 has the ENCRYPTED flag set and has the required TLV with the encrypted key. It then uses its internal private/secret key to decrypt the TLV containing the key. Given that no errors are found, it will then start the validation process, decrypting the blocks before check. A good image being determined, the upgrade consists in reading the blocks from slot1, decrypting and writing to slot0.

If swap is used for the upgrade process, the encryption happens when copying the sectors of slot1 to the scratch area.

The scratch area is not encrypted, so it must reside in the internal flash of the MCU to avoid attacks that could interrupt the upgrade and dump the data.

Also when swap is used, the image in slot0 is checked for presence of the ENCRYPTED flag and the key TLV. If those are present the sectors are re-encrypted when copying from slot0 to slot1.

PS: Each encrypted image must have its own key TLV that should be unique and used only for this particular image.

Also when swap method is employed, the sizes of both images are saved to the status area just before starting the upgrade process, because it would be very hard to determine this information when an interruption occurs and the information is spread across multiple areas.

Creating your keys

  • If using RSA-OAEP, generating a keypair follows steps similar to those described in signed_images
  • If using AES-KW-128 (newt only), the kek can be generated with a command like dd if=/dev/urandom bs=1 count=16 | base64 > my_kek.b64