i.MX 95 Encrypted Boot#
This Jupyter notebook demonstrates how to create and deploy encrypted, signed AHAB (Advanced High-Assurance Boot) containers for i.MX95 devices with U-Boot bootloader. This example showcases the complete secure boot chain with both authentication and confidentiality protection.
Key Features#
Individual Image Encryption: Each image within the container is encrypted separately using the same Data Encryption Key (DEK)
AES-CBC Encryption: Supports AES key sizes of 128, 192, and 256 bits using CBC mode
Unique IV Generation: Each image uses a unique Initialization Vector (IV) derived from the SHA256 hash of the plaintext image (lower 128 bits used as IV, full 256 bits for integrity verification)
In-Place Decryption: Images are decrypted directly in memory during boot process
1. Prerequisites#
SPSDK is needed with examples extension.
pip install spsdk[examples](Please refer to the installation documentation.)This demo was tested with i.MX 95 EVK board with LPDDR5 memory and B0 chip revision.
1.1 Images preparation#
To create resulting binary containing AHAB containers, we need to prepare the binaries
Obtain all the necessary binaries and put them into inputs directory
1.2 U-Boot#
In order to use the nxpele app, U-Boot must be built with AHAB support. CONFIG_AHAB_BOOT=y If you want to use the nxpele over fastboot, also multiplexing of console output to fastboot must be enabled by setting CONFIG_CONSOLE_MUX=y.
1.3 Requirements#
Primary image container set:
ELE firmware
LPDDR4 or LPDDR5 firmware files with OEI firmware
CM33 OEI TCM
CM33 System manager image
U-Boot SPL
[Optional] M7 application image
Four ECC keys (in this example we use ECC521) - might be created with nxpcrypto tool
Four ML-DSA keys (in this example we use ML-DSA65) - might be created with nxpcrypto tool
DEK key for image encryption (in this example we use 128 bits key size)
Secondary image container set:
ARM Trusted Firmware (bl31.bin binary)
U-Boot (built with AHAB support)
TEE binary
Four ECC keys (Same as in the primary container)
Four ML-DSA keys (Same as in the primary container)
DEK key for image encryption (Same as in the primary container)
2. Encryption blob#
To encrypt the bootloader we need to prepare DEK key with the desired length and use nxpele generate-keyblob DEK command to generate decryption blob (DEK keyblob), which is device unique. To use this command U-Boot needs to be running on the target device.
Note: See
nxpele generate-keyblob DEK --helpfor more details about command parameters.
DEK_KEY = "../../_data/keys/dek_key.txt"
DEK_KEYBLOB = "outputs/dek_keyblob.bin"
%! nxpele --family mimx9596 generate-keyblob DEK --algorithm AES_CBC --key-id 2 --key $DEK_KEY --key-size 128 --output $DEK_KEYBLOB
nxpele --family mimx9596 generate-keyblob DEK --algorithm AES_CBC --key-id 2 --key ../../_data/keys/dek_key.txt --key-size 128 --output outputs/dek_keyblob.bin
ELE generate DEK key blob ends successfully:
00480081011003005b8fd715771556d45b18ccd024a6bb2d0940d2252a40b41f48d02700c437a4ac0e1ced00974a1a8dd4167a1a4a3b3b5f2196424dbba09d62707de0c55c32ae83
3. AHAB Image#
3.1 AHAB Template#
We can generate the template using the nxpimage ahab get-template command. The template is a YAML file that contains the AHAB header and the AHAB container. The AHAB header contains the information about the image, such as the version, the number of containers, and the signature.
The following command generates the template:
nxpimage ahab get-template -f mimx9596 -o ahab_template.yaml
3.2 Exporting of the AHAB image#
The AHAB image can be exported using the nxpimage ahab export command. The command will create the AHAB image from the template. The following command creates the AHAB image:
nxpimage ahab export -c ahab_template.yaml
3.4 Primary image container set#
Primary image container set consists of the images mentioned before:
3.5 Secondary image container set#
Secondary image container set consists of the images mentioned before:
3.6 Exporting of full AHAB image (container set)#
U-Boot image consists from two image container sets. The first one contains ELE firmware, DDR firmware with OEI, system manager and U-Boot SPL. This image is loaded using the SDPS protocol. Once the U-Boot SPL is loaded to OCRAM the fastboot is opened and the second container is loaded using the fastboot protocol.
If the image is intended for loading using the UUU, the memory type should be set to serial_downloader. However the type of each individual AHAB should be set to standard, because it will be stored in flash memory.
nxpimage -v bootable-image export -c u-boot-flash_template.yaml -o flash.bin
YamlDiffWidget("inputs/mx95_encrypted_ahab_bimg.diffc").html
nxpimage bootable-image get-templates -f mimx9596 -o workspace --force
Creating workspace/bootimg_mimx9596_serial_downloader.yaml template file.
Creating workspace/bootimg_mimx9596_flexspi_nor.yaml template file.
Creating workspace/bootimg_mimx9596_emmc.yaml template file.
Creating workspace/bootimg_mimx9596_sd.yaml template file.
Creating workspace/bootimg_mimx9596_recovery_spi.yaml template file.
U_BOOT_FLASH_BOOT_CFG = "inputs/bootimg_encrypted_mx95_serial_downloader.yaml"
U_BOOT_FLASH_BOOT = "outputs/flash.bin"
VERBOSITY = "-v"
# EXPORT FULL U-BOOT IMAGE
%! nxpimage $VERBOSITY bootable-image export --config $U_BOOT_FLASH_BOOT_CFG --output $U_BOOT_FLASH_BOOT
nxpimage -v bootable-image export --config inputs/bootimg_encrypted_mx95_serial_downloader.yaml --output outputs/flash.bin
INFO:spsdk.apps.nxpimage_apps.nxpimage_bimg:Created Bootable Image:
Name: Bootable Image for mimx9596, Revision: latest
Starts: 0x0
Ends: 0x291fff
Size: Size: 2.6 MiB; 2,695,168 B
Alignment: 1 B
Execution Start Address: Not defined
Pattern:zeros
Memory type: MemoryType.SERIAL_DOWNLOADER
INFO:spsdk.apps.nxpimage_apps.nxpimage_bimg:Created Bootable Image memory map:
+==0x0000_0000= Bootable Image for mimx9596, Revision: latest ===+
| Size: 2.6 MiB; 2,695,168 B |
| Memory type: MemoryType.SERIAL_DOWNLOADER |
| Pattern: zeros |
|+==0x0000_0000= primary_image_container_set ===================+|
|| Size: 894.0 kiB; 915,456 B ||
|| AHAB Image for mimx9596, Revision: latest ||
|| Pattern: zeros ||
||+==0x0000_0000= AHAB Containers =============================+||
||| Size: 48.0 kiB; 49,152 B |||
||| AHAB Containers block |||
||| Pattern: zeros |||
|||+==0x0000_0000= AHAB Container 0 ==========================+|||
|||| Size: 8.0 kiB; 8,227 B ||||
|||| AHAB Container for nxp_SWver:0 ||||
|||+==0x0000_2022=============================================+|||
||| Gap: 8.0 kiB |||
|||+==0x0000_4000= AHAB Container 1 ==========================+|||
|||| Size: 832 B ||||
|||| AHAB Container for nxp_SWver:0 ||||
|||+==0x0000_433f=============================================+|||
||| Gap: 15.2 kiB |||
|||+==0x0000_8000= AHAB Container 2 ==========================+|||
|||| Size: 7.0 kiB; 7,181 B ||||
|||| AHAB Container for oem_SWver:0 ||||
|||+==0x0000_9c0c=============================================+|||
||+==0x0000_bfff===============================================+||
||+==0x0000_c000= Container 0 AHAB Data Image 0 ===============+||
||| Size: 44.6 kiB; 45,648 B |||
||| AHAB encrypted data block for ele core and ele Image Type. |||
||+==0x0001_724f===============================================+||
|| Gap: 3.4 kiB ||
||+==0x0001_8000= Container 1 AHAB Data Image 0 ===============+||
||| Size: 63.8 kiB; 65,280 B |||
||| AHAB encrypted data block for v2x-1 core and v2x_primary |||
||| Image Type. |||
||+==0x0002_7eff===============================================+||
|| Gap: 256 B ||
||+==0x0002_8000= Container 1 AHAB Data Image 1 ===============+||
||| Size: 28.0 kiB; 28,672 B |||
||| AHAB encrypted data block for v2x-2 core and v2x_secondary |||
||| Image Type. |||
||+==0x0002_efff===============================================+||
||+==0x0002_f000= OEI DDR =====================================+||
||| Size: 316.0 kiB; 323,584 B |||
|||AHAB encrypted data block for cortex-m33 core and oei Image |||
||| Type. |||
||+==0x0007_dfff===============================================+||
||+==0x0007_e000= OEI DDR =====================================+||
||| Size: 0 B |||
||| AHAB data block for dummy core and oei_ddr Image Type. |||
||+==0x0007_dfff===============================================+||
|| Gap: 64.0 kiB ||
||+==0x0008_e000= OEI TCM =====================================+||
||| Size: 5.0 kiB; 5,120 B |||
|||AHAB encrypted data block for cortex-m33 core and oei Image |||
||| Type. |||
||+==0x0008_f3ff===============================================+||
||+==0x0008_f400= System manager ==============================+||
||| Size: 163.0 kiB; 166,912 B |||
|||AHAB encrypted data block for cortex-m33 core and executable|||
||| Image Type. |||
||+==0x000b_7fff===============================================+||
||+==0x000b_8000= Additional Cortex M7 application ============+||
||| Size: 13.0 kiB; 13,312 B |||
||| AHAB encrypted data block for cortex-m7-1 core and |||
||| executable Image Type. |||
||+==0x000b_b3ff===============================================+||
||+==0x000b_b400= U-Boot SPL ==================================+||
||| Size: 145.0 kiB; 148,480 B |||
|||AHAB encrypted data block for cortex-a55 core and executable|||
||| Image Type. |||
||+==0x000d_f7ff===============================================+||
||+==0x000d_f800= V2X core Dummy record =======================+||
||| Size: 0 B |||
|||AHAB encrypted data block for cortex-m33 core and v2x_dummy |||
||| Image Type. |||
||+==0x000d_f7ff===============================================+||
|+==0x000d_f7ff=================================================+|
|+==0x000d_f800= secondary_image_container_set =================+|
|| Size: 1.7 MiB; 1,779,712 B ||
|| AHAB Image for mimx9596, Revision: latest ||
|| Pattern: zeros ||
||+==0x000d_f800= AHAB Containers =============================+||
||| Size: 48.0 kiB; 49,152 B |||
||| AHAB Containers block |||
||| Pattern: zeros |||
|||+==0x000d_f800= AHAB Container 0 ==========================+|||
|||| Size: 6.5 kiB; 6,669 B ||||
|||| AHAB Container for oem_SWver:0 ||||
|||+==0x000e_120c=============================================+|||
||+==0x000e_b7ff===============================================+||
||+==0x000e_b800= ATF - ARM Trusted Firmware ==================+||
||| Size: 38.0 kiB; 38,912 B |||
|||AHAB encrypted data block for cortex-a55 core and executable|||
||| Image Type. |||
||+==0x000f_4fff===============================================+||
||+==0x000f_5000= U-Boot Firmware =============================+||
||| Size: 1.0 MiB; 1,097,728 B |||
|||AHAB encrypted data block for cortex-a55 core and executable|||
||| Image Type. |||
||+==0x0020_0fff===============================================+||
||+==0x0020_1000= U-Boot TEE - Trusted Execution Environment ==+||
||| Size: 580.0 kiB; 593,920 B |||
|||AHAB encrypted data block for cortex-a55 core and executable|||
||| Image Type. |||
||+==0x0029_1fff===============================================+||
|+==0x0029_1fff=================================================+|
+==0x0029_1fff===================================================+
Success. (Bootable Image: outputs/flash.bin created)
INFO:spsdk.image.ahab.ahab_container:Generated file containing SRK hash: outputs/post_export/ahab_oem2_srk0_hash.txt
INFO:spsdk.image.ahab.ahab_container:
Fuses info:
--== Grouped register name: SRKH ==--
OTP ID: 128, Value: 0x241CF233
OTP ID: 129, Value: 0x598B9EEF
OTP ID: 130, Value: 0xDB555149
OTP ID: 131, Value: 0x11CA4D90
OTP ID: 132, Value: 0xADD4F20D
OTP ID: 133, Value: 0xA595873D
OTP ID: 134, Value: 0xD6BF1611
OTP ID: 135, Value: 0xA9F8BAA6
OTP ID: 136, Value: 0x6E3413DC
OTP ID: 137, Value: 0x1923841E
OTP ID: 138, Value: 0x10D0A7C0
OTP ID: 139, Value: 0xDBAEC7B4
OTP ID: 140, Value: 0xCA74C2A2
OTP ID: 141, Value: 0x358BC459
OTP ID: 142, Value: 0xB2997934
OTP ID: 143, Value: 0xF1CA7902
INFO:spsdk.image.ahab.ahab_container:Generated script for writing fuses for container 2: outputs/post_export/ahab_oem2_srk0_hash_nxpele.bcf
INFO:spsdk.image.ahab.ahab_container:Generated file containing SRK hash: outputs/post_export/ahab_oem2_srk1_hash.txt
INFO:spsdk.image.ahab.ahab_container:
Fuses info:
--== Grouped register name: PQC_SRKH ==--
OTP ID: 448, Value: 0xA4C25CF9
OTP ID: 449, Value: 0x3A897E6B
OTP ID: 450, Value: 0x65B02428
OTP ID: 451, Value: 0x97674462
OTP ID: 452, Value: 0xBF41C13A
OTP ID: 453, Value: 0x86D9F03A
OTP ID: 454, Value: 0x2EF246AE
OTP ID: 455, Value: 0x7A347919
OTP ID: 456, Value: 0x555B5447
OTP ID: 457, Value: 0xE801DF23
OTP ID: 458, Value: 0x7C278F6D
OTP ID: 459, Value: 0xC8FBEA31
OTP ID: 460, Value: 0x76CA9A8E
OTP ID: 461, Value: 0x3CE47C57
OTP ID: 462, Value: 0x640A8572
OTP ID: 463, Value: 0x09ACB465
INFO:spsdk.image.ahab.ahab_container:Generated script for writing fuses for container 2: outputs/post_export/ahab_oem2_srk1_hash_nxpele.bcf
INFO:spsdk.image.ahab.ahab_container:Generated file containing SRK hash: outputs/post_export/ahab_oem0_srk0_hash.txt
INFO:spsdk.image.ahab.ahab_container:
Fuses info:
--== Grouped register name: SRKH ==--
OTP ID: 128, Value: 0x241CF233
OTP ID: 129, Value: 0x598B9EEF
OTP ID: 130, Value: 0xDB555149
OTP ID: 131, Value: 0x11CA4D90
OTP ID: 132, Value: 0xADD4F20D
OTP ID: 133, Value: 0xA595873D
OTP ID: 134, Value: 0xD6BF1611
OTP ID: 135, Value: 0xA9F8BAA6
OTP ID: 136, Value: 0x6E3413DC
OTP ID: 137, Value: 0x1923841E
OTP ID: 138, Value: 0x10D0A7C0
OTP ID: 139, Value: 0xDBAEC7B4
OTP ID: 140, Value: 0xCA74C2A2
OTP ID: 141, Value: 0x358BC459
OTP ID: 142, Value: 0xB2997934
OTP ID: 143, Value: 0xF1CA7902
INFO:spsdk.image.ahab.ahab_container:Generated script for writing fuses for container 0: outputs/post_export/ahab_oem0_srk0_hash_nxpele.bcf
INFO:spsdk.image.ahab.ahab_container:Generated file containing SRK hash: outputs/post_export/ahab_oem0_srk1_hash.txt
INFO:spsdk.image.ahab.ahab_container:
Fuses info:
--== Grouped register name: PQC_SRKH ==--
OTP ID: 448, Value: 0xA4C25CF9
OTP ID: 449, Value: 0x3A897E6B
OTP ID: 450, Value: 0x65B02428
OTP ID: 451, Value: 0x97674462
OTP ID: 452, Value: 0xBF41C13A
OTP ID: 453, Value: 0x86D9F03A
OTP ID: 454, Value: 0x2EF246AE
OTP ID: 455, Value: 0x7A347919
OTP ID: 456, Value: 0x555B5447
OTP ID: 457, Value: 0xE801DF23
OTP ID: 458, Value: 0x7C278F6D
OTP ID: 459, Value: 0xC8FBEA31
OTP ID: 460, Value: 0x76CA9A8E
OTP ID: 461, Value: 0x3CE47C57
OTP ID: 462, Value: 0x640A8572
OTP ID: 463, Value: 0x09ACB465
INFO:spsdk.image.ahab.ahab_container:Generated script for writing fuses for container 0: outputs/post_export/ahab_oem0_srk1_hash_nxpele.bcf
Performing post export
outputs/post_export/ahab_oem2_srk0_hash.txt
outputs/post_export/ahab_oem2_srk0_hash_nxpele.bcf
outputs/post_export/ahab_oem2_srk1_hash.txt
outputs/post_export/ahab_oem2_srk1_hash_nxpele.bcf
outputs/post_export/ahab_oem0_srk0_hash.txt
outputs/post_export/ahab_oem0_srk0_hash_nxpele.bcf
outputs/post_export/ahab_oem0_srk1_hash.txt
outputs/post_export/ahab_oem0_srk1_hash_nxpele.bcf
4. Download image#
4.1 Download AHAB image#
Set the boot mode to Cortex-M Serial Downloader (1001 on EVK boot switch) and download the files using the UUU tool
%! nxpuuu $VERBOSITY write --family mimx9596 --boot-device emmc $U_BOOT_FLASH_BOOT
nxpuuu -v write --family mimx9596 --boot-device emmc outputs/flash.bin
SDPS: boot -f outputs/flash.bin
SDPV: write -f outputs/flash.bin -skipspl
SDPV: jump
Success
5. Write fuses#
NOTE: For more information about fuses, refer to i.MX 95 signed AHAB with U-BOOT Jupyter Notebook.
6. Boot and test#
Now change the boot mode to Cortex-M eMMC (1010 on EVK boot switch) and reset the board. Find the serial port that belongs to U-Boot console and interrupt the boot. When the console is switched to U-Boot menu, we can use the nxpele tool to communicate with the ELE.
%! nxpele --family mimx9596 --port COM266 --device uboot_serial get-info
nxpele --family mimx9596 --port COM266 --device uboot_serial get-info
ELE get info ends successfully:
Command: 0xda
Version: 3
Length: 256
SoC ID: MX95 - 0x9500
SoC version: B000
Life Cycle: OEM_CLSD - 0x0040
SSSM state: 4
Attest API version: 0
UUID: c9d88ddf5ace444da168dd2a520630e1
SHA256 ROM PATCH: 72d02b666a524aca0a3162accb4c8de7af33083fc2faefb249d87c7de1437c81
SHA256 FW: 9fdfd92f6f1a6e222362b4a9b5110a964df304a66f91e343d25c3be6a88b75c9
Advanced information:
OEM SRKH: 41a3ab5e956ff6649e843f2686ada51840415d2fa2b6508960098d5bf6f41f27eafeff21a88f3c4b2ccf08895c1440f4b2675fb0bfe5675333b5fcbb3fba9a45
CSAL state: EdgeLock secure enclave random context initialization succeed - 0x02
TRNG state: TRNG entropy is valid and ready to be read - 0x03
OEM PQC SRKH: 643dcc626197897115d7cce1ec079c479399af59cd46b9b45b6578fabe86d20e788683151239d8128c4f8ccc871ea86c9d8ee58b6e03e9bf8fdbde6b21b5bd09