MCUboot with encryption enabled

The MCUboot with encryption enabled sample demonstrates secure device firmware update (DFU) using MCUboot with encryption enabled. You will learn how to build encrypted images and deploy them to supported development kits, protecting application code from unauthorized access during updates. This sample does not contain its own application code. Instead, it focuses on configuring encryption in MCUboot and generating encrypted DFU images. To provide a working example, the sample uses the SMP server project as its application by directly importing the project’s sources in the main CMakeLists.txt file.

Requirements

The sample supports the following development kits:

Hardware platforms

PCA

Board name

Board target

nRF7120 DK

nrf7120dk

nrf7120dk/nrf7120/cpuapp

nRF54LV10 DK

PCA10188

nrf54lv10dk

nrf54lv10dk/nrf54lv10a/cpuapp

nRF54LM20 DK

PCA10184

nrf54lm20dk

nrf54lm20dk/nrf54lm20b/cpuapp nrf54lm20dk/nrf54lm20a/cpuapp

nRF54L15 DK

PCA10156

nrf54l15dk

nrf54l15dk/nrf54l15/cpuapp

nRF54H20 DK

PCA10175

nrf54h20dk

nrf54h20dk/nrf54h20/cpuapp

Note

On the nRF54LV10 DK, the SMP server configuration is trimmed to fit the application slot size. For the nRF54L15 DK, an overlay is used to increase the size of the MCUboot partition. It is necessary because the enabled logging features require more space than the default partitioning provides.

Overview

This sample provides a practical starting point for using MCUboot with application image encryption enabled. It walks you through the process of building encrypted firmware images and updating them securely on a supported development kit.

MCUboot in this sample is built with enhanced debug output, making it easier to observe and understand the secure boot process. For more information on minimal builds and optimization, see the MCUboot minimal configuration documentation.

The firmware update protocol is handled by the MCUmgr SMP server, so you can use all related configuration options.

Platform-specific information

The nRF54L Series platforms use the following cryptographic algorithms:

  • ED25519 for digital signature verification.

  • X25519 for securely exchanging AES encryption keys during image updates.

Configuration

See Configuring and building for information about how to permanently or temporarily change the configuration.

Configuration options

You can use the following Kconfig options to configure the sample:

  • CONFIG_FPROTECT - This option is disabled by default. It enables flash protection for the MCUboot code. You can disable it for development and enable it for production purposes to prevent MCUboot overwriting at runtime. This option is not available on the nRF54H20 DK. You can enable the flash protection on this platform using IronSide services (see Protecting a device with IronSide SE for more details).

  • CONFIG_MCUBOOT_LOG_LEVEL_DBG - This option is enabled by default. It allows you to easily verify that MCUboot is starting up. Disable it for production builds.

  • CONFIG_BOOT_SWAP_SAVE_ENCTLV - Enable this option in the MCUboot configuration if you are performing DFU to an external storage device. This ensures that the random AES key used for the currently swapped image is not exposed.

  • SB_CONFIG_BOOT_ENCRYPTION_KEY_FILE - MCUboot uses a default encryption key. To override it, adjust this option by setting a path to your custom encryption key file.

  • CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION - Use this option to set the application image version for software updates.

To configure the sample to use KMU crypto storage, add -DSB_EXTRA_CONF_FILE=sysbuild_kmu.conf to the build command line. This option is supported only on nRF54L Series devices. This option brings in sysbuild configuration file that selects two additional options:

To configure the sample to use ITS crypto storage, add the -DSB_EXTRA_CONF_FILE=sysbuild_its.conf option to the build command. This option is supported only on nRF54H Series devices. This option brings in sysbuild configuration file that selects one additional option:

Signature key

Even with encryption enabled, MCUboot relies on signature keys to verify images at each boot. On some devices, you can store the public signature key in one of the following ways:

  • Compile it into the device firmware.

  • Use the crypto storage.

If your application is not using crypto storage, you can set a key with the SB_CONFIG_BOOT_SIGNATURE_KEY_FILE Kconfig option. In this case, MCUboot can only use one signature key file compiled into the firmware.

On devices that store keys in crypto storage, the number of stored keys depends on the specific device and may range from one to several. Typically, three slots are reserved for storing MCUboot signature keys. To use MCUboot with crypto storage, you must provision a set of keys to the device in addition to compiling in support for crypto storage. If you use KMU for signature key storage, follow the instructions in Provisioning the KMU to provision the keys. If you use ITS for signature key storage, follow the instructions in the Provisioning keys on the nRF54H20 SoC page to provision the keys.

Security considerations

See the list of best practices, security-related options, and recommended settings when configuring the sample:

  • For secure production builds:

    See the Configuration section for details.

  • MCUmgr’s shell is enabled by default, allowing you to manage commands using a serial terminal.

  • MCUboot accepts unencrypted images in the secondary slot if signature verification passes. For higher security, use encrypted images wherever possible.

  • KMU key handling:

    • By default, KMU is not used to store keys in MCUboot.

    • If KMU is enabled, the asymmetric private key used for transport encryption of the random AES key is still compiled into MCUboot in plain text. Use hardware-backed key storage in production.

    • Do not leave encryption keys or private keys in plain text inside the MCUboot binary.

  • ITS key handling:

    • By default, MCUboot does not use ITS to store keys.

    • If you enable ITS, MCUboot still compiles the asymmetric private key for transport encryption of the random AES key into the binary in plain text. Use hardware-backed key storage in production.

    • Do not store encryption keys or private keys in plain text in the MCUboot binary.

