MKL27Z644 Bootloader encryption

cancel
Showing results for 
Search instead for 
Did you mean: 

MKL27Z644 Bootloader encryption

258 Views
Contributor IV

Hi,

I built NXP_Kinetis_Bootloader_2_0_0\targets\MKL25Z4\kds\freedom_bootloader. It works fine. Now I would like to encrypt application image (the image that is received by this bootloader and flashed to the flash memory).

Please provide instructions:

1) How do I build this bootloader with decryption support?

2) How can I create encrypted application image?

3) How do we send encrypted application image to the device (via USB HID)?

I know my MCU doesn't have any hw crypto module, but I think I can use e.g. GitHub - kokke/tiny-AES-c: Small portable AES128/192/256 in C  to decrypt AES encrypted image in bootloader. Or is there already any small flash footprint library provided by NXP?

Is there any tutorial for this? Are there any sample projects (even for different MCUs)?

Labels (1)
0 Kudos
11 Replies

2 Views
Specialist V

Martin

The uTasker project includes KBOOT USB-HID operation with AES256 encryption (for processors with or without crypto accelerators).

For the KL27 I use either the mbedtls, openSSL or Wolf SSL crypto functions, although mbedTLS gives smallest code size.
There are some comparisons between then at https://www.utasker.com/docs/uTasker/uTasker_Cryptography.pdf

As reference, KBOOT HID without encryption is 11.6k in size. With AES256 encryption on KL27 it is 15.6k (4k Flash cost for the encryption). I don't know Tiny AES or whether it gives smaller code (how big is your non-encrypted binary at the moment?).

To encrypt files for loading I use

uTaskerConvert.exe file_to_encrypt.bin aes256_coded.bin $"aes256 secret key" $"initial vector"

You can get it here:
https://www.utasker.com/forum/index.php?topic=1445.0

The same AES256 (secret) key and optional initial vector strings simply have to be used by the decryption routine.

I understand you are not allowed to use existing solutions but contact me via private mail in case you need help with an immediate solution or consulting advice.

Regards

Mark

[uTasker project developer for Kinetis and i.MX RT]

0 Kudos

2 Views
Contributor IV

Hi Mark,

thanks, so finally I'll try uTasker, it seems your bootloader has all the features I need :smileyhappy:  I googled a little to find how uTasker can be used in Visual Studio, no luck. Do you support e.g. VisualGDB? Is it possible to debug uTasker application using Visual Studio? I use VS2019 a the moment with VisualGDB 5.5.

Thank you

Martin

0 Kudos

2 Views
Specialist V

Martin

