i.MX93 Key Import and Key Exchange Example#

This documentation covers the key import and key exchange operations for the i.MX93 EdgeLock Secure Enclave, specifically focusing on the combined key agreement and key derivation functionality used to establish secure key import capabilities.

1. Prerequisites#

  • SPSDK is needed with examples extension. pip install spsdk[examples] (Please refer to the installation documentation.)

  • This demo was tested with i.MX93 EVK board

  • Obtain an NXP_PROD_KA_PUB key

1.1 NXP Production Key#

The EdgeLock Secure Enclave provides a built-in production key for key agreement:

  • Key ID: 0x70000000 (NXP PROD MANUFACT KEY AGREEMENT)

  • Purpose: Enables consistent OEM_IMPORT_xxx keys across devices with same SRKH

  • Availability: Same key across all lifecycles

  • Public Key Export: Available via Public key export API (0x32)

This ensures that devices with the same Super Root Key Hash (SRKH) can use identical import keys, simplifying key management across device populations.

2 Key Exchange Operation#

2.1 Purpose#

The key exchange operation performs a combined key agreement and key derivation to create symmetric keys stored in the EdgeLock Secure Enclave key storage. This operation is primarily used to establish OEM Master Keys for secure key import operations.

2.2 Key Features#

  • Combined Operation: Performs both key agreement (ECDH) and key derivation (HKDF) in a single operation

  • Symmetric Key Creation: Only symmetric keys can be created through this operation

  • Secure Storage: Derived keys are stored in EdgeLock Secure Enclave key storage

  • OEM Signed Content: Input parameters are protected by OEM signed messages for integrity

2.3 Key Exchange Signed Message Configuration#

message:
  command:
    KEY_EXCHANGE_REQ:
      # Key storage configuration
      key_store_id: 0x454C4500
      
      # Algorithm selection
      key_exchange_algorithm: HKDF SHA256  # Options: HKDF SHA256, HKDF SHA384
      
      # Salt configuration for HKDF process
      salt_flags: 0                        # Bit 0: Salt source, Bit 1: ELE import salt
      
      # Derived key attributes
      derived_key_grp: 0                   # Group ID (0-99)
      derived_key_size_bits: 256           # Key size: 128/192/256
      derived_key_type: OEM_IMPORT_MK_SK   # Key type for import operations
      derived_key_lifetime: PERSISTENT     # VOLATILE/PERSISTENT/PERMANENT
      derived_key_usage:                   # Permission list
        - Derive
      derived_key_permitted_algorithm: HKDF SHA256
      derived_key_lifecycle: CURRENT       # Lifecycle restrictions
      derived_key_id: 0x1                  # Key identifier
      
      # ECDH configuration
      private_key_id: 0x70000000           # NXP PROD MANUFACT KEY AGREEMENT
      oem_private_key: oem_private_key.pem # OEM private key for ECDH
      nxp_prod_ka_pub: nxp.pub             # NXP production public key

2.4 OEM Master Key Generation#

The key exchange operation generates an OEM_IMPORT_MK_SK (OEM Import Master Secret Key) with specific requirements:

Required Attributes#

  • Type: OEM_IMPORT_MK_SK

  • Usage: Derive (Cache usage set by default)

  • Permitted Algorithm: HKDF SHA256 (0x08000109)

  • Size: 256 bits

  • Lifecycle: User-defined

  • Lifetime: User-defined (PERSISTENT recommended)

Derived Keys#

From the OEM_IMPORT_MK_SK, two additional keys are derived:

  1. OEM_IMPORT_CMAC_SK

    • Used to verify Key Import signed TLV buffers

    • Type: AES, Size: 256 bits

    • No key identifier (derived on-demand)

  2. OEM_IMPORT_WRAP_SK

    • Used to decrypt wrapped keys in Key Import operations

    • Type: AES, Size: 256 bits

    • No key identifier (derived on-demand)

YamlDiffWidget("inputs/key_exchange.diffc").html
nxpimage signed-msg get-template -f mx93 -o workspace/key_exchange.yaml --force -m KEY_EXCHANGE_REQ
Creating workspace/key_exchange.yaml template file.

Configuration Differences

2.5 Generation of signed message and key derivation#

The command generates the signed message for the key exchange. If the -w/–assets option is specified, also generates the assets - OEM_IMPORT_MK_SK key is derived.

nxpimage -v signed-msg export -c inputs/key_exchange.yaml
%! nxpimage -v signed-msg export -c inputs/key_exchange.yaml -w workspace/assets
 
