How to start with code confidentiality on STM32H7S

This article gives step-by-step instructions on application encryption and MCE decryption, using the "MCE executes AES-crypted code" STM32Cube MCU Package example provided by STMicroelectronics. The user application that is programmed during the provisioning is the GPIO_IOToggle example from the STM32Cube MCU Package; it is encrypted and installed in external memory.

Info white.png Information
This step-by-step demonstration uses an STM32H7S78-DK board; all necessary files can be found in the STM32Cube_FW_H7RS\Projects\STM32H7S78-DK folder.

1. Introduction

This article provides easy instructions on how to encrypt and program a user application in external memory, provision the chip, and execute the encrypted code, using an example from the STM32Cube MCU Package. More specifically, these instructions show:

  • How to use the STM32Cube example provided.
  • How to encrypt an application using OpenSSL.
  • How to install the boot example and the encrypted application.

2. Prerequisites

2.1. Hardware

  • STM32H7S discovery board: STM32H7S devices have all the available security features, including the hardware cryptographic accelerator (STM327R devices do not support the hardware cryptographic acceleration)
  • Discovery board MB1736-STM32H7S (with USB-C cable)
STM32H7S DK.png

2.2. Tools

  • STM32Cube_FW_H7RS (V1.0.0 or later)
  • STM32CubeProgrammer (v2.16.0 or later) (with Trusted Package Creator (TPC) selected at installation)
  • IAR Embedded Workbench (rev 9.20.1 or later) + IAR Patch EWARMv9_STM32H7R-Sxx_Vx.x.x; the IAR patch is available in the STM32Cube MCU Package: STM32Cube_FW_H7RS_Vx.x.x\Utilities\PC_Software
  • TeraTerm, Putty, or equivalent terminal emulator

2.3. STM32Cube MCU Package

  • Download the STM32Cube_FW_H7RS firmware (place it close to the partition root to avoid long paths).
  • An STM32H7S78-DK directory is included in STM32Cube_FW_H7RS\Projects.

2.4. Literature


3. Application binary generation

  1. Open the GPIO_IOToggle example.
  2. Go to Options -> Output Converter and change the format to Raw binary, then click on OK.
  3. Go to Options -> Linker -> Config and click on Edit... to update the .icf file.
    This example must be stored in flash memory, so update the address so it is in line with the external memory storage.
    Update the vector table and memory regions as follows:
    ICF File Updated For Execution In External Memory
  4. Compile the project.

4. Application encryption

The application is encrypted in stream mode using the AES-128 CTR algorithm available in OpenSSL. The data encryption with AES 128 CTR is handled in 16-byte block units (128 bits). A binary file generated from an IDE (such as IAR) contains the addresses in low-to-high order. This binary file must be preprocessed before encryption and postprocessed after encryption for data ordering.

The preprocessing and postprocessing consist of a byte swap for every 16-byte block:

Byte swap for every 16 bytes block

The byte swap can be performed through a script, for example, the xxd command, which is available after installing the related script (this is a native command for Linux, and can be found for Windows by searching for xxd-for-windows in a search engine).

The following commands must be executed in a command prompt and opened in the same folder as the generated binary, after the OpenSSL installation and binary generation for the GPIO_IOToggle example.

  • First byte swap:
xxd.exe -e -g 16 GPIO_IOToggle_Appli.bin > tmp.txt
xxd.exe -r tmp.txt > tmp.bin
  • Encryption:
openssl enc -aes-128-ctr -nosalt -e -in tmp.bin -out tmp_enc.bin -iv C3C3C3C3A5A5A5A50000FEDC09000000 -K 89ABCDEF7123456789ABCDEF71234567
  • Second byte swap:
xxd.exe -e -g 16 tmp_enc.bin > tmp.txt
xxd.exe -r tmp.txt > GPIO_IOToggle_Crypted.bin

The -K option refers to the key that is used, and -iv refers to the initialization vector that is necessary to perform the encryption. Both are configurable but must be updated in the MCE configuration in the MCE_ExecuteAESCryptedCode_Boot example.

MCE Key and IV parameters location to be updated in the main.c file of the MCE_ExecuteAES_CryptedCode_Boot example.

Care must be taken when declaring the IV and Key. The Key parts declared in the boot example must be swapped for the OpenSSL encryption, and the nonce must to be swapped for the first half of the IV. The IV corresponds to the equivalent of the MCE counter[127:0] data block.

Correlation between OpenSSL Key and IV and MCE parameters configuration

For more information about the MCE implementation of stream cipher, refer to the dedicated chapter in the product reference manual.[1]

Warning white.png Warning
For a commercial product, define a custom IV and Key and do not take the default ones used in this demonstration.