Signing encrypted images outside the build system

You can sign and encrypt application images outside the NCS build system using imgtool directly. This is useful for production workflows where the signing infrastructure is separate from the build environment.

To do this, you need to extract the raw application payload from an unencrypted signed image and then re-sign and encrypt it with imgtool.

Extracting the raw payload

Extract the raw application binary from the unencrypted signed image (zephyr.signed.bin) by stripping the MCUboot header and TLV trailer. Do not use the encrypted image (zephyr.signed.encrypted.bin).

See the following example:

import struct

data = open("build_dir/mcuboot_with_encryption/zephyr/zephyr.signed.bin", "rb").read()
hdr_size = struct.unpack_from("<H", data, 4)[0]
img_size = struct.unpack_from("<I", data, 12)[0]
open("raw_payload.bin", "wb").write(data[hdr_size : hdr_size + img_size])

Re-signing and encrypting

Use imgtool sign with the --encrypt option to re-sign the extracted payload and encrypt it with your X25519 key. Ensure that the signing parameters (--align, --header-size, --slot-size, --sha) match the values used during the original build. You can find these in the build directory configuration files.

Note

On nRF54L Series devices, you must use also the --hmac-sha 512 argument. Without it, MCUboot will reject the image.

See the following example for the nRF54L Series:

imgtool sign \
  --align 16 \
  --header-size 0x800 \
  --slot-size 0xa5000 \
  --version 2.0.0 \
  --pad-header \
  --key root-ed25519.pem \
  --encrypt custom-x25519-enc-priv.pem \
  --sha 512 \
  --hmac-sha 512 \
  raw_payload.bin \
  encrypted_output.bin

Building and running

This sample can be found under samples/dfu/mcuboot_with_encryption in the nRF Connect SDK folder structure.

To build the sample, follow the instructions in Building an application for your preferred building environment. See also Programming an application for programming steps and Testing and optimization for general information about testing and debugging in the nRF Connect SDK.

Note

When building repository applications in the SDK repositories, building with sysbuild is enabled by default. If you work with out-of-tree freestanding applications, you need to manually pass the --sysbuild parameter to every build command or configure west to always use it.

By default, the sample builds with KMU support on platforms that support it (nRF54L Series). Otherwise, the signature key is embedded in the MCUboot binary. To see the encryption workflow, you must build two application images with different version numbers (for example, set the CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION Kconfig option to 1.0.0 and 2.0.0), using separate build directories.

Testing

After programming the device with the first image, verify its functionality:

  1. Connect to the device’s serial console.

  2. Reset the device.

  3. Observe the boot output confirming successful start of the SMP Server application:

    *** Booting MCUboot v2.3.0-dev-0d263faf6e55 ***
    *** Using nRF Connect SDK v3.1.99-4f1d50b83bfb ***
    *** Using Zephyr OS v4.2.99-164b47d30942 ***
    
    *** Booting nRF Connect SDK v3.1.99-4f1d50b83bfb ***
    *** Using Zephyr OS v4.2.99-164b47d30942 ***
    [00:00:00.075,512] <inf> bt_sdc_hci_driver: SoftDevice Controller build revision:
                                                9d dc 12 f9 d0 01 5e 7e  af 5b 84 59 45 12 69 4e
    |......^~ .[.YE.iN
                                                5e dc 0b 2f                                      |^../
    [00:00:00.076,807] <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
    [00:00:00.076,822] <inf> bt_hci_core: HW Variant: nRF54Lx (0x0005)
    [00:00:00.076,836] <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version
    157.4828 Build 1577177337
    [00:00:00.077,217] <inf> bt_hci_core: HCI transport: SDC
    [00:00:00.077,269] <inf> bt_hci_core: Identity: C0:0A:89:ED:8F:B9 (random)
    [00:00:00.077,285] <inf> bt_hci_core: HCI: version 6.1 (0x0f) revision 0x30c0, manufacturer 0x0059
    [00:00:00.077,299] <inf> bt_hci_core: LMP: version 6.1 (0x0f) subver 0x30c0
    [00:00:00.077,765] <inf> smp_bt_sample: Advertising successfully started
    
  4. To test encrypted updates, upload the second (encrypted) image using any supported method, such as MCUmgr over Bluetooth, serial shell, or another DFU transport. For more information on DFU, see the Zephyr Device Firmware Upgrade documentation.

  5. After uploading the image, mark the new image for test.

  6. On reboot, verify that the new firmware version is running. If the image is not confirmed, the bootloader will revert to the previous version. The image will then be re-encrypted if swapped out of the boot slot.

Note

This sample also accepts unencrypted firmware updates. If you upload an unencrypted and properly signed image, MCUboot will successfully boot it.

Further information on image encryption and generating keys

More information on MCUboot support for image encryption can be found in the MCUboot documentation section under Encrypted images. Users should familiarize themselves with this section, as they will need to generate their own keys for encryption key exchange.

Note

The keys used in this sample are publicly known. Do not use them in your product under any circumstances.

To learn how to upload custom keys to KMU, see the Configuring DFU and MCUboot documentation page. To learn how to upload custom keys to ITS, see the Provisioning keys on the nRF54H20 SoC documentation page.

Dependencies

The sample depends on following subsystems and libraries: