This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Adding Encryption to Secure DFU SDK v15

In the following Q&A I will outline a working implementation of encrypted firmware updates using the Secure DFU in SDK v15. This implementation allows for encrypted firmware updates of both the application and the bootloader.


Creating a custom DFU init packet

We need a unique nonce/IV for each firmware version to avoid reuse. Therefore the init packet generated by nrfuitl needs to be extended to include the nonce. You can either customize nrfutil as outlined here: http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.tools/dita/tools/nrfutil/nrfutil_customizing.html?cp=5_5_8; you can use the version of nrfutil.exe (v3.5.1) found below (which has been modified to generate a new random 12 byte nonce (created with a call to os.urandom()) and include it in the init packet each time a call to 'nrfutil pkg generate' is made) or make the changes to the nrfutil source code (v3.5.1) as outlined below:

Replace lines 234-254 of package.py with:


Replace lines 256-273 of package.py with:

Add the following between line 353 & 355 in package.py:

Replace lines 368-379 of package,py with:

Replace lines 104-11 of manifest.py with:

Replace lines 123-128 of manifest.py with:

Replace lines 65-77 of init_packet_pb.py with:

Replace lines 100-110 of init_packet_pb.py with:


https://devzone.nordicsemi.com/cfs-file/__key/support-attachments/beef5d1b77644c448dabff31668f3a47-44326a9c207d4171a49f9b8ad4cb8a67/nrfutil.exe

The following command will display the contents of the init packet and allow you to view the 12-byte nonce value:


Bootloader changes required to process encrypted firmware

Let's begin by making the necessary changes to two files in the dfu libraries (nrf_dfu_validation.c, nrf_dfu_req_handler.c, dfu-cc.proto & dfu-cc.options) to compute the appropriate crc32 values in the correct places; to decrypt the firmware images and to correctly process the newly added nounce in the init packet.

nrf_dfu_validation.c

In nrf_dfu_validation.c we want to add the following code which includes a function for intialising the ECB module:

Here is our encrypt/decrypt code which has been modified from the version found here to allow us to access it from the on_data_obj_write_request function in nrf_dfu_req_handler.c and allow us to pass it one byte at a time. Add the following function to nrf_dfu_validation.c:

In order to check whether the firmware type requires decryption, add the following function to nrf_dfu_validation.c:

We need to create the following function in nrf_dfu_validation.c to initialise the ECB module with the ECB key and nonce from the init packet:

Call the new nrf_dfu_validation_crypt_init() function from within the nrf_dfu_validation_init_cmd_execute() function as shown below:

In the nrf_dfu_validation_post_data_execute function, add the following code to compute a crc32 value on the decrypted firmware image that has been written to flash. This crc32 value will be stored (written to flash) and checked on every subsequent startup. Because we are encrypting application firmware images and bootloader firmware images, the crc32 needs to computed in both scenarios.

The location to place this code in the nrf_dfu_validation_post_data_execute function is shown below:

nrf_dfu_req_handler.c

In the on_data_obj_write_request function, the crc32 value is currently computed after the call to nrf_dfu_flash_store. We want to compute the crc32 value on the encrypted data. Add the following line of code before the call to the nrf_dfu_flash_store function:

Replace:

with the following code to set the crc32 value previously computed on the encrypted data:

Now let's turn our focus to decrypting the data. In on_data_obj_write_request function in nrf_dfu_req_handler.c add the following code (prior to the call to nrf_dfu_flash_store) to loop through the buffer and decrypt each individual byte:

The code above needs to be placed after the crc32 has been computed and before the call to nrf_dfu_flash_store function (as shown below):

dfu-cc.proto & dfu-cc.options

Add the following code to the initCommand message definition found in dfu-cc.proto:

as shown below:

Replace the contents of dfu-cc.options with the following:

and then perform Step 4. as described here.


Generating an encrypted package

Now let's look at how we can generate a firmware package containing an encrypted firmware image (.bin) that our new bootloader will decrypt.

Encrypting the firmware image