The temporary files (tmp.txt, tmp.bin, and tmp_enc.bin) can be deleted after the process.

5. MCE_ExecuteAESCryptedCode_Boot configuration

Follow these steps to configure MCE_ExecuteAESCryptedCode_Boot:

  1. Open the MCE_ExecuteAESCryptedCode_Boot example.
  2. The MCE_ExecuteAESCryptedCode_Boot example code programs an encrypted application image in the external memory. This example uses a custom encrypted application, so this line must be deleted in the private include section in the main.c file:
    Line to be deleted in main.c
  3. In the previous step, the application was encrypted with a stream cipher. Update the MCE configuration to stream cipher mode in the main() function:
    Stream cipher mode enabled in the MCE configuration
  4. If the IV and Key have been updated, update parameters such as the key, nonce, and version of the MCE configuration. Refer to the figures in the previous steps to avoid any errors in this parameter update.
    For more information about the MCE implementation and configuration of the stream cipher, refer to the dedicated chapter in the product reference manual.[1]
  5. Generate the .bin file:
    1. Go to Options -> Options -> Output Converter and change the format to Raw binary.
    2. Click on OK.
      Output configuration to be changed to binary file
  6. Compile the project.

6. Debug authentication

The STM32 debug authentication controls the product life cycle, which includes regressions (for more details about the life cycle, refer to the product reference manual), debug reopening, and download forcing. When the STM32 product state is not open, the user can trigger the debug authentication services by sending a password or a certificate chain to the STM32 device. These two options are called debug authentication methods.

This demonstration uses a debug authentication with a preconfigured certificate

Warning white.png Warning
For security reasons, it is important to define a custom password or certificate and not use the default ones provided with the example.

For more information on the debug authentication on STM32H7Rx/Sx devices, refer to the dedicated wiki page, Debug authentication for STM32H7Rx/7Sx.
To understand how to configure and tailor debug authentication on STM32H7rx/Rx devices, refer to this wiki page: How to start with DA access on STM32H7RS.

7. Provisioning flow for STM32H7Sx devices

This section describes the basic steps to provision a product in the targeted configuration. The command that is used must be entered in a command prompt. The function RSSLIB_PFUNC->DataProvisioning uses SRAM3, so a prerequisite is to ensure that SRAM3 is fully available.

Before provisioning, ensure that DTCM_AXI_SHARE and ITCM_AXI_SHARE are cleared. If this is not the case, force the clearing with the following command:

STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -ob DTCM_AXI_SHARE=0 ITCM_AXI_SHARE=0

The following figure shows a provisioning flow.

Provisioning flow and regression


The list below shows the commands used in the numbered steps in the figure above. This provisioning flow example integrates the OB setup (such as WRP and HDP).

  • Step 1: set the PRODUCT_STATE to provisioning.
    STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -psrss 0x17
    
    This step must be done in the open product state. The product state can only be written with -psrss (product state RSS change) and this is handled by RSSLIB_PFUNC->SetProductState().
    More information about this function is available in the STM32H7Rx/7Sx reference manual.[1]
  • Step 2: provision the OBKeys for debug authentication.
    STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -hardRst
     STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -sdp ./../DA/Binary/DA_Config.obk
    
  • Step 3: remove the protections, and load MCE_ExecuteAESCryptedCode_Boot.bin in the user flash memory and GPIO_IOToggle_Crypted.bin in the external flash memory.
    • Remove the protections:
      • Remove the write protection through the FLASH_WRPSRP programming register. Address: 0x5200221C, mask: 0x000000FF, value: 0xFF, bit shift: 0x00.
         STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=UR >> nul
        STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -obrss 0x5200221C 0x000000FF 0xFF 0x00
        
      • Remove the hide protection through the FLASH_HDPSRP programming register. Address: 0x52002234, mask: 0x00FF00FF, value: 0x000000FF, bit shift: 0x00.
        STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=UR >> nul
        STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -obrss 0x52002234 0x00FF00FF 0x000000FF 0x00
    • Erase the user flash memory.
       STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=UR >> nul
      STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -e all
      
    • Set SRAM ECC protection and XSPI configuration (required for external memory use).
      STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -ob ECC_ON_SRAM=1
      STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -ob XSPI1_HSLV=1
      STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -ob XSPI2_HSLV=1
      
    • Download the binary to the user flash memory and set the required protections (replace %fw_location% with the STM32Cube_FW_H7RS location).
      STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -d %fw_location%\Projects\STM32H7S78-DK\Examples\MCE\MCE_ExecuteAESCryptedCode\EWARM\Boot\MCE_ExecuteAESCryptedCode_Boot\Exe\MCE_ExecuteAESCryptedCode_Boot.bin 0x8000000 -v
      
    • Set WRP and HDP protections for the user flash memory.
      STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=UR >> nul
      STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -obrss 0x5200221C 0x000000FF 0 0x00
      STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=UR >> nul
      STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -obrss 0x52002234 0x00FF00FF 0x00FF0000 0x00
      
    • Download the encypted binary to the external flash memory.
      (Replace %com_port% with the connected COM port and %fw_location% with the STM32Cube_FW_H7RS location.
      MX66UW1G45G_STM32H7S78-DK_XSPIM1-SFIx.stldr is used with the external flash memory MX66UW1G45G with the swapped mode of the XSPI I/O manager enabled, meaning that the external flash memeory is mapped at 0x9000 0000.)
      STM32_Programmer_CLI.exe -c port=%com_port% br=921600 -elbl "C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\ExternalLoader\MX66UW1G45G_S
      TM32H7S78-DK_XSPIM1-SFIx.stldr" -d %fw_location%\Projects\STM32H7S78-DK\Examples\GPIO\GPIO_IOToggle\EWARM\Appli\GPIO_IOToggle_Appli\Exe\GPIO_IOToggle_Crypted.bin 0x90000000 --verify
  • Step 4: change PRODUCT_STATE to closed.
    STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -psrss 0x72
    STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=UR >> nul
    
    The command STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=UR is used to force a reset on the device but results in the expected error No STM32 target found! , since the product state is at least provisioning.