nxpimage -v signed-msg export -c inputs/key_exchange.yaml -w workspace/assets
INFO:spsdk.image.ahab.signed_msg:Calculated input_peer_public_key_digest from OEM private key during config loading 3d164eb2e8c2c8566be458bdbdae6715f4484c8ffbacb14f248e20c3811def9b
INFO:spsdk.image.ahab.signed_msg:ECDH shared secret: 1ae9e13162f15e3b0baa0b7b959852e4d8a5c573cc0a4072e0d3a6666c728cbd
INFO:spsdk.image.ahab.signed_msg:Derived OEM_Import_MK_SK: c7e7436ed876b0176d775a658c3e9bcf59c940a41a2673b0552b7d7df504d194
INFO:spsdk.image.ahab.signed_msg:Derived OEM_Import_Wrap_SK: f2fa66b83ed82acbe4dddb5c60966cabad61cf3116b542115f10f06cf6aee825
INFO:spsdk.image.ahab.signed_msg:Derived OEM_Import_CMAC_SK: dc202a1160b4a5d11c088514e99e298b45aba12867543236fcd8774227f3e15c
INFO:spsdk.image.ahab.signed_msg:ECDH key derivation completed during configuration loading
INFO:spsdk.apps.nxpimage_apps.nxpimage_signed_msg:Created Signed message Image:
Name:      Signed Message Image
Starts:    0x0
Ends:      0x23f
Size:      Size: 576 B
Alignment: 8 B
Execution Start Address: Not defined
Pattern:zeros
Signed Message Image for mimx9352, Revision: latest

INFO:spsdk.apps.nxpimage_apps.nxpimage_signed_msg:Created Signed message Image memory map:

┌──0x0000_0000─ Signed Message Image ──┐
│             Size: 576 B              │
│  Signed Message Image for mimx9352,  │
│           Revision: latest           │
│            Pattern: zeros            │
┌──0x0000_0000─ Signed Message ──────┐│
││            Size: 576 B             ││
││Signed Message for KEY_EXCHANGE_REQ ││
│└──0x0000_023f───────────────────────┘│
└──0x0000_023f─────────────────────────┘

INFO:spsdk.apps.nxpimage_apps.nxpimage_signed_msg:SRK hash:cb2cc774b2dcec92c840eca0646b78f8d3661d3a43ed265a490a13aca75e190a
INFO:spsdk.image.ahab.signed_msg:Exported shared_secret to workspace/assets/shared_secret.bin
INFO:spsdk.image.ahab.signed_msg:Exported oem_import_mk_sk to workspace/assets/oem_import_mk_sk.bin
INFO:spsdk.image.ahab.signed_msg:Exported oem_import_wrap_sk to workspace/assets/oem_import_wrap_sk.bin
INFO:spsdk.image.ahab.signed_msg:Exported oem_import_cmac_sk to workspace/assets/oem_import_cmac_sk.bin
Performing post export
workspace/assets/shared_secret.bin
workspace/assets/oem_import_mk_sk.bin
workspace/assets/oem_import_wrap_sk.bin
workspace/assets/oem_import_cmac_sk.bin
Success. (Signed message: workspace/signed_msg_key_exchange_hkdf.bin created.)

3. Key Import Operation#

3.1 Purpose#

The key import operation allows secure importation of symmetric keys or private keys from asymmetric key pairs into the EdgeLock Secure Enclave key storage.

3.2 Key Features#

  • Encrypted Import: All imported keys must be encrypted (except specific cases like SRKH)

  • Multiple Key Types: Supports AES, HMAC, ECC, and other key types

  • Flexible Wrapping: Supports RFC3394 and AES-CBC wrapping algorithms

  • Signed TLV Format: Uses signed TLV (Type-Length-Value) format for integrity

3.3 TLV Blob generation#

Example of the configuration of TLV blob for importing the AES-256 key.

command:
  KEY_IMPORT:
    # Key identification
    key_id: 0                               # Key store ID
    
    # Permitted algorithm
    permitted_algorithm: "ALL CIPHER"       # Hash algorithm for verification
    
    # Key attributes
    key_type: AES                           # Key type and hash
    key_size_bits: 256                      # Key size: 128/192/224/256/384/512
    key_lifetime: ELE_KEY_IMPORT_PERSISTENT # Persistence level
    key_lifecycle: OPEN_CLOSED              # Lifecycle restrictions
    key_usage:                              # Permission list
      - Encrypt
      - Decrypt
      
    # Wrapping configuration
    oem_mk_sk_key_id: 1                     # OEM_IMPORT_MK_SK key ID
    key_wrapping_algorithm: RFC3394         # RFC3394 or AES_CBC
    signing_algorithm: CMAC                 # Signature algorithm
    
    # Key data (two options)
    # Option 1: Pre-wrapped key and signature
    # wrapped_key: "0x00000000"
    # signature: "0x00000000000000000000000000000000"
    
    # Option 2: Raw key with master key (automatic wrapping)
    import_key: aes256.bin                  # Raw key file
    oem_import_mk_sk_key: "0xc7e7436ed876b0176d775a658c3e9bcf59c940a41a2673b0552b7d7df504d194" # Taken from the key exchange operation
    
    # Optional SRKH for salt derivation
    srkh: "0x00000000000000000000000000000000"