First generate a package (dfu_pkg_unencrypted_app_v0_0_1.zip) using the unencrypted firmware image (application_v0_0_1.hex) using the following command (ensure you are using the modified nrfutil.exe) :

Then view the contents of the init packet and obtain the 12-byte nonce value with the following command (ensure you are using the modified nrfutil.exe):

Next unzip dfu_pkg_unencrypted_app_v0_0_1.zip.

Edit the following command to replace '100f0e0d0c0b0a090807060504030201' with your ECB Key (in big-endian format), and replace the 'ffffffffffffffffffffffff' in 'ffffffffffffffffffffffff00000000' with the12-byte nonce found previously (in big-endian format).

The previous command will create a file called encrypted_application_v0_0_1.bin in the unzipped folder called dfu_pkg_unencrypted_app_v0_0_1. Delete the file labelled application_v0_0_1.bin and rename encrypted_application_v0_0_1.bin to application_v0_0_1.bin.

Leave both the application_v0_0_1.dat and the manifest.json files untouched and zip the three files (.bin, .dat, .json) up into 'dfu_pkg_app_v0_0_1.zip' - you now have an encrypted firmware package.

  • Hi,

    Thank you for sharing this.

  • Hi, Mathew.
    I changed the nrfutil as you recommended, but using it for create zip file, there is no mention of  "nonce" when call "pkg display"
    DFU Package: <dfu_pkg_app_v0_0_1.zip>:
    |
    |- Image count: 1
    |
    |- Image #0:
    |- Type: application
    |- Image file: dfu_pkg_app_v0_0_1.bin
    |- Init packet file: dfu_pkg_app_v0_0_1.dat
    |
    |- op_code: INIT
    |- signature_type: ECDSA_P256_SHA256
    |- signature (little-endian): 80e53a7e8ae12edb0d17eca5557219459679b753c2920b290d49df603815eb39c4c45814eba459d5a34d533f99ce2e6028edfc4c002549bce4b1ca20eaf850fd
    |
    |- fw_version: 0x00000001 (1)
    |- hw_version 0x00000034 (52)
    |- sd_req: 0xAF
    |- type: APPLICATION
    |- sd_size: 0
    |- bl_size: 0
    |- app_size: 24032
    |
    |- hash_type: SHA256
    |- hash (little-endian): c249494ce7fcf9a6230c1c4cda3b4410951f45094b9cdbfab37806aa84f85597
    |
    |- is_debug: False

    Although in folder
    C:\Python27\Lib\site-packages\nrfutil-4.0.0-py2.7.egg\nordicsemi\dfu
    the file "dfu_cc_pb2.py" is created as You recommend with
    optional bytes  nonce = 10;
    and
    dfu.InitCommand.nonce max_size:12.
    But when I use Your "1-nrfutil.exe"
    the string
     |- nonce (little-endian): ca3c807241b2c02b85323556
    is present.
    Is need to change init_packet_pb.py and package.py ?
    What could be? Maybe you missed something?
    ------------------------------------------------------------
    If I use Your "1-nrfutil.exe" to enerate package, bin file in archive stil not encrypted.
    What do you mean by encryption? Encrypting the firmware itself or something else?
    You wrote: "Next, we need to generate a package using the UNENCRYPTED firmware image" using "nrfutil pkg generate..." and using nRF Connect load this zip-file to device.
    But, where in you text encrypting procedure? We load to device UNencrypted firmware.
    Best, Vyacheslav.
  • Mathew, thanks for clarifying the description of encryption generation.

    Could you please describe the process of changing nrfutil in more detail? For example  is need to change init_packet_pb.py and package.py.

    I changed the code of nrfutil as you recommend but when I call nrfutil with params "pcg display" is no mention of "nonce".

    Thanks.

  • Hi Mathew,

    Can you please share the required change to nrfutil to add the nonce? You attached a .exe but I'm modifying the nrfutil source to be able to use this on Linux. 


    Regards.

  • I've updated the post to include the changes made to the files found in the pc-nrfutil/nordicsemi/dfu folder. Don't forget to edit the dfu-cc.proto file and regenerate the dfu_cc_pb2.py file with the protocol buffer compiler.

1 2 3 4 5 »