8. Managing regression

If the process requires a full regression of the product, launch a regression using the debug authentication. It corresponds to step 5 in the provisioning flow example figure above.

STM32_Programmer_CLI.exe -c port=SWD speed=fast per=a key=.\Keys\key_3_leaf.pem cert=.\Certificates\cert_leaf_chain.b64 debugauth=1

The STM32CubeProgrammer command debugauth is described in the STM32CubeProgrammer documentation. The example files (.pem and .b64) can be found in the Keys and Certificates folders in STM32Cube_FW_H7RS_V1.0.0\Projects\STM32H7S78-DK\ROT_Provisioning\DA.

In the STM32Cube example, the requested action is linked with the "per" (permissions) parameter. The list of allowed permissions is detailed below.
Syntax: per=[Permission]
The user can choose from the following permission values:

  • a: Full regression
  • b: Debug opening level 3
  • c: Debug opening level 2
  • d: Debug opening level 1
  • e: Forced download

9. Verifying the product configuration

At any stage of the provisioning, the product configuration can be verified. This paragraph describes several possibilities to perform checks.

  • Product state:
    When moving to a closed product state, the number of available interfaces become very limited. In the closed product state, debug authentication allows the user to obtain device information through the discovery command.
    STM32_Programmer_CLI.exe -c port=SWD debugauth=2
    
  • User flash memory provisioning:
    The command used to provision the MCE_ExecuteAESCryptedCode_Boot binary in the user flash is shown below.
    STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -d %fw_location%\Projects\STM32H7S78-DK\Examples\MCE\MCE_ExecuteAESCryptedCode\EWARM\Boot\MCE_ExecuteAESCryptedCode_Boot\Exe\MCE_ExecuteAESCryptedCode_Boot.bin 0x8000000 -v
    
    The -v stands for --verify and ensures that the download is successfully executed. %fw_location% is the STM32Cube_FW_H7RS location.
  • External flash memory provisioning:
    The command used to provision the GPIO_IOToggle_Crypted binary in the external flash memory is shown below.
    STM32_Programmer_CLI.exe -c port=%com_port% br=921600 -elbl "C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\ExternalLoader\MX66UW1G45G_STM32H7S78-DK_XSPIM1-SFIx.stldr" -d %fw_location%\Projects\STM32H7S78-DK\Examples\GPIO\GPIO_IOToggle\EWARM\Appli\GPIO_IOToggle_Appli\Exe\GPIO_IOToggle_Crypted.bin 0x90000000 –verify
    
    %com_port% must be replaced with the connected COM port and %fw_location% is the STM32Cube_FW_H7RS location.
  • Option bytes:
    Below is the command line example used to set option bytes.
    STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -ob ECC_ON_SRAM=1
    
    This command checks the correct writing of the option byte. When the execution result is positive, the change is successfully completed.
    To ensure that the option byte is changed successfully, add -ob displ in the command line, or add a dedicated line to check all option byte changes. -ob displ prints all OB values.
  • OBKeys:
    The command line examples below are used to set OBKeys.
    STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -hardRst
    STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -sdp ./../DA/Binary/DA_Config.obk
    
    When calling the -sdp command, a positive result (OBKey Provisioned successfully) means the data were written correctly.

10. References