3.4 Supported Key Types#

Key Type

Value

Supported Sizes (bits)

AES

0x2400

128, 192, 256

HMAC

0x1100

224, 256, 384, 512

Derived key

0x1200

256, 384

OEM_IMPORT_MK_SK

0x9200

128, 192, 256

ECC NIST

0x7112

128, 192, 256, 384, 521

3.5 Key Usage Permissions#

Permission

Value

Description

Cache

0x00000004

Cache in secure memory (default)

Encrypt

0x00000100

Encryption operations

Decrypt

0x00000200

Decryption operations

Sign message

0x00000400

Message signing (MAC/asymmetric)

Verify message

0x00000800

Message verification

Sign hash

0x00001000

Hash signing (asymmetric)

Verify hash

0x00002000

Hash verification

Derive

0x00004000

Key derivation operations

3.6 Export of TLV blob#

nxpimage -v signed-msg tlv export -c inputs/tlv_import_aes256.yaml
YamlDiffWidget("inputs/tlv_import_aes256.diffc").html
nxpimage signed-msg tlv get-template -f mx93 -o workspace/tlv_import_aes256.yaml --force
Success. (TLV template: workspace/tlv_import_aes256.yaml created.)

Configuration Differences

3.6.1 TLV blob - AES256#

%! nxpimage -v signed-msg tlv export -c inputs/tlv_import_aes256.yaml
nxpimage -v signed-msg tlv export -c inputs/tlv_import_aes256.yaml
INFO:spsdk.image.ahab.tlv:The Import key Signed message created with raw key and OEM_IMPORT_MK_SK key.
INFO:spsdk.image.ahab.tlv:Derived OEM_IMPORT_WRAP_SK: f2fa66b83ed82acbe4dddb5c60966cabad61cf3116b542115f10f06cf6aee825
INFO:spsdk.image.ahab.tlv:Derived OEM_IMPORT_CMAC_SK: dc202a1160b4a5d11c088514e99e298b45aba12867543236fcd8774227f3e15c
INFO:spsdk.apps.nxpimage_apps.nxpimage_signed_msg:TLV blob size: 141 bytes
INFO:spsdk.apps.nxpimage_apps.nxpimage_signed_msg:TLV details:
TLV
  Key ID value: 0x00000000, 0
  Key import algorithm value: ALL CIPHER
  Key usage value: ['Encrypt', 'Decrypt']
  Key type value: AES
  Key bit size value: 0x00000100, 256
  Key life time value: ELE_KEY_IMPORT_PERSISTENT
  Key life cycle value: OPEN_CLOSED
  OEM Import MK SK key ID value: 0x00000001, 1
  Key wrapping algorithm: RFC3394
  Initial vector value: 00000000000000000000000000000000
  Key signing algorithm: CMAC
  Import key wrapped data: 8551f75b2dd95752084cfbc196a8ae1102eab2e1821fbcaf70a9f5b4e7dc3a130441cc3272524bf0
  Signature: a63e4e71b1dae995c8a484a12e6f811b
Success. (TLV blob: inputs/tlv.bin created.)

3.6.2 TLV blob - ECC384#

YamlDiffWidget("inputs/tlv_import_ecc384.diffc").html
nxpimage signed-msg tlv get-template -f mx93 -o workspace/tlv_import_ecc384.yaml --force
Success. (TLV template: workspace/tlv_import_ecc384.yaml created.)

Configuration Differences

