In a previous article, we demonstrated how to import an RFC3394-wrapped key blob into ELS by manually performing the following operations:
NXP_DIE_KEK_SK using CKDF-SP800-108mcuxClEls_KeyImport_Async()While this approach provides full visibility into the underlying ELS operations, applications using the PSA Crypto API can achieve the same result with significantly less code.
This article demonstrates how to use psa_import_key() together with PSA_KEY_LOCATION_S50_RFC3394_STORAGE to import a wrapped key blob stored in OTP. The PSA Oracle driver transparently handles the secure key loading sequence, including KEK derivation, key unwrapping, ELS slot management, and cleanup.
Required Headers:
#include "psa/crypto.h"
#include "mcuxClPsaDriver_Oracle_Interface_key_locations.h"
#include "fsl_romapi_otp.h"
otp_fuse_read(starting_fuse_index + i, &fuse_word);
These words are assembled into a contiguous buffer:
blob_data[i * 4 + 0] = (fuse_word >> 0) & 0xFF;
blob_data[i * 4 + 1] = (fuse_word >> 8) & 0xFF;
blob_data[i * 4 + 2] = (fuse_word >> 16) & 0xFF;
blob_data[i * 4 + 3] = (fuse_word >> 24) & 0xFF;
The resulting buffer contains the RFC3394 wrapped key.
Before importing the blob, PSA key attributes must describe how the key should be managed.
The most important configuration is the key location:
psa_set_key_lifetime(
&attributes,
PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
PSA_KEY_PERSISTENCE_VOLATILE,
PSA_KEY_LOCATION_S50_RFC3394_STORAGE));
The PSA_KEY_LOCATION_S50_RFC3394_STORAGE location informs the Oracle driver that:
NXP_DIE_KEK_SK must be derived automatically during key loading.In this example we used an AES 128-bit key. The key type and size must match the wrapped key:
psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
psa_set_key_bits(&attributes, 128);
Usage permissions are then assigned:
psa_set_key_usage_flags(
&attributes,
PSA_KEY_USAGE_ENCRYPT |
PSA_KEY_USAGE_DECRYPT);
Finally, specify the algorithm:
psa_set_key_algorithm(
&attributes,
PSA_ALG_ECB_NO_PADDING);
The blob is imported using a single PSA API call:
psa_import_key(
&attributes,
blob_data,
blob_length,
&key_handle);
For developers familiar with the low-level ELS implementation, this single call effectively replaces:
derive_nxp_die_kek_sk()
import_wrapped_key_blob()
delete_key_from_slot()
At this point, PSA stores the wrapped blob and returns a key handle:
psa_key_id_t key_handle;
The returned handle is subsequently used for cryptographic operations.
At this point, the wrapped key blob has been successfully imported into the target ELS key slot, and the temporary NXP_DIE_KEK_SK has been removed. The imported key is now available for use by ELS-protected cryptographic operations without exposing the underlying key material to application software.
The next step is to validate the imported key by performing the operation it was provisioned for.
For this example, we used AES-ECB encryption:
psa_cipher_encrypt(
key_handle,
PSA_ALG_ECB_NO_PADDING,
plaintext,
sizeof(plaintext),
ciphertext,
sizeof(ciphertext),
&ciphertext_length);
Once the key is no longer required, destroy it using:
psa_destroy_key(key_handle);
This releases the PSA key object and allows the Oracle driver to clean up any associated secure resources.
Unlike the low-level ELS implementation, the application does not need to explicitly manage ELS keyslots.
| Direct ELS API | PSA Crypto API |
|---|---|
| Derive KEK manually | Automatic |
| Import blob manually | Automatic |
| Manage keyslots | Managed by Oracle |
| Delete temporary KEK | Automatic |
| Greater control | Simpler application code |
| Higher implementation effort | Faster integration |
Both approaches ultimately leverage the same secure hardware mechanisms within RW612. The PSA approach simply abstracts the underlying ELS operations behind a standardized cryptographic interface.