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.
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)
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
- Wiki articles:
- STM32CubeProgrammer software description (UM2237)
- STM32H7Rx/7Sx Arm®-based 32-bit MCUs reference manual (RM0477)
3. Application binary generation
- Open the GPIO_IOToggle example.
- Go to Options -> Output Converter and change the format to Raw binary, then click on OK.
- 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: - 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:
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.
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.
For more information about the MCE implementation of stream cipher, refer to the dedicated chapter in the product reference manual.[1]
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:
- Open the MCE_ExecuteAESCryptedCode_Boot example.
- 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 themain.c
file:
- In the previous step, the application was encrypted with a stream cipher. Update the MCE configuration to stream cipher mode in the
main()
function:
- 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] - Generate the .bin file:
- Go to Options -> Options -> Output Converter and change the format to Raw binary.
- Click on OK.
- 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
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.
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.
This step must be done in the open product state. The product state can only be written withSTM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -psrss 0x17
-psrss
(product state RSS change) and this is handled byRSSLIB_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 andGPIO_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
- Remove the write protection through the FLASH_WRPSRP programming register. Address: 0x5200221C, mask: 0x000000FF, value: 0xFF, bit shift: 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
- Remove the protections:
- Step 4: change PRODUCT_STATE to closed.
The commandSTM32_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
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.TheSTM32_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
-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.This command checks the correct writing of the option byte. When the execution result is positive, the change is successfully completed.STM32_Programmer_CLI.exe -c port=SWD speed=fast ap=1 mode=Hotplug -ob ECC_ON_SRAM=1
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.When calling theSTM32_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
-sdp
command, a positive result (OBKey Provisioned successfully) means the data were written correctly.
10. References