%! nxpimage -v signed-msg tlv export -c inputs/tlv_import_ecc384.yaml
nxpimage -v signed-msg tlv export -c inputs/tlv_import_ecc384.yaml
INFO:spsdk.image.ahab.tlv:The Import key Signed message created with raw key and OEM_IMPORT_MK_SK key.
INFO:spsdk.image.ahab.tlv:Derived OEM_IMPORT_WRAP_SK: f2fa66b83ed82acbe4dddb5c60966cabad61cf3116b542115f10f06cf6aee825
INFO:spsdk.image.ahab.tlv:Derived OEM_IMPORT_CMAC_SK: dc202a1160b4a5d11c088514e99e298b45aba12867543236fcd8774227f3e15c
INFO:spsdk.apps.nxpimage_apps.nxpimage_signed_msg:TLV blob size: 157 bytes
INFO:spsdk.apps.nxpimage_apps.nxpimage_signed_msg:TLV details:
TLV
  Key ID value: 0x00000000, 0
  Key import algorithm value: ECDSA SHA384
  Key usage value: ['Sign hash', 'Verify hash']
  Key type value: ECC NIST
  Key bit size value: 0x00000180, 384
  Key life time value: ELE_KEY_IMPORT_PERSISTENT
  Key life cycle value: OPEN_CLOSED
  OEM Import MK SK key ID value: 0x00000001, 1
  Key wrapping algorithm: RFC3394
  Initial vector value: 00000000000000000000000000000000
  Key signing algorithm: CMAC
  Import key wrapped data: 8b3fa3a1a659ae4c4b5a120cb5eebb2ae3fd33ecbd9b3e2cc7c3b4566848cc40aa33601469fa82750ef1acc9d37800f03c381e86ec560513
  Signature: e7d995f27ac05e7336a800a5924d38e0
Success. (TLV blob: inputs/tlv.bin created.)

3.6.3 TLV blob - ECC521#

YamlDiffWidget("inputs/tlv_import_ecc521.diffc").html
nxpimage signed-msg tlv get-template -f mx93 -o workspace/tlv_import_ecc521.yaml --force
Success. (TLV template: workspace/tlv_import_ecc521.yaml created.)

Configuration Differences

%! nxpimage -v signed-msg tlv export -c inputs/tlv_import_ecc521.yaml
nxpimage -v signed-msg tlv export -c inputs/tlv_import_ecc521.yaml
INFO:spsdk.image.ahab.tlv:The Import key Signed message created with raw key and OEM_IMPORT_MK_SK key.
INFO:spsdk.image.ahab.tlv:Derived OEM_IMPORT_WRAP_SK: f2fa66b83ed82acbe4dddb5c60966cabad61cf3116b542115f10f06cf6aee825
INFO:spsdk.image.ahab.tlv:Derived OEM_IMPORT_CMAC_SK: dc202a1160b4a5d11c088514e99e298b45aba12867543236fcd8774227f3e15c
INFO:spsdk.apps.nxpimage_apps.nxpimage_signed_msg:TLV blob size: 199 bytes
INFO:spsdk.apps.nxpimage_apps.nxpimage_signed_msg:TLV details:
TLV
  Key ID value: 0x00000000, 0
  Key import algorithm value: ECDSA SHA512
  Key usage value: ['Sign hash', 'Verify hash']
  Key type value: ECC NIST
  Key bit size value: 0x00000209, 521
  Key life time value: ELE_KEY_IMPORT_PERSISTENT
  Key life cycle value: OPEN_CLOSED
  OEM Import MK SK key ID value: 0x00000001, 1
  Key wrapping algorithm: AES_CBC
  Initial vector value: 00000000000000000000000000000000
  Key signing algorithm: CMAC
  Import key wrapped data: 917b068704098f0685083f3056a08b1a95d0f49cff49806103a04c7cad2a57859b1a16a74e82fb193db3a6aeb1726c6d9190c501c19a3bd4613406010b8a010b7a12435e56bec4a7df52e9fec126e6d3
  Signature: db088ca226029d74b52cb97b88f86d8b
Success. (TLV blob: inputs/tlv.bin created.)

3.6.3 TLV blob - RSA4096#

YamlDiffWidget("inputs/tlv_import_rsa4096.diffc").html
nxpimage signed-msg tlv get-template -f mx93 -o workspace/tlv_import_rsa4096.yaml --force
Success. (TLV template: workspace/tlv_import_rsa4096.yaml created.)

Configuration Differences