The project can be built in Visual Studio: https://www.utasker.com/docs/KINETIS/uTaskerV1.4_Kinetis.pdf
( here is the serial loader for Kboot HID AES256 being build in VS: https://www.youtube.com/watch?v=MXsJvTdCcH4&list=PLWKlVb_MqDQFZAulrUywU30v869JBYi9Q&index=25 )
and when it runs in VS it simulates the Kinetis (or i.MX RT) part.


It uses a post-build step to also generate an object (using GCC) that can be loaded to the HW.
For HW debugging the project can be used in KDS, MCUXpressor, IAR, uVision, Crossworks, CooCox, etc.
I haven't yet tried VisualGDB but I expect that it will allow direct HW debugging in VS too if you have it.

I fact I am surprised that you use VisualGDB because, although I have always thought that it is a game changer, it seems to be poo-pooed by the majority of engineers due to the fact that they prefer a Linux/Mac cross-platform solution that has no links to Microsoft. But I am very pleased to hear that you are actually using it!

To build the serial loader in VS one opens the VS project located at
\Applications\uTaskerSerialBoot\Simulator\uTaskerSerialBoot.vcxproj

Please send me your email so I can send you account details to the professional version since the open source one doesn't include all security stuff. You can have a free commercial license if support remains at this forum.
The video (above) explains how to configure. For your board it is essentially (all in config.h):
#define FRDM_KL27Z (the board/processor - almost any part can be chosen without needing any other changes - parts with crypto accelerators will automatically use them)
#define USB_INTERFACE
#define HID_LOADER
#define KBOOT_HID_LOADER
#define KBOOT_SECURE_LOADER
- optionally set #define USB_MSD_DEVICE_LOADER and USB_MSD_DEVICE_SECURE_LOADER for KBOOT / USB-MSD composite
- optionally set #define SERIAL_INTERFACE and #define KBOOT_LOADER if you want secure Kboot also on a UART

Choose your decrypt keys (strings) in
serial_loader.c
at
static const CHAR decrypt_key[] = "aes256 secret key";
and
static const CHAR initial_vector[] = "initial vector";

and match these with the ones used to encrypt the application's binary file.

You will see that secure loading involves just two changes:
1.
Call to
fnPrepareDecrypt(0);                             // prepare AES-256 decryption key and initial vector
when KBOOT_COMMAND_TAG_ERASE_REGION is received (to delete space for the code)
2.
Decryped flash programmer
fnWriteBytesSecure(ptrFlashAddress, ptrKBOOT_packet->ucData, usBuff_length);
instead of
fnWriteBytesFlash(ptrFlashAddress, ptrKBOOT_packet->ucData, usBuff_length); // program flash
each time data is received with KBOOT_REPORT_ID_DATA_OUT

To build with GCC as post-build step choose the appropriate VS target (with the GCC step) and ensure you have set up the make file for your processor as described here: https://www.utasker.com/kinetis/compilers.html#GCC

If you need to change KBOOT handling you can find this in
extern int fnHandleKboot(QUEUE_HANDLE hInterface, int iInterfaceType, KBOOT_PACKET *ptrKBOOT_packet)
in serial_loader.c (valid for UART and HID)

Good luck

Regards

Mark

P.S. If building with the post build make/file step, make sure that you put this version of make.exe into the GCC binary directory:

https://www.utasker.com/forum/index.php?topic=1988.msg7410#msg7410

0 Kudos

2 Views
Contributor IV

Mark,

you have PM with my email address. Waiting for your reply so I can start digging into uTasker.

I know I'm weird that I use Windows as an HW/SW engineer. And Linux only marginally. I think I don't use many features of VisualGDB, I often rather edit makefiles manually. It is just the best experience to work in Visual Studio.

0 Kudos

2 Views
Specialist V

Martin

I sent the details.

You should feel at home since uTasker is essentially a VS project (that happens to build also with most cross compilers). I have always found the VS editor and tools highly productive and developing and testing applications  in the simulator is 10 fold faster than with an IDE and the HW.

"Theoretically" you can configure and complete the work you need in a few minutes (for any Kinetis part) so if all goes well you may experience a paradigm shift in embedded development efficiency: If not just ask here to solve any complications.

Regards

Mark

P.S. The manual serial loader make file is

\Applications\uTaskerSerialBoot\GNU_Kinetis\make_uTaskerSerialBoot_GNU_Kinetis
and works with any loader configuration and any processor as long as the CPU type and linker script is set correctly. It is also included in the VS project so can be accessed there directly for simplicity.

0 Kudos

2 Views
Contributor IV

I also have some questions regarding how your bootloader works:

1) Original NXP's bootloader does transitions between bootloader and app by calling app's reset vector. This means some peripherals were not in their default reset state. This is documented and expected behaviour but I don't like it. In my modified NXP's bootloader I write a constant to System Register file and perform cpu reset. After reset, bootloader immediatelly checks value of System Register file (without performing any peripheral initialization) and if it contains certain value it resets System Register file and jumps to app. How your bootloader behaves when transiting between bootloader and app (and vice versa)? I guess it doesn't use System Register file (or similar technique). I think I will have to modify start_application() function in kinetis.c and some function that serves as an entry point of the bootloader. What are they?

2) On uTasker Utilities  there is: Use 2: "uTaskerConvert file1.bin file2.bin -0x22ba -b267a8200926 -ab627735ad192b3561524512 -17cc –f109" . Is there a more comprehensive documentation of parameters:  -0x22ba, -17cc and –f109. Where in actual source code of the bootloader are they used?

Thank you

Martin

0 Kudos

2 Views
Specialist V

Martin

1.

The serial loader expects to be called from a reset and so don't generally do any special handling when it starts.
However, in some cases this is used (see the appendix in the serial loader's document):

#define FORCE_BOOT()           ((_READ_PORT_MASK(D, SWITCH_3) == 0) || ((SOFTWARE_RESET_DETECTED()) && (*(BOOT_MAIL_BOX) == RESET_TO_SERIAL_LOADER)))   // hold SW3 at reset to force loader mode, or commanded to stay in loader mode


This doesn't use the system register file (which would be processor dependent) but instead uses a mail-box and commanded reset. It allows the serial loader to be started by an application (writes command in RAM mail box and commands reset, or it can also be used by the serial loader to command a reset of itself to directly start the application). This corresponds to your technique where you can then be 100% sure that the registers are in their original reset state when the application starts.

In fact this video shows the technique being used on another device:
https://www.youtube.com/watch?v=dq-m-Dokq7E&feature=youtu.be
to allow the serial loader to be controlled to start the application or itself, and also because the USB in that chip is quite sensitive when not carefully de-initialised between serial loader and application use.

However more common is to use RESET_PERIPHERALS() just before the jump (see the jump code below) whereby used peripherals are de-initialised and the NVIC reset so that there are no potential pending interrupts when the application starts configuring its peripheral use.

extern void fnJumpToValidApplication(int iResetPeripherals)
{
    if ((*(unsigned long *)fnGetFlashAdd((unsigned char *)_UTASKER_APP_START_) != 0xffffffff) && (*(unsigned long *)(fnGetFlashAdd((unsigned char *)_UTASKER_APP_START_) + 4) != 0xffffffff)) {
        if (iResetPeripherals != 0) {                                    // if peripherals have been in use
            uDisable_Interrupt();                                        // ensure interrupts are disabled when jumping to the application
            RESET_PERIPHERALS();                                         // reset peripherals and disable interrupts ready for jumping to the application
        }
        start_application(_UTASKER_APP_START_);                          // jump to the application
    }
}

2. See https://www.utasker.com/docs/uTasker/uTasker_BM_Loader.pdf
for some details about the header. These parameters are however used by the "Bare-Minimum" encrypted loader (and not the serial loader). For AES256 encryption you won't use these and they are not used by the serial loader code. See \Applications\uTaskerBoot\uTaskerBootLoader.c to see their use in that code.

Regards

Mark

0 Kudos

2 Views
Contributor IV

Hi Mark,

regarding https://www.utasker.com/docs/KINETIS/uTaskerV1.4_Kinetis.pdf : I was able to get to part number 6 on page 5. There is static const NETWORK_PARAMETERS in application.c, but this code is grey (no define enables it). Should I modify anything to enable that code or should I just continue with the tutorial?

Also part 3 and 4 on page 5, I think they are obsolete as there are individual configurations in VS for every part you support.

Regarding serial bootloader - when I build Tasker Serial Loader - Kinetis plus GNU build, gcc build fails:

1>arm-none-eabi-gcc -mcpu=cortex-m0plus -mthumb -mlittle-endian -mthumb -Wall -Wstrict-prototypes -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -Wundef -I../ -D _GNU -D _KINETIS -g -c -Os ../../../Hardware/Kinetis/Crypto/mmcau_aes_functions.S -o Build/mmcau_aes_functions.o
1>../../../Hardware/Kinetis/Crypto/mmcau_aes_functions.S: Assembler messages:
1>../../../Hardware/Kinetis/Crypto/mmcau_aes_functions.S:158: Error: selected processor does not support `stmdb sp!,{r4-ip,lr}' in Thumb mode
1>../../../Hardware/Kinetis/Crypto/mmcau_aes_functions.S:161: Error: selected processor does not support `movw r8,#:lower16:setkey_reg_data' in Thumb mode
1>../../../Hardware/Kinetis/Crypto/mmcau_aes_functions.S:162: Error: selected processor does not support `movt r8,#:upper16:setkey_reg_data' in Thumb mode
1>../../../Hardware/Kinetis/Crypto/mmcau_aes_functions.S:172: Error: cannot honor width suffix -- `ldmia r8,{sl-ip}'

I updated Applications\uTaskerSerialBoot\GNU_Kinetis\Build_Kinetis.bat (to set path to my toolchain) :

SET PATH=C:\SysGCC\arm-eabi\bin
make -f make_uTaskerSerialBoot_GNU_Kinetis all

I of course modified makefile so it uses C flags:

C_FLAGS = -mcpu=cortex-m0plus -mthumb -mlittle-endian -mthumb -Wall -Wstrict-prototypes -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -Wundef

and linker file:

$(CC) $(C_FLAGS) -Os -g -TKL_64_16.ld -nostartfiles -Xlinker --gc-sections -Wl,-Map,"uTaskerSerialBoot.map" -o "uTaskerSerialBoot.elf" $(OBJS)

Martin

0 Kudos

2 Views
Specialist V

Martin

1. When following the tutorial choose a board with Ethernet (like FRDM-K64F) so that the Ethernet part can work.
In config.h make sure that neither BLINKY nor HELLO_WORLD are enabled since these will reduce the project to simple "blinky" and "Hello, World" cases (without Ethernet):
Finally make sure that ETH_INTERFACE is enabled so that all IP parameters and the TCP/IP stack are used.

2. Can you check that the makefile has this (from line 37)?

       Build/mmcau_aes_functions.o

ifeq (,$(findstring mcpu=cortex-m0plus,$(C_FLAGS)))
A_FLAGS = -DARM_MATH_CM4
else
A_FLAGS = -DARM_MATH_CM0PLUS
endif

mmcau_aes_functions.S is used by Cortex-M4 processors that have the MMCAU HW accelerator. For the KL parts, which don't have it and won't try to use it, this file is not relevant.

When i build the loader I get:

1>arm-none-eabi-gcc -mcpu=cortex-m0plus -mthumb -mlittle-endian -mthumb -Wall -Wstrict-prototypes -fmessage-length=0 -fsigned-char  -ffunction-sections -fdata-sections -Wundef -DARM_MATH_CM0PLUS -I../ -D _GNU -D _KINETIS -g -c -Os ../../../Hardware/Kinetis/Crypto/mmcau_aes_functions.S -o Build/mmcau_aes_functions.o
1>arm-none-eabi-gcc -mcpu=cortex-m0plus -mthumb -mlittle-endian -mthumb -Wall -Wstrict-prototypes -fmessage-length=0 -fsigned-char  -ffunction-sections -fdata-sections -Wundef -Os -g -TKL_64_16.ld -nostartfiles -Xlinker --gc-sections -Wl,-Map,"uTaskerSerialBoot.map" -o "uTaskerSerialBoot.elf" Build/serial_loader.o Build/usb_device_loader.o Build/disk_loader.o Build/usb_host_loader.o Build/usb_application.o Build/webInterface.o Build/mass_storage.o Build/MODBUS.o Build/modbus_app.o Build/GLCD.o Build/kinetis.o Build/crypto.o Build/aes_mbedTLS.o Build/eth_drv.o Build/Driver.o Build/uMalloc.o Build/uTasker.o Build/Tty_drv.o Build/i2c_drv.o Build/USB_drv.o Build/uFile.o Build/Watchdog.o Build/Ethernet.o Build/arp.o Build/ip.o Build/tftp.o Build/udp.o Build/tcp.o Build/http.o Build/dhcp.o Build/ip_utils.o Build/webutils.o Build/icmp.o Build/mmcau_aes_functions.o
1>arm-none-eabi-objcopy --output-target=srec uTaskerSerialBoot.elf uTaskerSerialBoot.s19
1>arm-none-eabi-objcopy --output-target=ihex uTaskerSerialBoot.elf uTaskerSerialBoot.hex
1>arm-none-eabi-objcopy --only-section=.data --only-section=.init --only-section=.text --only-section=.rodata --only-section=.vectors --only-section=.f_config --output-target=binary uTaskerSerialBoot.elf uTaskerSerialBoot.bin
1>arm-none-eabi-size   uTaskerSerialBoot.elf
1>   text       data        bss        dec        hex    filename
1>  15014         15      10051      25080       61f8    uTaskerSerialBoot.elf

which is successful. It actually builds the assembler file but its content is not used due to the -DARM_MATH_CM0PLUS pre-processor define. It may be that you checked out a slightly older version where thsi was not yet included (?)

If you still have problems remove this file from the make file since you don't need it.

Otherwise you have done every thing correctly.

Regards

Mark

0 Kudos

2 Views
Contributor IV

Mark, I'm in master branch, latest commit.

My Applications\uTaskerSerialBoot\GNU_Kinetis\make_uTaskerSerialBoot_GNU_Kinetis doesn't contain

ifeq (,$(findstring mcpu=cortex-m0plus,$(C_FLAGS)))
A_FLAGS = -DARM_MATH_CM4
else
A_FLAGS = -DARM_MATH_CM0PLUS
endif

 

After I delete Build/mmcau_aes_functions.o in OBJS and build command for Build/mmcau_aes_functions.o it works:

1> text data bss dec hex filename
1> 15072 15 10051 25138 6232 uTaskerSerialBoot.elf

0 Kudos

2 Views
Specialist V

Martin

Following your report I have found that commits to the repository were not being pushed to the server (only locally) due to an incorrect setting after a re-installation following a disk failure. Thss has been solved in the meantime and repository is re-synchronised.

Although I doubt that it will be needed for your work pulling the repo would now update to the most up to date version - this does explain the need to remove the mmcau assembler file in order to build.

Regards

Mark

0 Kudos