%! nxpimage -v signed-msg tlv export -c inputs/tlv_import_rsa4096.yaml
nxpimage -v signed-msg tlv export -c inputs/tlv_import_rsa4096.yaml
INFO:spsdk.image.ahab.tlv:The Import key Signed message created with raw key and OEM_IMPORT_MK_SK key.
INFO:spsdk.image.ahab.tlv:RSA key loaded: 4096 bits, modulus: 512 bytes, exponent: 512 bytes
INFO:spsdk.image.ahab.tlv:Derived OEM_IMPORT_WRAP_SK: f2fa66b83ed82acbe4dddb5c60966cabad61cf3116b542115f10f06cf6aee825
INFO:spsdk.image.ahab.tlv:Derived OEM_IMPORT_CMAC_SK: dc202a1160b4a5d11c088514e99e298b45aba12867543236fcd8774227f3e15c
INFO:spsdk.apps.nxpimage_apps.nxpimage_signed_msg:TLV blob size: 1135 bytes
INFO:spsdk.apps.nxpimage_apps.nxpimage_signed_msg:TLV details:
TLV
  Key ID value: 0x00000000, 0
  Key import algorithm value: RSA PKCS1 ALL
  Key usage value: ['Sign hash', 'Verify hash']
  Key type value: RSA
  Key bit size value: 0x00001000, 4096
  Key life time value: ELE_KEY_IMPORT_PERSISTENT
  Key life cycle value: OPEN_CLOSED
  OEM Import MK SK key ID value: 0x00000001, 1
  Key wrapping algorithm: RFC3394
  Initial vector value: 00000000000000000000000000000000
  Key signing algorithm: CMAC
  Import key wrapped data: 897ef5802e89080fb176798992bbe954b2ce3e6b31afe2c6d151e171487b76cfca004a70f83dbaf3b7d7a7dc4b1187bc57c8da4d9d6a0663cad30f1156806fc8973cf391aa4df68450392292539a782c400f33f03c7703e709816752f71cd8db836be26cf7e5814ee3d0e3bb9ee67b633630cc34497c395f510d1dd357975e9d55add77475b1ac52031e6db64be8decf234dfe05fbe439d1e0a8c8eea8d66b6c9fc746d7640860384692d913dfecafc1cefc79d3ce4f2b932724891ff0ad01e46667b44a5259901fedcda603318ea989e052e6b9a8fc60af1303bae83d36c12b5e538a9f561d34e441e8cfd7e6533222a1f79a57831d6ac00c465880a9b7e01c9a05e2f0b0f4651a5b26b1f889ba5964ee52495d3746a458a7cd83ba2bff43633f8e9d3eb1f48d8b266176f68f933f02cffde1bd7dd4c1636b133bc1d2ae48b9d3dacef71512a902960b44abd53bdee6b5e6fdb3b125be55a24d278c9bf351e57c258fd5725a91a09a6b7b616eb8c9935af44c1f78d70e6fce8cc5f8f808cb920bb1c8860d108bc5887cdcbe14e84355ad941c5cb5b1e2ec706c7a08292a03a733cb7975518e8bc023728fbf0ebf827728550a20c216dde511b362d579f6f515bfbc16f912efcffed2e076ecb72f503a584a702823bc8218c38305bf88ca8d015dd30219471dd0bad0c629e712dac5bf5ec72773be2855b7836b7dd49420bb6fe34b0ec977639ac64ec70ed190e6e45f6b4ffc55bf734e6daddf8acd6eb3fe36a6b3bf46d9f5c6ba34226e4886decc9674e10595e331ff625373eb2eac16cb19fa87ed1e99f9132bf63c2af243c1e530568004e6665e4c251dadb04cef6d9ab9e3b3535c59a628a7ec3863c372e6d61728e4a671b8b5cd8bb0072e10c615b908207afb0d3f9ee9d8f7061bbb932c9cf6279966a553e3b38868eb2ac045fe3fba5ff2861c4c9f1b02ed4293475a89a3e291ad95bd029c9a47a9afc228be51ba60159a7773621e3e1bf9f37a90554e5d74ee2b467d74e172ff46c412b837e784fa361bb6389a1737e8ddae1296b0e585ba119d4eacc8cdf9a9747366b34f1ab5136597216478897b777ae3b94ed2e3dcf1180f6fa3cb84e437d26c8f477a6978d3d98f1bff290f9b465a6d6bfe2746fff21a658671ec50705ea140ea64399adcac4118fb1fe1fc8f800764ca095396cdccd90b592a533a82039bb817451cfa382c27b23bf9a1b0bb293f4b91cad702372678229d2d5404488efbd544ed28cfce3aa1fce533c6d2924512334d3c436d04081364949f2c0f32b36466c534eb764435a5724bfe5173e6dee905e2f646faa36cabc3ebf79fefbeaeaa513dc67b032e76d2de1bd78aead20e24745ffc3d9ac7a3e248a14577fef24cd98ccca4cad1334380d577d7d6f8e5d80567131f18eb1c9fff51c62743c2eb2ad070fa6a560cba26ac0e6ca152cb2db3
  Signature: 6458344257179e589d2acb7e102743b9
Success. (TLV blob: inputs/tlv.bin created.)