Migration Guide#

System Requirements and Document#

  1. Simplicity Studio 5

  2. GSDK v3.1.1 (Mbed TLS v2.24.0) or later

  3. The latest SE Firmware image and release note can be found in the Windows folder below.

    • For GSDK v3.1.x and v3.2.x: C:\SiliconLabs\SimplicityStudio\v5\developer\sdks\gecko_sdk_suite\<GSDK VERSION\>\util\se_release\public

    • For GSDK v4.0.0 and higher: C:\Users\<PC USER NAME\>\SimplicityStudio\SDKs\gecko_sdk\util\se_release\public

  4. PSA Crypto API (aka PSA Cryptography API) document: ARM

Mbed TLS Versus PSA Crypto API#

Item Mbed TLS PSA Crypto API

Key input

APIs take key input directly.

• APIs do not take key input directly.
• Key (identifier) needs to be created or imported before use.
• APIs take an identifier if a key is required.

Symmetric cryptographic operation

Individual API (one-shot and streaming) for algorithm-specific functions.

• APIs are grouped by algorithm category for one-shot and streaming modes.
• The exact algorithm is a parameter (psa_algorithm_t) to the function, not an individual API.

Except for AEAD (encrypt and decrypt), a one-shot function is not in a pair.

Single-part (one-shot) functions are in a pair. For example, compute and verify, or encrypt and decrypt.

Initialization and free a context are required.

Initialization and abort an operation are only required in multi-part (streaming) operations.

Error code

APIs always return an integer.

APIs always return psa_status_t.

Migration#

In Key Handling, Symmetric Cryptographic Operation, Asymmetric Cryptographic Operation the following items will be considered when migrating from Mbed TLS to PSA Crypto.

  1. The algorithms that can be used in a cryptographic operation.

  2. The key attributes type and usage flags for specific algorithms in the PSA Crypto.

  3. Security Software Components.

  4. The functions (APIs) for the Mbed TLS and PSA Crypto. For each type of symmetric cryptographic operation, the functions include:

    • A pair of single-part (one-shot) functions

    • A series of functions that implement multi-part (streaming) operations

  5. Quick Reference Examples. These examples do not have error checking, but the user should always check the return code (psa_status_t = PSA_SUCCESS or PSA_ERROR_XXX) from PSA Crypto to determine whether to use the output parameters in the application.

Platform Examples#

Simplicity Studio 5 includes the PSA Crypto platform examples to evaluate the performance on key handling, symmetric and asymmetric cryptographic operations, and X.509 certificate.

  • Refer to the corresponding readme file for details about each PSA Crypto platform example. This file also includes the procedures to create the project and run the example.

  • Unless specified in the example, the PSA Crypto platform examples will use the software fallback feature in Mbed TLS if the cryptography hardware accelerator of the selected device does not support the corresponding ECC key or algorithm.

The figures in the following sections are based on GSDK v4.1.0. These figures may be different on other versions of the GSDK.

Security Software Components#

The slcp file for each PSA Crypto platform example defines the software components installed in the project. The following figure shows the installed security software components (under the Platform → Security category) in the PSA Crypto ECDH example (psa_crypto_ecdh.slcp) on an HSE-SVH device.

Installed Security Software ComponentsInstalled Security Software Components

The Simplicity IDE uses the installed security software components to automatically generate the configuration files for Mbed TLS (mbedtls_config_autogen.h) and PSA Crypto (psa_crypto_config_autogen.h) in the autogen folder when creating the project.

Mbed TLS and PSA Crypto Configuration FilesMbed TLS and PSA Crypto Configuration Files

The user can browse the available security software components (under the Platform → Security category) on the target MCU or Wireless SoC if the [Installed Components] checkbox is unchecked.

Available Security Software Components on the Target DeviceAvailable Security Software Components on the Target Device

The Mbed TLS and PSA Crypto configuration files automatically regenerates when the user installs or uninstalls a security software component in the project.

Install a Security Software ComponentInstall a Security Software Component

Uninstall a Security Software ComponentUninstall a Security Software Component

For a new project (like empty.slcp), the required security software components will be automatically added to the project after installing any cryptographic operation in PSA Crypto (like GCM) from the user. The SE Manager component is only for the HSE devices.

Security Software Components for PSA CryptSecurity Software Components for PSA Crypt

If users are about to use the PSA Crypto for persistent key storage (either plain or wrapped) in their application, make sure to add the PSA Persistent Storage Support (ITS) component to the project.

Security Software Component for Persistent Key StorageSecurity Software Component for Persistent Key Storage

PSA Crypto Configuration#

Click Configuration in Installed Components. Click [Configure] to open the Configuration Wizard in Context Menu.

image19image19

Enter the desired values in PSA User Maximum Open Keys Count (SL_PSA_KEY_USER_SLOT_COUNT) and PSA Maximum User Persistent Keys Count (SL_PSA_ITS_USER_MAX_FILES) to replace the default values. Click [X] to exit.

The default value of PSA User Maximum Open Keys Count is equal to 0 if the project installed any Wireless Stack before.

image20image20

The PSA Crypto configuration file (psa_crypto_config_autogen.h) in the autogen folder Figure Mbed TLS and PSA Crypto Configuration Files includes the definitions for PSA key slot count and maximum PSA ITS files.

#define MBEDTLS_PSA_KEY_SLOT_COUNT (2 + 1 + SL_PSA_KEY_USER_SLOT_COUNT)
#define SL_PSA_ITS_MAX_FILES (1 + SL_PSA_ITS_USER_MAX_FILES)

The first digit in MBEDTLS_PSA_KEY_SLOT_COUNT is Wireless Stack (if installed) dependent. The second digit should be 1 for the PSA Crypto.

The first digit in SL_PSA_ITS_MAX_FILES is equal to 1 if the project installed the PSA persistent storage support (ITS) component Figure Security Software Component for Persistent Key Storage before.

Initialization and Random Number Generation (RNG)#

In PSA Crypto, applications must call psa_crypto_init() to initialize the library before using any other function. The PSA Crypto initialization includes seeding the pseudo-random generator (CTR-DRBG) with a hardware entropy source during the execution of psa_crypto_init().

Item Mbed TLS PSA Crypto

Initialization

Initialize CTR-DRBG
void mbedtls_entropy_init(…)
void mbedtls_ctr_drbg_init(…)
int mbedtls_entropy_add_source(…)
Seed and set up the CTR-DRBG entropy
int mbedtls_ctr_drbg_seed(…)

Initialize PSA Crypto
psa_status_t psa_crypto_init(void)

Generate random bytes

int mbedtls_ctr_drbg_random(…)

psa_status_t psa_generate_random(…)

Free resources

void mbedtls_ctr_drbg_free(…)
void mbedtls_entropy_free(…)

void mbedtls_psa_crypto_free(void)

If a device includes a True Random Number Generator (TRNG) hardware module, the example will use the TRNG as an entropy source to seed the CTR-DRBG. If the device does not incorporate a TRNG, the example will use RAIL, Non-volatile (NV) seed (requires NVM3 driver), or ADC as the entropy source.

Device

Entropy Source

MCU Series 1 - EFM32JG1, EFM32PG1

NV seed (default) or ADC

MCU Series 1 - EFM32JG12, EFM32PG12, EFM32GG11, EFM32GG12, EFM32TG11

TRNG

Wireless SoC Series 1 - EFR32xG1, EFR32xG14

RAIL

Wireless SoC Series 1 - EFR32xG12, EFR32xG13 (Revision D or later)

TRNG

All MCU Series 2 and Wireless SoC Series 2 devices

TRNG

Quick Reference Examples

PSA Crypto Initialization and Random Number Generation

#include "psa/crypto.h"
void app_process_action(void)
{
  uint8_t rand_buf[32];
  psa_status_t ret;

  // Initialize the PSA Crypto and generate random numbers
  ret = psa_crypto_init();
  ret = psa_generate_random(rand_buf, sizeof(rand_buf));
}

Key Handling#

The following table describes the main differences in key handling between Mbed TLS and PSA Crypto.

Item

Mbed TLS

PSA Crypto

Random Number Generation (RNG)

It requires application code to keep track of RNG.

The core keeps track of RNG.

Buffer

It requires dedicated key buffers.

The core manages the key.

Key export

The key is exportable.

The usage flag manages this option.

Lifetime

It is volatile.

It can be volatile or persistent.

Location

Local

Local or Secure

Symmetric Key#

A symmetric key can be used with a block cipher or a stream cipher.

Algorithms

Refer to the Symmetric Cryptographic Operation section.

Key Attributes in PSA Crypto

Refer to the Symmetric Cryptographic Operation section.

Security Software Components

Refer to the Symmetric Cryptographic Operation section.

Functions

Item Mbed TLS PSA Crypto

Create a random key

Generate random numbers to a buffer
int mbedtls_ctr_drbg_random(…)
Set up a key from a buffer (API is algorithm dependent)
int mbedtls_aes_setkey_enc(…)
int mbedtls_aes_setkey_dec(…)
int mbedtls_cipher_setkey(…)
int mbedtls_ccm_setkey(…)
int mbedtls_gcm_setkey(…)
int mbedtls_chacha20_setkey(…)
int mbedtls_chachapoly_setkey(…)

Create a key from randomly generated data
psa_status_t psa_generate_key(…)

Import a key from a buffer

API is algorithm dependent
int mbedtls_aes_setkey_enc(…)
int mbedtls_aes_setkey_dec(…)
int mbedtls_cipher_setkey(…)
int mbedtls_ccm_setkey(…)
int mbedtls_gcm_setkey(…)
int mbedtls_chacha20_setkey(…)
int mbedtls_chachapoly_setkey(…)

psa_status_t psa_import_key(…)

Copy a key

psa_status_t psa_copy_key(…)

Export a key to a buffer

The key is always in a buffer.

psa_status_t psa_export_key(…)

Destroy a key

Zero the key buffer.

psa_status_t psa_destroy_key(…)

Note: The psa_export_key() can export a symmetric key in plaintext if the PSA_KEY_USAGE_EXPORT usage flag is set.

Quick Reference Examples

Symmetric Plain Key Creation and Import

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t aes_ecb_key[16] = {0};

  psa_status_t ret;
  psa_key_id_t generate_key_id;
  psa_key_id_t import_key_id;
  psa_key_attributes_t key_attr;

  ret = psa_crypto_init();

  // Set up attributes for a AES ECB key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
  psa_set_key_bits(&key_attr, 128);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
  psa_set_key_algorithm(&key_attr, PSA_ALG_ECB_NO_PADDING);

  // Generate a random volatile plain key for AES ECB
  ret = psa_generate_key(&key_attr, &generate_key_id);

  // Import a volatile plain key for AES ECB
  ret = psa_import_key(&key_attr, aes_ecb_key, sizeof(aes_ecb_key), &import_key_id);

  // Destroy the volatile plain keys for AES ECB
  ret = psa_destroy_key(generate_key_id);
  ret = psa_destroy_key(import_key_id);

  // Generate a random persistent plain key for AES ECB (ID = 0x02)
  psa_set_key_id(&key_attr, 0x02);
  ret = psa_generate_key(&key_attr, &generate_key_id);

  // Import a persistent plain key for AES ECB (ID = 0x03)
  psa_set_key_id(&key_attr, 0x03);
  ret = psa_import_key(&key_attr, aes_ecb_key, sizeof(aes_ecb_key), &import_key_id);

  // Destroy the persistent plain keys for AES ECB
  ret = psa_destroy_key(generate_key_id);
  ret = psa_destroy_key(import_key_id);
}

Symmetric Wrapped Key Creation and Import (HSE-SVH only)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t aes_ecb_key[16] = {0};

  psa_status_t ret;
  psa_key_id_t generate_key_id;
  psa_key_id_t import_key_id;
  psa_key_attributes_t key_attr;
  ret = psa_crypto_init();

  // Set up attributes for a AES ECB key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
  psa_set_key_bits(&key_attr, 128);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
  psa_set_key_algorithm(&key_attr, PSA_ALG_ECB_NO_PADDING);
  psa_set_key_lifetime(&key_attr, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_PERSISTENCE_VOLATILE, 0x01));

  // Generate a random volatile wrapped key for AES ECB
  ret = psa_generate_key(&key_attr, &generate_key_id);

  // Import a volatile wrapped key for AES ECB
  ret = psa_import_key(&key_attr, aes_ecb_key, sizeof(aes_ecb_key), &import_key_id);

  // Destroy the volatile wrapped keys for AES ECB
  ret = psa_destroy_key(generate_key_id);
  ret = psa_destroy_key(import_key_id);

  // Generate a random persistent wrapped key for AES ECB (ID = 0x02)
  psa_set_key_id(&key_attr, 0x02);
  psa_set_key_lifetime(&key_attr, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_PERSISTENCE_DEFAULT, 0x01));
  ret = psa_generate_key(&key_attr, &generate_key_id);

  // Import a persistent wrapped key for AES ECB (ID = 0x03)
  psa_set_key_id(&key_attr, 0x03);
  psa_set_key_lifetime(&key_attr, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_PERSISTENCE_DEFAULT, 0x01));
  ret = psa_import_key(&key_attr, aes_ecb_key, sizeof(aes_ecb_key), &import_key_id);

  // Destroy the persistent wrapped keys for AES ECB
  ret = psa_destroy_key(generate_key_id);
  ret = psa_destroy_key(import_key_id);
}

PSA Crypto Platform Example

Click the View Project Documentation link to open the readme file.

image21image21

The following table describes the implementation status of the PSA Crypto symmetric key platform example.

Key

Series 1

Series 2 - VSE

Series 2 - HSE

Remark

Extractable

Y

Y

Y

Copyable

Y

Y

Y

The PSA_KEY_USAGE_COPY usage flag does not apply to the wrapped key.

Wrapped

Y

Only on HSE-SVH devices.

128-bit

Y

Y

Y

192-bit

Y

Y

Y

256-bit

Y

Y

Y

Asymmetric Key#

An asymmetric key pair consists of a (secret) private key and a public key (not secret). A public key cryptographic algorithm can be used for key distribution and digital signatures.

Algorithms

Refer to the Asymmetric Cryptographic Operation section.

Key Attributes in PSA Crypto

Refer to the Asymmetric Cryptographic Operation section.

Security Software Components

Refer to the Asymmetric Cryptographic Operation section.

Functions

Item Mbed TLS PSA Crypto

Create a random key

ECDH
void mbedtls_ecdh_init(…)
int mbedtls_ecp_group_load(…)
int mbedtls_ecdh_gen_public(…)
ECDSA
void mbedtls_ecdsa_init(…)
int mbedtls_ecdsa_genkey(…)

Create a key from randomly generated data
psa_status_t psa_generate_key(…)

Import a private or public key from a buffer

int mbedtls_ecp_point_read_binary(…)
int mbedtls_mpi_read_binary(…)

psa_status_t psa_import_key(…)

Copy a key

psa_status_t psa_copy_key(…)

Export a private key to a buffer

int mbedtls_ecp_point_write_binary(…)
int mbedtls_mpi_write_binary(…)

psa_status_t psa_export_key(…)

Export a public key to a buffer

int mbedtls_ecp_point_write_binary(…)
int mbedtls_mpi_write_binary(…)

psa_status_t psa_export_public_key(…)

Destroy a key

ECDH
void mbedtls_ecdh_free(…)
ECDSA
void mbedtls_ecdsa_free(…)

psa_status_t psa_destroy_key(…)

Note:

  • The psa_import_key() cannot store a public key in wrapped form.

  • The psa_export_key() can export a private key in plaintext if the PSA_KEY_USAGE_EXPORT usage flag is set.

ECC Key

Private Key Size (Import and Export)

Public Key Size (Import and Export)

secp192r1

24-byte

49-byte

secp224r1

28-byte

57-byte

secp256r1

32-byte

65-byte

secp384r1

48-byte

97-byte

secp521r1

66-byte

133-byte

secp256k1

32-byte

65-byte

Curve25519

32-byte

32-byte

Curve448

56-byte

56-byte

Edwards25519

32-byte

32-byte

Note:

  • The public key of the secpxxx curve is stored in an uncompressed format (prefix 0x04 with the X and Y coordinates).

  • EFR32xG21A/B devices do not support hardware acceleration on the secp224r1 curve.

  • Only the VSE-SVM devices support hardware acceleration on the secp256k1 curve.

  • The secp224r1 and secp256k1 with wrapped keys are not supported yet.

Quick Reference

Examples Asymmetric Key Creation and Import

#include "psa/crypto.h"
void app_process_action(void)
{
  uint8_t public_key[65];         // Uncompressed point format
  size_t pubkey_len;

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;

  ret = psa_crypto_init();

  // Check if there is already a persistent key with the given identifier (ID = 0x02)
  key_attr = psa_key_attributes_init();
  ret = psa_get_key_attributes(0x02, &key_attr);

  if (ret == PSA_ERROR_INVALID_HANDLE) {
    // Key identifier does not exist, set up attributes for a persistent private wrapped key (secp256r1)
    key_attr = psa_key_attributes_init();
    psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
    psa_set_key_bits(&key_attr, 256);
    psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH);
    psa_set_key_algorithm(&key_attr, PSA_ALG_ECDSA_ANY);
    psa_set_key_id(&key_attr, 0x02);
    psa_set_key_lifetime(&key_attr, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_PERSISTENCE_DEFAULT, 0x01));

    // Generate a random persistent private wrapped key (ID = 0x02)
    ret = psa_generate_key(&key_attr, &key_id);

    // Export a public key from a persistent private wrapped key (ID = 0x02)
    ret = psa_export_public_key(0x02, public_key, sizeof(public_key), &pubkey_len);

    // Set up attributes for a public key (secp256r1)
    key_attr = psa_key_attributes_init();
    psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
    psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_VERIFY_HASH);
    psa_set_key_algorithm(&key_attr, PSA_ALG_ECDSA_ANY);

    // Import a public key
    ret = psa_import_key(&key_attr, public_key, sizeof(public_key), &key_id);

    // Destroy a persistent private wrapped key (ID = 0x02) and public key
    ret = psa_destroy_key(0x02);
    ret = psa_destroy_key(key_id);
  } else if (ret == PSA_SUCCESS) {
    // Key identifier already exists
    return;
  } else {
      // Unexpected error
    return;
  }
}

Note: Remove the code for the psa_set_key_lifetime() function to generate a random persistent private plain key on non-HSE-SVH devices.

PSA Crypto Platform Example

Click the View Project Documentation link to open the readme file.

image22image22

The following table describes the implementation status of the PSA Crypto asymmetric key platform example.

ECC Key

Series 1

Series 2 - VSE

Series 2 - HSE

Remark

Extractable

Y

Y

Y

Copyable

Y

Y

Y

The PSA_KEY_USAGE_COPY usage flag does not apply to the wrapped key.

Wrapped

Y

Only on HSE-SVH devices.

secp192r1

Y

Y

Y

secp256r1

Y

Y

Y

secp384r1

Y

Y

Y

Hardware acceleration only on HSE-SVH devices.

secp521r1

Y

Y

Y

Hardware acceleration only on HSE-SVH devices.

Curve25519

Y

Y

Y

Hardware acceleration only on HSE devices.

Curve448

Y

Only on HSE-SVH devices with hardware acceleration.

Edwards25519

Y

Only on HSE devices with hardware acceleration.

Note:

  • This example does not include secp224r1 and secp256k1.

  • The PSA Crypto does not yet support software fallback on the Curve448 and Edwards25519.

  • The HSE-SVM devices require SE firmware v1.2.11 or higher (EFR32xG21) and v2.1.7 or higher (other HSE devices) to support hardware acceleration on Curve25519 and Edwards25519. This feature also requires GSDK v4.0.1 or higher.

Symmetric Cryptographic Operation#

Message Digests#

Message digests are designed to protect the integrity of a piece of data or media to detect changes to any part of a message. They are a type of cryptography utilizing hash values that can warn the receiver of any modifications applied to a message transmitted over an insecure channel.

Algorithms

Algorithm Mbed TLS PSA Crypto

SHA-1

MBEDTLS_MD_SHA1

PSA_ALG_SHA_1

SHA-2

MBEDTLS_MD_SHA224
MBEDTLS_MD_SHA256
MBEDTLS_MD_SHA384
MBEDTLS_MD_SHA512

PSA_ALG_SHA_224
PSA_ALG_SHA_256
PSA_ALG_SHA_384
PSA_ALG_SHA_512

Security Software Components

Algorithm

Security Software Components

PSA_ALG_SHA_1

SHA-1

PSA_ALG_SHA_224

SHA-224

PSA_ALG_SHA_256

SHA-256

PSA_ALG_SHA_384

SHA-384

PSA_ALG_SHA_512

SHA-512

Single-Part Functions

Mbed TLS PSA Crypto

Generic
int mbedtls_md(…)
Algorithm specific
int mbedtls_sha1_ret(…)
int mbedtls_sha256_ret(…)
int mbedtls_sha512_ret(…)

psa_status_t psa_hash_compute(…)

psa_status_t psa_hash_compare(…)

Multi-Part Operations

Mbed TLS PSA Crypto

Generic
void mbedtls_md_init(…)
Algorithm specific
void mbedtls_sha1_init(…)
void mbedtls_sha256_init(…)
void mbedtls_sha512_init(…)

psa_hash_operation_t psa_hash_operation_init(void)

Generic
int mbedtls_md_setup(…)
int mbedtls_md_starts(…)
Algorithm specific
int mbedtls_sha1_starts_ret(…)
int mbedtls_sha256_starts_ret(…)
int mbedtls_sha512_starts_ret(…)

psa_status_t psa_hash_setup(…)

Generic
int mbedtls_md_update(…)
Algorithm specific
int mbedtls_sha1_update_ret(…)
int mbedtls_sha256_update_ret(…)
int mbedtls_sha512_update_ret(…)

psa_status_t psa_hash_update(…)

Generic
int mbedtls_md_finish(…)
Algorithm specific
int mbedtls_sha1_finish_ret(…)
int mbedtls_sha256_finish_ret(…)
int mbedtls_sha512_finish_ret(…)

psa_status_t psa_hash_finish(…)

psa_status_t psa_hash_verify(…)

Generic
void mbedtls_md_free(…)
Algorithm specific
void mbedtls_sha1_free(…)
void mbedtls_sha256_free(…)
void mbedtls_sha512_free(…)

psa_status_t psa_hash_abort(…)

Generic
int mbedtls_md_clone(…)
Algorithm specific
int mbedtls_sha1_clone(…)
int mbedtls_sha256_clone(…)
int mbedtls_sha512_clone(…)

psa_status_t psa_hash_clone(…)

Note: The multi-part operation allows the data to be processed for message digest in fragments instead of all at once.

Quick Reference Examples

SHA-256 (One-shot)

#include "psa/crypto.h"
void app_process_action(void)
{
  char test_msg[] = {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"};
  uint8_t expect_sha256_hash[] = {
    0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
    0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1
  };

  uint8_t hash_buf[32];
  size_t hash_len;
  psa_status_t ret;

  ret = psa_crypto_init();

  // Calculate the hash of a message
  ret = psa_hash_compute(PSA_ALG_SHA_256,
                        (uint8_t *)test_msg,
                        sizeof(test_msg) - 1,
                        hash_buf,
                        sizeof(hash_buf),
                        &hash_len);

  // Calculate the hash of a message and compare it with a reference value
  ret = psa_hash_compare(PSA_ALG_SHA_256,
                        (uint8_t *)test_msg,
                        sizeof(test_msg) - 1,
                        expect_sha256_hash,
                        sizeof(expect_sha256_hash));
}

SHA-256 (Streaming)

#include "psa/crypto.h"
void app_process_action(void)
{
  char test_msg[] = {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"};
  uint8_t hash_buf[32];
  size_t hash_len;
  uint32_t hash_total;
  uint32_t stream_block_size = 16;            // Block size for streaming

  psa_status_t ret;
  psa_hash_operation_t hash_op;
  psa_hash_operation_t verify_op;

  ret = psa_crypto_init();

  hash_op = psa_hash_operation_init();
  ret = psa_hash_setup(&hash_op, PSA_ALG_SHA_256);

  // Streaming block
  hash_total = 0;
  while ((sizeof(test_msg) - 1 - hash_total) > stream_block_size) {
  ret = psa_hash_update(&hash_op, (uint8_t *)(test_msg + hash_total), stream_block_size);
  hash_total += stream_block_size;
  }
  ret = psa_hash_update(&hash_op, (uint8_t *)(test_msg + hash_total), sizeof(test_msg) -1 - hash_total);

  // Generate hash and verify
  // Expected hash:
  // 24 8d 6a 61 d2 06 38 b8 e5 c0 26 93 0c 3e 60 39 a3 3c e4 59 64 ff 21 67 f6 ec ed d4 19 db 06 c1
  verify_op = psa_hash_operation_init();
  ret = psa_hash_clone(&hash_op, &verify_op);
  ret = psa_hash_finish(&hash_op, hash_buf, sizeof(hash_buf), &hash_len);
  ret = psa_hash_verify(&verify_op, hash_buf, hash_len);
}

PSA Crypto Platform Example

Click the View Project Documentation link to open the readme file.

image23image23

The following table describes the implementation status of the PSA Crypto hash platform example.

Algorithm

Series 1

Series 2 - VSE

Series 2 - HSE

Remark

SHA-1

Y

Y

Y

SHA-224

Y

Y

Y

SHA-256

Y

Y

Y

SHA-384

Y

Y

Y

Hardware acceleration only on HSE-SVH devices.

SHA-512

Y

Y

Y

Hardware acceleration only on HSE-SVH devices.

Message Authentication Codes (MAC)#

A Message Authentication Code (MAC), sometimes known as a tag, is a short piece of information used to confirm that the message came from the stated sender (its authenticity) and has not been changed.

Algorithms

Algorithm Mbed TLS PSA Crypto

HMAC

• MBEDTLS_MD_SHA1
• MBEDTLS_MD_SHA224
• MBEDTLS_MD_SHA256
• MBEDTLS_MD_SHA384
• MBEDTLS_MD_SHA512

PSA_ALG_HMAC(PSA_ALG_SHA_1)
PSA_ALG_HMAC(PSA_ALG_SHA_224)
PSA_ALG_HMAC(PSA_ALG_SHA_256)
PSA_ALG_HMAC(PSA_ALG_SHA_384)
PSA_ALG_HMAC(PSA_ALG_SHA_512)
PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(hash_alg), mac_length)
PSA_ALG_FULL_LENGTH_MAC(PSA_ALG_HMAC(hash_alg))
PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(PSA_ALG_HMAC(hash_alg), min_mac_length)

CMAC

MBEDTLS_CIPHER_AES_128_ECB
MBEDTLS_CIPHER_AES_192_ECB
MBEDTLS_CIPHER_AES_256_ECB

PSA_ALG_CMAC
PSA_ALG_TRUNCATED_MAC(PSA_ALG_CMAC, mac_length)
PSA_ALG_FULL_LENGTH_MAC(PSA_ALG_CMAC)
PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(PSA_ALG_CMAC, min_mac_length)

Key Attributes in PSA Crypto

Algorithm Key Type Key Size in Bits Key Usage Flag
•PSA_ALG_HMAC(PSA_ALG_SHA_1)

•PSA_ALG_HMAC(PSA_ALG_SHA_224)

•PSA_ALG_HMAC(PSA_ALG_SHA_256)

•PSA_ALG_HMAC(PSA_ALG_SHA_384)

•PSA_ALG_HMAC(PSA_ALG_SHA_512)

•PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(hash_alg), mac_length)

•PSA_ALG_FULL_LENGTH_MAC(PSA_ALG_HMAC(hash_alg))

•PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(PSA_ALG_HMAC(hash_alg), min_mac_length)
PSA_KEY_TYPE_HMAC Multiple of 8 •PSA_KEY_USAGE_SIGN_MESSAGE

•PSA_KEY_USAGE_VERIFY_MESSAGE
•PSA_ALG_CMAC

•PSA_ALG_TRUNCATED_MAC(PSA_ALG_CMAC, mac_length)

•PSA_ALG_FULL_LENGTH_MAC(PSA_ALG_CMAC)

•PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(PSA_ALG_CMAC, min_mac_length)
PSA_KEY_TYPE_AES •128 (16-byte)

•192 (24-byte)

•256 (32-byte)

Note: For GSDK lower than v4.1.0, use usage flag PSA_KEY_USAGE_SIGN_HASH and PSA_KEY_USAGE_VERIFY_HASH instead of PSA_KEY_USAGE_SIGN_MESSAGE and PSA_KEY_USAGE_VERIFY_MESSAGE.

Security Software Components

Algorithm

Security Software Components

PSA_ALG_HMAC(PSA_ALG_SHA_1)

HMAC and SHA-1

PSA_ALG_HMAC(PSA_ALG_SHA_224)

HMAC and SHA-224

PSA_ALG_HMAC(PSA_ALG_SHA_256)

HMAC and SHA-256

PSA_ALG_HMAC(PSA_ALG_SHA_384)

HMAC and SHA-384

PSA_ALG_HMAC(PSA_ALG_SHA_512)

HMAC and SHA-512

PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(hash_alg), mac_length)

HMAC and SHA-X

PSA_ALG_FULL_LENGTH_MAC(PSA_ALG_HMAC(hash_alg))

HMAC and SHA-X

PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(PSA_ALG_HMAC(hash_alg), min_mac_length)

HMAC and SHA-X

PSA_ALG_CMAC

CMAC

PSA_ALG_TRUNCATED_MAC(PSA_ALG_CMAC, mac_length)

CMAC

PSA_ALG_FULL_LENGTH_MAC(PSA_ALG_CMAC)

CMAC

PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(PSA_ALG_CMAC, min_mac_length)

CMAC

Single-Part Functions

Mbed TLS PSA Crypto

HMAC
int mbedtls_md_hmac(…)
CMAC
int mbedtls_cipher_cmac(…)

psa_status_t psa_mac_compute(…)

psa_status_t psa_mac_verify(…)

Multi-Part Operations

Mbed TLS PSA Crypto

HMAC
void mbedtls_md_init(…)
int mbedtls_md_setup(…)
CMAC
void mbedtls_cipher_init(…)

psa_mac_operation_t psa_mac_operation_init(void)

HMAC
int mbedtls_md_hmac_starts(…)
CMAC
int mbedtls_cipher_cmac_starts(…)

psa_status_t psa_mac_sign_setup(…)

psa_status_t psa_mac_verify_setup(…)

HMAC
int mbedtls_md_hmac_update(…)
CMAC
int mbedtls_cipher_cmac_update(…)

psa_status_t psa_mac_update(…)

HMAC
int mbedtls_md_hmac_finish(…)
CMAC
int mbedtls_cipher_cmac_finish(…)

psa_status_t psa_mac_sign_finish(…)

psa_status_t psa_mac_verify_finish(…)

HMAC
void mbedtls_md_free(…)
CMAC
void mbedtls_cipher_free(…)

psa_status_t psa_mac_abort(…)

Note: The multi-part operation allows the data to be processed for MAC in fragments instead of all at once.

Quick Reference Examples

CMAC (One-shot)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t cmac_key[] = {
    0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
    0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4
  };
  uint8_t cmac_msg[] = {
    0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
    0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
    0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11
  };
  uint8_t mac_buf[16];
  size_t mac_len;

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;

  ret = psa_crypto_init();

  // Set up attributes for a CMAC key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_CMAC);

  // Import a volatile plain key for CMAC
  ret = psa_import_key(&key_attr, cmac_key, sizeof(cmac_key), &key_id);

  // Calculate the CMAC MAC of a message
  // Expected CMAC MAC: aa f3 d8 f1 de 56 40 c2 32 f5 b1 69 b9 c9 11 e6
  ret = psa_mac_compute(key_id, PSA_ALG_CMAC,
                        cmac_msg, sizeof(cmac_msg),
                        mac_buf, sizeof(mac_buf), &mac_len);

  // Verify the CMAC MAC of a message
  ret = psa_mac_verify(key_id, PSA_ALG_CMAC,
                        cmac_msg, sizeof(cmac_msg),
                        mac_buf, mac_len);

  // Destroy a volatile plain key for CMACss
  ret = psa_destroy_key(key_id);
}

Note: There are two ways to change the CMAC MAC length (default 16 bytes).

  1. Replace all MAC algorithm PSA_ALG_CMAC with PSA_ALG_TRUNCATED_MAC``(PSA_ALG_CMAC, mac_length) for the desired size (≥ 4) of the MAC in bytes.

  2. Replace the MAC algorithm PSA_ALG_CMAC in the psa_set_key_algorithm(&key_attr, PSA_ALG_CMAC) function with PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(PSA_ALG_CMAC, min_mac_length) to set the minimum MAC length (≥ 4) in bytes. Replace the MAC algorithm PSA_ALG_CMAC in psa_mac_compute() and psa_mac_verify() with PSA_ALG_TRUNCATED_MAC``(PSA_ALG_CMAC, mac_length) to set the desired MAC length (≥ min_mac_length and ≤ PSA_MAC_LENGTH``(PSA_KEY_TYPE_AES, 256, PSA_ALG_CMAC)) in bytes.

HMAC SHA-256 (One-shot)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t hmac_key[] = {
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
  };
  uint8_t hmac_msg[] = {
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
  };
  uint8_t mac_buf[32];
  size_t mac_len;

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;

  ret = psa_crypto_init();

  // Set up attributes for a HMAC key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_HMAC);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_HMAC(PSA_ALG_SHA_256));

  // Import a volatile plain key for HMAC
  ret = psa_import_key(&key_attr, hmac_key, sizeof(hmac_key), &key_id);

  // Calculate the HMAC MAC of a message
  // Expected HMAC MAC:
  // fb 5b 26 22 9c 20 b7 ed 86 67 06 a2 fb fa e6 7e 3f 40 4b b6 ab e7 7f f4 50 63 a4 59 a4 29 24 a4
  ret = psa_mac_compute(key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256),
                        hmac_msg, sizeof(hmac_msg),
                        mac_buf, sizeof(mac_buf), &mac_len);
  // Verify the HMAC MAC of a message
  ret = psa_mac_verify(key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256),
                        hmac_msg, sizeof(hmac_msg),
                        mac_buf, mac_len);

  // Destroy a volatile plain key for HMAC
  ret = psa_destroy_key(key_id);
}

Notes: There are two ways to change the HMAC MAC length (default is hash_alg dependent).

  1. Replace all MAC algorithm PSA_ALG_HMAC(hash_alg) with PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(hash_alg), mac_length) for the desired size (≥ 4) of the MAC in bytes.

  2. Replace the MAC algorithm PSA_ALG_HMAC(hash_alg) in the psa_set_key_algorithm(&key_attr, PSA_ALG_HMAC(hash_alg)) function with PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(PSA_ALG_HMAC(hash_alg), min_mac_length) to set the minimum MAC length (≥ 4) in bytes.

Replace the MAC algorithm PSA_ALG_HMAC(hash_alg) in psa_mac_compute() and psa_mac_verify() with PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(hash_alg), mac_length) to set the desired MAC length (≥ min_mac_length and ≤ PSA_MAC_LENGTH(PSA_KEY_TYPE_HMAC, 256, PSA_ALG_HMAC(hash_alg))) in bytes.

CMAC (Streaming)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t cmac_key[] = {
    0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
    0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4
  };
  uint8_t cmac_msg[] = {
    0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
    0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
    0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11
  };
  uint8_t mac_buf[16];
  size_t mac_len;
  uint32_t mac_total;
  uint32_t stream_block_size = 8;

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;
  psa_mac_operation_t mac_op;

  ret = psa_crypto_init();

  // Set up attributes for a CMAC key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_CMAC);

  // Import a volatile plain key for CMAC
  ret = psa_import_key(&key_attr, cmac_key, sizeof(cmac_key), &key_id);

  // Stream message and calculate the CMAC MAC
  // Expected CMAC MAC: aa f3 d8 f1 de 56 40 c2 32 f5 b1 69 b9 c9 11 e6
  mac_op = psa_mac_operation_init();
  ret = psa_mac_sign_setup(&mac_op, key_id, PSA_ALG_CMAC);
  mac_total = 0;        // Streaming block
  while ((sizeof(cmac_msg) - mac_total) > stream_block_size) {
    ret = psa_mac_update(&mac_op, cmac_msg + mac_total, stream_block_size);
    mac_total += stream_block_size;
  }
  ret = psa_mac_update(&mac_op, cmac_msg + mac_total, sizeof(cmac_msg) - mac_total);
  ret = psa_mac_sign_finish(&mac_op, mac_buf, sizeof(mac_buf), &mac_len);

  // Stream message and verify the CMAC MAC
  mac_op = psa_mac_operation_init();
  ret = psa_mac_verify_setup(&mac_op, key_id, PSA_ALG_CMAC);
  mac_total = 0;        // Streaming block
  while ((sizeof(cmac_msg) - mac_total) > stream_block_size) {
    ret = psa_mac_update(&mac_op, cmac_msg + mac_total, stream_block_size);
    mac_total += stream_block_size;
  }
  ret = psa_mac_update(&mac_op, cmac_msg + mac_total, sizeof(cmac_msg) - mac_total);
  ret = psa_mac_verify_finish(&mac_op, mac_buf, mac_len);

  // Destroy a volatile plain key for CMAC
  ret = psa_destroy_key(key_id);
}

Notes: There are two ways to change the CMAC MAC length (default 16 bytes).

  1. Replace all MAC algorithm PSA_ALG_CMAC with PSA_ALG_TRUNCATED_MAC(PSA_ALG_CMAC, mac_length) for the desired size (≥ 4) of the MAC in bytes.

  2. Replace the MAC algorithm PSA_ALG_CMAC in the psa_set_key_algorithm(&key_attr, PSA_ALG_CMAC) function with PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(PSA_ALG_CMAC, min_mac_length) to set the minimum MAC length (≥ 4) in bytes.

Replace the MAC algorithm PSA_ALG_CMAC in psa_mac_sign_setup() and psa_mac_verify_setup() with PSA_ALG_TRUNCATED_MAC(PSA_ALG_CMAC, mac_length) to set the desired MAC length (≥ min_mac_length and ≤ PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, 256, PSA_ALG_CMAC)) in bytes.

HMAC SHA-256 (Streaming)

#include "psa/crypto.h"
void app_process_action(void)
{
  uint8_t hmac_key[] = {
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
  };
  uint8_t hmac_msg[] = {
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
  };
  uint8_t mac_buf[32];
  size_t mac_len;
  uint32_t mac_total;
  uint32_t stream_block_size = 8;

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;
  psa_mac_operation_t mac_op;

  ret = psa_crypto_init();

  // Set up attributes for a HMAC key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_HMAC);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_HMAC(PSA_ALG_SHA_256));

  // Import a volatile plain key for HMAC
  ret = psa_import_key(&key_attr, hmac_key, sizeof(hmac_key), &key_id);

  // Stream message and calculate the HMAC MAC
  // Expected HMAC MAC:
  // fb 5b 26 22 9c 20 b7 ed 86 67 06 a2 fb fa e6 7e 3f 40 4b b6 ab e7 7f f4 50 63 a4 59 a4 29 24 a4
  mac_op = psa_mac_operation_init();
  ret = psa_mac_sign_setup(&mac_op, key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256));
  mac_total = 0; // Streaming block
  while ((sizeof(hmac_msg) - mac_total) > stream_block_size) {
    ret = psa_mac_update(&mac_op, hmac_msg + mac_total, stream_block_size);
    mac_total += stream_block_size;
  }
  ret = psa_mac_update(&mac_op, hmac_msg + mac_total, sizeof(hmac_msg) - mac_total);
  ret = psa_mac_sign_finish(&mac_op, mac_buf, sizeof(mac_buf), &mac_len);

  // Stream message and verify the HMAC MAC
  mac_op = psa_mac_operation_init();
  ret = psa_mac_verify_setup(&mac_op, key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256));
  mac_total = 0; // Streaming block
  while ((sizeof(hmac_msg) - mac_total) > stream_block_size) {
    ret = psa_mac_update(&mac_op, hmac_msg + mac_total, stream_block_size);
    mac_total += stream_block_size;
  }
  ret = psa_mac_update(&mac_op, hmac_msg + mac_total, sizeof(hmac_msg) - mac_total);
  ret = psa_mac_verify_finish(&mac_op, mac_buf, mac_len);

  // Destroy a volatile plain key for HMAC
  ret = psa_destroy_key(key_id);
}

Notes: There are two ways to change the HMAC MAC length (default is hash_alg dependent).

  1. Replace all MAC algorithm PSA_ALG_HMAC(hash_alg) with PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(hash_alg), mac_length) for the desired size (≥ 4) of the MAC in bytes.

  2. Replace the MAC algorithm PSA_ALG_HMAC(hash_alg) in the psa_set_key_algorithm(&key_attr, PSA_ALG_HMAC(hash_alg)) function with PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(PSA_ALG_HMAC(hash_alg), min_mac_length) to set the minimum MAC length (≥ 4) in bytes.

Replace the MAC algorithm PSA_ALG_HMAC(hash_alg) in psa_mac_sign_setup() and psa_mac_verify_setup() with PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(hash_alg), mac_length) to set the desired MAC length (≥ min_mac_length and ≤ PSA_MAC_LENGTH(PSA_KEY_TYPE_HMAC, 256, PSA_ALG_HMAC(hash_alg))) in bytes.

PSA Crypto Platform Example

Click the View Project Documentation link to open the readme file.

image24image24

The following table describes the implementation status of the PSA Crypto MAC platform example.

Algorithm Series 1 Series 2 - VSE Series 2 - HSE Remark

HMAC

Y

Y

Y

- Hardware acceleration only on Series 2 devices.
- HMAC streaming with wrapped key is not supported yet.

CMAC

Y

Y

Y

Series 1 devices do not support a 192-bit key.

Note:

  • The MAC platform example uses the default MAC length.

  • The single-part MAC functions are only available on GSDK v4.0.0 and higher.

Unauthenticated Ciphers#

The unauthenticated cipher API is for use cases where the data integrity and authenticity are guaranteed by non-cryptographic means.

Algorithms

Algorithm Mbed TLS PSA Crypto

AES ECB

MBEDTLS_CIPHER_AES_128_ECB
MBEDTLS_CIPHER_AES_192_ECB
MBEDTLS_CIPHER_AES_256_ECB

PSA_ALG_ECB_NO_PADDING

AES CBC

MBEDTLS_CIPHER_AES_128_CBC
MBEDTLS_CIPHER_AES_192_CBC
MBEDTLS_CIPHER_AES_256_CBC

PSA_ALG_CBC_NO_PADDING

AES CFB

MBEDTLS_CIPHER_AES_128_CFB128
MBEDTLS_CIPHER_AES_192_CFB128
MBEDTLS_CIPHER_AES_256_CFB128

PSA_ALG_CFB

AES CTR

MBEDTLS_CIPHER_AES_128_CTR
MBEDTLS_CIPHER_AES_192_CTR
MBEDTLS_CIPHER_AES_256_CTR

PSA_ALG_CTR

CHACHA20

MBEDTLS_CIPHER_CHACHA20

PSA_ALG_STREAM_CIPHER

Key Attributes in PSA Crypto

Algorithm Key Type Key Size in Bits Key Usage Flag
PSA_ALG_ECB_NO_PADDING PSA_KEY_TYPE_AES 128 (16-byte)
192 (24-byte)
256 (32-byte)
PSA_KEY_USAGE_ENCRYPT
PSA_KEY_USAGE_DECRYPT
PSA_ALG_CBC_NO_PADDING
PSA_ALG_CFB
PSA_ALG_CTR
PSA_ALG_STREAM_CIPHER PSA_KEY_TYPE_CHACHA20 256 (32-byte)

Security Software Components

Algorithm and Built-in Key

Security Software Components

PSA_ALG_ECB_NO_PADDING

ECB Mode

PSA_ALG_CBC_NO_PADDING

CBC Mode

PSA_ALG_CFB

CFB Mode

PSA_ALG_CTR

CTR Mode

PSA_ALG_STREAM_CIPHER

Chacha20 Stream Cipher

Built-in Key

Security Software Components

secp256r1 keys in SE OTP

Built-In Keys

Single-Part Functions

Mbed TLS PSA Crypto

Generic
int mbedtls_cipher_crypt(…)
Algorithm specific
int mbedtls_aes_crypt_ecb(…)
int mbedtls_aes_crypt_cbc(…)
int mbedtls_aes_crypt_cfb128(…)
int mbedtls_aes_crypt_ctr(…)
int mbedtls_chacha20_crypt(…)

psa_status_t psa_cipher_encrypt(…)

Generic
int mbedtls_cipher_crypt(…)
Algorithm specific
int mbedtls_aes_crypt_ecb(…)
int mbedtls_aes_crypt_cbc(…)
int mbedtls_aes_crypt_cfb128(…)
int mbedtls_aes_crypt_ctr(…)
int mbedtls_chacha20_crypt(…)

psa_status_t psa_cipher_decrypt(…)

Note:

  • The psa_cipher_encrypt() encrypts a message with a random initialization vector (IV). The output of this function is the IV followed by the ciphertext. Use the multi-part operations to manage the IV and ciphertext separately.

  • The input to psa_cipher_decrypt() must contain the IV followed by the ciphertext, as output by psa_cipher_encrypt(). Use the multi-part operations to decrypt data that is not in the expected input format.

Multi-Part Operations

Mbed TLS PSA Crypto

Generic
void mbedtls_cipher_init(…)
Algorithm specific
void mbedtls_chacha20_init(…)

psa_cipher_operation_t psa_cipher_operation_init(void)

Generic
int mbedtls_cipher_setup(…)
int mbedtls_cipher_setkey(…)
Algorithm specific
int mbedtls_chacha20_setkey(…)

psa_status_t psa_cipher_encrypt_setup(…)

Generic
int mbedtls_cipher_set_iv(…)
Algorithm specific
int mbedtls_chacha20_starts(…)

psa_status_t psa_cipher_generate_iv(…)

Generic
int mbedtls_cipher_setup(…)
int mbedtls_cipher_setkey(…)
Algorithm specific
int mbedtls_chacha20_setkey(…)

psa_status_t psa_cipher_decrypt_setup(…)

Generic
int mbedtls_cipher_set_iv(…)
Algorithm specific
int mbedtls_chacha20_starts(…)

psa_status_t psa_cipher_set_iv(…)

Generic
int mbedtls_cipher_update(…)
Algorithm specific
int mbedtls_chacha20_update(…)

psa_status_t psa_cipher_update(…)

int mbedtls_cipher_finish(…)

psa_status_t psa_cipher_finish(…)

Generic
void mbedtls_cipher_free(…)
Algorithm specific
int mbedtls_chacha20_free(…)

psa_status_t psa_cipher_abort(…)

Note: The following situations require the use of a multi-part operation:

  • Processing messages that cannot be assembled in memory.

  • Using a deterministic initialization vector (IV) for unauthenticated encryption.

  • Providing the IV separately for unauthenticated encryption or decryption.

Quick Reference Examples

AES ECB (One-shot)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t aes_ecb_key[] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
  };
  uint8_t plain_msg_buf[] = {
    0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
  };
  uint8_t cipher_buf[16];
  size_t out_len;

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;
  psa_cipher_operation_t cipher_op;

  ret = psa_crypto_init();

  // Set up attributes for a AES ECB key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
  psa_set_key_algorithm(&key_attr, PSA_ALG_ECB_NO_PADDING);

  // Import a volatile plain key for AES ECB
  ret = psa_import_key(&key_attr, aes_ecb_key, sizeof(aes_ecb_key), &key_id);
  
  // AES ECB encryption and decryption
  // Expected ciphertext: 69 c4 e0 d8 6a 7b 04 30 d8 cd b7 80 70 b4 c5 5a
  // Single-part
  ret = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING,
                          plain_msg_buf, sizeof(plain_msg_buf),
                          cipher_buf, sizeof(cipher_buf), &out_len);

  ret = psa_cipher_decrypt(key_id, PSA_ALG_ECB_NO_PADDING,
                          cipher_buf, out_len,
                          plain_msg_buf, sizeof(plain_msg_buf), &out_len);

  // Multi-part
  cipher_op = psa_cipher_operation_init();
  ret = psa_cipher_encrypt_setup(&cipher_op, key_id, PSA_ALG_ECB_NO_PADDING);
  ret = psa_cipher_update(&cipher_op, plain_msg_buf, sizeof(plain_msg_buf),
                          cipher_buf, sizeof(cipher_buf), &out_len);

  ret = psa_cipher_finish(&cipher_op,
                          cipher_buf + out_len,
                          sizeof(cipher_buf) - out_len,
                          &out_len);

  cipher_op = psa_cipher_operation_init();
  ret = psa_cipher_decrypt_setup(&cipher_op, key_id, PSA_ALG_ECB_NO_PADDING);
  ret = psa_cipher_update(&cipher_op, cipher_buf, sizeof(cipher_buf),
                          plain_msg_buf, sizeof(plain_msg_buf), &out_len);

  ret = psa_cipher_finish(&cipher_op,
                          plain_msg_buf + out_len,
                          sizeof(plain_msg_buf) - out_len,
                          &out_len);

  // Destroy a volatile plain key for AES ECB
  ret = psa_destroy_key(key_id);
}

AES CFB (One-shot)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t aes_cbc_key[] = {
    0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
  };
  uint8_t iv_buf[] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
  };
  uint8_t plain_msg_buf[] = {
    0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a
  };
  uint8_t cipher_buf[32]; // Random IV + Ciphertext for single-part
  size_t out_len;

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;
  psa_cipher_operation_t cipher_op;

  ret = psa_crypto_init();

  // Set up attributes for a AES CBC key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
  psa_set_key_algorithm(&key_attr, PSA_ALG_CBC_NO_PADDING);

  // Import a volatile plain key for AES CBC
  ret = psa_import_key(&key_attr, aes_cbc_key, sizeof(aes_cbc_key), &key_id);

  // AES CBC encryption and decryption
  // Single-part - Random IV generated during encryption is embedded in the ciphertext buffer
  ret = psa_cipher_encrypt(key_id, PSA_ALG_CBC_NO_PADDING,
                          plain_msg_buf, sizeof(plain_msg_buf),
                          cipher_buf, sizeof(cipher_buf), &out_len);

  ret = psa_cipher_decrypt(key_id, PSA_ALG_CBC_NO_PADDING,
                          cipher_buf, out_len,
                          plain_msg_buf, sizeof(plain_msg_buf), &out_len);

  // Multi-part
  // Expected ciphertext: 76 49 ab ac 81 19 b2 46 ce e9 8e 9b 12 e9 19 7d
  cipher_op = psa_cipher_operation_init();
  ret = psa_cipher_encrypt_setup(&cipher_op, key_id, PSA_ALG_CBC_NO_PADDING);
  ret = psa_cipher_set_iv(&cipher_op, iv_buf, sizeof(iv_buf));
  ret = psa_cipher_update(&cipher_op,
                          plain_msg_buf, sizeof(plain_msg_buf),
                          cipher_buf, sizeof(cipher_buf),
                          &out_len);
  ret = psa_cipher_finish(&cipher_op,
                          cipher_buf + out_len,
                          sizeof(cipher_buf) - out_len,
                          &out_len);

  cipher_op = psa_cipher_operation_init();
  ret = psa_cipher_decrypt_setup(&cipher_op, key_id, PSA_ALG_CBC_NO_PADDING);
  ret = psa_cipher_set_iv(&cipher_op, iv_buf, sizeof(iv_buf));
  ret = psa_cipher_update(&cipher_op,
                          cipher_buf, sizeof(plain_msg_buf),
                          plain_msg_buf, sizeof(plain_msg_buf),
                          &out_len);
  ret = psa_cipher_finish(&cipher_op,
                          plain_msg_buf + out_len,
                          sizeof(plain_msg_buf) - out_len,
                          &out_len);

  // Destroy a volatile plain key for AES CBC
  ret = psa_destroy_key(key_id);
}

Note: The multi-part operations provide the IV separately for AES CFB encryption or decryption.

AES CTR (One-shot)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t aes_ctr_key[] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  };
  uint8_t iv_buf[] = {
    0x22, 0x22, 0x1a, 0x70, 0x22, 0x22, 0x1a, 0x70, 0x22, 0x22, 0x1a, 0x70, 0x22, 0x22, 0x1a, 0x70
  };
  uint8_t plain_msg_buf[] = {
    0xd8, 0x65, 0xc9, 0xcd, 0xea, 0x33, 0x56, 0xc5, 0x48, 0x8e, 0x7b, 0xa1, 0x5e, 0x84, 0xf4, 0xeb,
    0xa3, 0xb8, 0x25, 0x9c, 0x05, 0x3f, 0x24, 0xce, 0x29, 0x67, 0x22, 0x1c, 0x00, 0x38, 0x84, 0xd7,
    0x9d, 0x4c, 0xa4, 0x87, 0x7f, 0xfa, 0x4b, 0xc6, 0x87, 0xc6, 0x67, 0xe5, 0x49, 0x5b, 0xcf, 0xec,
    0x12, 0xf4, 0x87, 0x17, 0x32, 0xaa, 0xe4, 0x5a, 0x11, 0x06, 0x76, 0x11, 0x3d, 0xf9, 0xe7, 0xda
  };
  uint8_t cipher_buf[80]; // Random IV + Ciphertext for single-part
  size_t out_len;

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;
  psa_cipher_operation_t cipher_op;

  ret = psa_crypto_init();

  // Set up attributes for a AES CTR key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
  psa_set_key_algorithm(&key_attr, PSA_ALG_CTR);

  // Import a volatile plain key for AES CTR
  ret = psa_import_key(&key_attr, aes_ctr_key, sizeof(aes_ctr_key), &key_id);

  // AES CTR encryption and decryption
  // Single-part - Random IV generated during encryption is embedded in the ciphertext buffer
  ret = psa_cipher_encrypt(key_id, PSA_ALG_CTR,
                          plain_msg_buf, sizeof(plain_msg_buf),
                          cipher_buf, sizeof(cipher_buf), &out_len);

  ret = psa_cipher_decrypt(key_id, PSA_ALG_CTR,
                          cipher_buf, out_len,
                          plain_msg_buf, sizeof(plain_msg_buf), &out_len);
  // Multi-part
  // Expected ciphertext:
  // b6 72 f2 af 6a cc 20 ae ee 1a d8 14 12 8c 31 8b 95 5b be 80 5b 38 92 49 89 76 00 f5 20 74 54 32
  // 7d 6d 0f b4 ac 0a 94 f3 7c a0 9e 45 05 33 98 fe a8 9c 20 0a d3 58 12 6d 9e 89 a4 05 26 5c 96 e7
  cipher_op = psa_cipher_operation_init();
  ret = psa_cipher_encrypt_setup(&cipher_op, key_id, PSA_ALG_CTR);
  ret = psa_cipher_set_iv(&cipher_op, iv_buf, sizeof(iv_buf));
  ret = psa_cipher_update(&cipher_op,
                          plain_msg_buf, sizeof(plain_msg_buf),
                          cipher_buf, sizeof(cipher_buf),
                          &out_len);
  ret = psa_cipher_finish(&cipher_op,
                          cipher_buf + out_len,
                          sizeof(cipher_buf) - out_len,
                          &out_len);

  cipher_op = psa_cipher_operation_init();
  ret = psa_cipher_decrypt_setup(&cipher_op, key_id, PSA_ALG_CTR);
  ret = psa_cipher_set_iv(&cipher_op, iv_buf, sizeof(iv_buf));
  ret = psa_cipher_update(&cipher_op,
                          cipher_buf, sizeof(plain_msg_buf),
                          plain_msg_buf, sizeof(plain_msg_buf),
                          &out_len);
  ret = psa_cipher_finish(&cipher_op,
                          plain_msg_buf + out_len,
                          sizeof(plain_msg_buf) - out_len,
                          &out_len);
  // Destroy a volatile plain key for AES CTR
  ret = psa_destroy_key(key_id);
}

Note: The multi-part operations provide the IV separately for AES CTR encryption or decryption.

CHACHA20 (One-shot)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t chacha20_key[32] = {0};
  uint8_t iv_buf[12] = {0};
  uint8_t plain_msg_buf[64] = {0};
  uint8_t cipher_buf[76];         // Random IV + Ciphertext for single-part
  size_t out_len;

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;
  psa_cipher_operation_t cipher_op;

  ret = psa_crypto_init();

  // Set up attributes for a CHACHA20 key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_CHACHA20);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
  psa_set_key_algorithm(&key_attr, PSA_ALG_STREAM_CIPHER);

  // Import a volatile plain key for CHACHA20
  ret = psa_import_key(&key_attr, chacha20_key, sizeof(chacha20_key), &key_id);

  // CHACHA20 encryption and decryption
  // Single-part - Random IV generated during encryption is embedded in the ciphertext buffer
  ret = psa_cipher_encrypt(key_id, PSA_ALG_STREAM_CIPHER,
                          plain_msg_buf, sizeof(plain_msg_buf),
                          cipher_buf, sizeof(cipher_buf), &out_len);

  ret = psa_cipher_decrypt(key_id, PSA_ALG_STREAM_CIPHER,
                          cipher_buf, out_len,
                          plain_msg_buf, sizeof(plain_msg_buf), &out_len);

  // Multi-part
  // Expected ciphertext:
  // 76 b8 e0 ad a0 f1 3d 90 40 5d 6a e5 53 86 bd 28 bd d2 19 b8 a0 8d ed 1a a8 36 ef cc 8b 77 0d c7
  // da 41 59 7c 51 57 48 8d 77 24 e0 3f b8 d8 4a 37 6a 43 b8 f4 15 18 a1 1c c3 87 b6 69 b2 ee 65 86
  cipher_op = psa_cipher_operation_init();
  ret = psa_cipher_encrypt_setup(&cipher_op, key_id, PSA_ALG_STREAM_CIPHER);
  ret = psa_cipher_set_iv(&cipher_op, iv_buf, sizeof(iv_buf));
  ret = psa_cipher_update(&cipher_op,
                          plain_msg_buf, sizeof(plain_msg_buf),
                          cipher_buf, sizeof(cipher_buf),
                          &out_len);
  ret = psa_cipher_finish(&cipher_op,
                          cipher_buf + out_len,
                          sizeof(cipher_buf) - out_len,
                          &out_len);

  cipher_op = psa_cipher_operation_init();
  ret = psa_cipher_decrypt_setup(&cipher_op, key_id, PSA_ALG_STREAM_CIPHER);
  ret = psa_cipher_set_iv(&cipher_op, iv_buf, sizeof(iv_buf));
  ret = psa_cipher_update(&cipher_op,
                          cipher_buf, sizeof(plain_msg_buf),
                          plain_msg_buf, sizeof(plain_msg_buf),
                          &out_len);
  ret = psa_cipher_finish(&cipher_op,
                          plain_msg_buf + out_len,
                          sizeof(plain_msg_buf) - out_len,
                          &out_len);

  // Destroy a volatile plain key for CHACHA20
  ret = psa_destroy_key(key_id);
}

Note: The multi-part operations provide the IV separately for CHACHA20 encryption or decryption.

AES CTR (Streaming)

#include "psa/crypto.h"

void app_process_action(void)
{
 uint8_t aes_ctr_key[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 };
 uint8_t iv_buf[] = {
   0x22, 0x22, 0x1a, 0x70, 0x22, 0x22, 0x1a, 0x70, 0x22, 0x22, 0x1a, 0x70, 0x22, 0x22, 0x1a, 0x70
 };
 uint8_t plain_msg_buf[] = {
  0xd8, 0x65, 0xc9, 0xcd, 0xea, 0x33, 0x56, 0xc5, 0x48, 0x8e, 0x7b, 0xa1, 0x5e, 0x84, 0xf4, 0xeb,
  0xa3, 0xb8, 0x25, 0x9c, 0x05, 0x3f, 0x24, 0xce, 0x29, 0x67, 0x22, 0x1c, 0x00, 0x38, 0x84, 0xd7,
  0x9d, 0x4c, 0xa4, 0x87, 0x7f, 0xfa, 0x4b, 0xc6, 0x87, 0xc6, 0x67, 0xe5, 0x49, 0x5b, 0xcf, 0xec,
  0x12, 0xf4, 0x87, 0x17, 0x32, 0xaa, 0xe4, 0x5a, 0x11, 0x06, 0x76, 0x11, 0x3d, 0xf9, 0xe7, 0xda
 };
 uint8_t cipher_buf[64];
 size_t out_len;
 uint32_t out_total;
 uint32_t stream_block_size = 14;                 // Block size for streaming

 psa_status_t ret;
 psa_key_id_t key_id;
 psa_key_attributes_t key_attr;
 psa_cipher_operation_t cipher_op;

 ret = psa_crypto_init();

 // Set up attributes for a AES CTR key
 key_attr = psa_key_attributes_init();
 psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
 psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
 psa_set_key_algorithm(&key_attr, PSA_ALG_CTR);

 // Import a volatile plain key for AES CTR
 ret = psa_import_key(&key_attr, aes_ctr_key, sizeof(aes_ctr_key), &key_id);

 // AES CTR stream encryption and decryption
 // Expected ciphertext:
 // b6 72 f2 af 6a cc 20 ae ee 1a d8 14 12 8c 31 8b 95 5b be 80 5b 38 92 49 89 76 00 f5 20 74 54 32
 // 7d 6d 0f b4 ac 0a 94 f3 7c a0 9e 45 05 33 98 fe a8 9c 20 0a d3 58 12 6d 9e 89 a4 05 26 5c 96 e7
 cipher_op = psa_cipher_operation_init();
 ret = psa_cipher_encrypt_setup(&cipher_op, key_id, PSA_ALG_CTR);
 ret = psa_cipher_set_iv(&cipher_op, iv_buf, sizeof(iv_buf));

 out_total = 0; // Streaming block
 while ((sizeof(plain_msg_buf) - out_total) > stream_block_size) {
   ret = psa_cipher_update(&cipher_op,
                            plain_msg_buf + out_total, stream_block_size,
                            cipher_buf + out_total, sizeof(cipher_buf) - out_total,
                            &out_len);
  out_total += out_len;
 }
  ret = psa_cipher_update(&cipher_op, // Last block
                          plain_msg_buf + out_total, sizeof(plain_msg_buf) - out_total,
                          cipher_buf + out_total, sizeof(cipher_buf) - out_total,
                          &out_len);
  out_total += out_len;

 ret = psa_cipher_finish(&cipher_op,
                        cipher_buf + out_total,
                        sizeof(cipher_buf) - out_total,
                        &out_len);

 cipher_op = psa_cipher_operation_init();
 ret = psa_cipher_decrypt_setup(&cipher_op, key_id, PSA_ALG_CTR);
 ret = psa_cipher_set_iv(&cipher_op, iv_buf, sizeof(iv_buf));

 out_total = 0; // Streaming block
 while ((sizeof(cipher_buf) - out_total) > stream_block_size) {
  ret = psa_cipher_update(&cipher_op,
                          cipher_buf + out_total, stream_block_size,
                          plain_msg_buf + out_total, sizeof(plain_msg_buf) - out_total,
                          &out_len);
  out_total += out_len;
 }

  ret = psa_cipher_update(&cipher_op, // Last block
                          cipher_buf + out_total, sizeof(cipher_buf) - out_total,
                          plain_msg_buf + out_total, sizeof(plain_msg_buf) - out_total,
                          &out_len);
  out_total += out_len;

  ret = psa_cipher_finish(&cipher_op,
                          plain_msg_buf + out_total,
                          sizeof(plain_msg_buf) - out_total,
                          &out_len);

 // Destroy a volatile plain key for AES CTR
 ret = psa_destroy_key(key_id);
}

AES CTR with Built-in AES-128 Key (HSE only)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t iv_buf[16] = {0};
  uint8_t plain_msg_buf[16] = {0};
  uint8_t cipher_buf[32]; // Random IV + Ciphertext for single-part
  size_t out_len;

  psa_status_t ret;
  psa_cipher_operation_t cipher_op;

  ret = psa_crypto_init();

  // AES CTR encryption and decryption with built-in AES-128 key
  // ret = -140 (PSA_ERROR_DOES_NOT_EXIST) if the AES-128 key has not been provisioned
  // Single-part - Random IV generated during encryption is embedded in the ciphertext buffer
  ret = psa_cipher_encrypt(SL_SE_BUILTIN_KEY_AES128_ID, PSA_ALG_CTR,
                          plain_msg_buf, sizeof(plain_msg_buf),
                          cipher_buf, sizeof(cipher_buf), &out_len);

  ret = psa_cipher_decrypt(SL_SE_BUILTIN_KEY_AES128_ID, PSA_ALG_CTR,
                          cipher_buf, out_len,
                          plain_msg_buf, sizeof(plain_msg_buf), &out_len);

  // Multi-part
  // Built-in AES-128 key: 81 a5 e2 1f a1 52 86 f1 df 44 5c 2c c1 20 fa 3f
  // Expected ciphertext: 66 d2 0f 99 65 3e a8 d0 83 05 a6 39 d4 4e 98 a6
  cipher_op = psa_cipher_operation_init();
  ret = psa_cipher_encrypt_setup(&cipher_op, SL_SE_BUILTIN_KEY_AES128_ID, PSA_ALG_CTR);
  ret = psa_cipher_set_iv(&cipher_op, iv_buf, sizeof(iv_buf));
  ret = psa_cipher_update(&cipher_op,
                          plain_msg_buf, sizeof(plain_msg_buf),
                          cipher_buf, sizeof(cipher_buf),
                          &out_len);
  ret = psa_cipher_finish(&cipher_op,
                          cipher_buf + out_len,
                          sizeof(cipher_buf) - out_len,
                          &out_len);

  cipher_op = psa_cipher_operation_init();
  ret = psa_cipher_decrypt_setup(&cipher_op, SL_SE_BUILTIN_KEY_AES128_ID, PSA_ALG_CTR);
  ret = psa_cipher_set_iv(&cipher_op, iv_buf, sizeof(iv_buf));
  ret = psa_cipher_update(&cipher_op,
                          cipher_buf, sizeof(plain_msg_buf),
                          plain_msg_buf, sizeof(plain_msg_buf),
                          &out_len);
  ret = psa_cipher_finish(&cipher_op,
                          plain_msg_buf + out_len,
                          sizeof(plain_msg_buf) - out_len,
                          &out_len);
}

PSA Crypto Platform Example

Click the View Project Documentation link to open the readme file.

image25image25

The following table describes the implementation status of the PSA Crypto cipher platform example.

Algorithm/Key

Series 1

Series 2 - VSE

Series 2 - HSE

Remark

AES ECB

Y

Y

Y

Series 1 devices do not support a 192-bit key.

AES CBC

Y

Y

Y

Series 1 devices do not support a 192-bit key.

AES CFB

Y

Y

Y

Series 1 devices do not support a 192-bit key.

AES CTR

Y

Y

Y

Series 1 devices do not support a 192-bit key.

CHACHA20

Y

Y

Y

Hardware acceleration only on HSE-SVH devices.

AES-128 Key

Y

Note: The single-part unauthenticated cipher functions are only available on GSDK v4.0.0 and higher.

Authenticated Encryption with Associated Data (AEAD)#

The authenticated encryption with associated data (AEAD) is a form of encryption that simultaneously assures the confidentiality and authenticity of data.

Algorithms

Algorithm Mbed TLS PSA Crypto

AES GCM

• MBEDTLS_CIPHER_AES_128_GCM
• MBEDTLS_CIPHER_AES_192_GCM
• MBEDTLS_CIPHER_AES_256_GCM

• PSA_ALG_GCM
• PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, tag_length)
• PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(PSA_ALG_GCM)
• PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_GCM, min_tag_length)

AES CCM

• MBEDTLS_CIPHER_AES_128_CCM
• MBEDTLS_CIPHER_AES_192_CCM
• MBEDTLS_CIPHER_AES_256_CCM

• PSA_ALG_CCM
• PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length)
• PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(PSA_ALG_CCM)
• PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, min_tag_length)

CHACHA20_POLY1305

MBEDTLS_CIPHER_CHACHA20_POLY1305

PSA_ALG_CHACHA20_POLY1305

Algorithm

Nonce Length (Bytes)

Authentication Tag Length (Bytes)

AES GCM

1 - 16 (Default 12)

4, 8, 12, 13, 14, 15, and 16 (Default)

AES CCM

7 - 13

4, 6, 8, 10, 12, 14, and 16 (Default)

CHACHA20_POLY1305

12

16

Key Attributes in PSA Crypto

Algorithm Key Type Key Size in Bits Key Usage Flag
PSA_ALG_GCM or
PSA_ALG_AEAD_WITH_*(PSA_ALG_GCM…)
PSA_KEY_TYPE_AES 128 (16-byte)
192 (24-byte)
256 (32-byte)
PSA_KEY_USAGE_ENCRYPT
PSA_KEY_USAGE_DECRYPT
PSA_ALG_CCM or
PSA_ALG_AEAD_WITH_*(PSA_ALG_CCM…)
PSA_ALG_CHACHA20_POLY1305 PSA_KEY_TYPE_CHACHA20 256 (32-byte)

Security Software Components

Algorithm

Security Software Components

PSA_ALG_GCM or PSA_ALG_AEAD_WITH_*(PSA_ALG_GCM…)

GCM (12-byte IV) or GCM with Non-Recommended IV Lengths

PSA_ALG_CCM or PSA_ALG_AEAD_WITH_*(PSA_ALG_CCM…)

CCM Mode

PSA_ALG_CHACHA20_POLY1305

ChachaPoly

Single-Part Functions

Mbed TLS PSA Crypto

Generic
int mbedtls_cipher_auth_encrypt(…)
Algorithm specific
int mbedtls_ccm_encrypt_and_tag(…)
int mbedtls_gcm_crypt_and_tag(…)
int mbedtls_chachapoly_encrypt_and_tag(…)

psa_status_t psa_aead_encrypt(…)

Generic
int mbedtls_cipher_auth_decrypt(…)
Algorithm specific
int mbedtls_ccm_auth_decrypt(…)
int mbedtls_gcm_auth_decrypt(…)
int mbedtls_chachapoly_auth_decrypt(…)

psa_status_t psa_aead_decrypt(…)

Note: The single-part functions use one buffer for the ciphertext and AEAD authentication tag.

Multi-Part Operations

Mbed TLS PSA Crypto

Generic
void mbedtls_cipher_init(…)
Algorithm specific
void mbedtls_gcm_init(…)
void mbedtls_chachapoly_init(…)

psa_aead_operation_t psa_aead_operation_init(void)

Generic
int mbedtls_cipher_setup(…)
int mbedtls_cipher_setkey(…)
Algorithm specific
int mbedtls_gcm_setkey(…)
int mbedtls_chachapoly_setkey(…)

psa_status_t psa_aead_encrypt_setup(…)

Generic
int mbedtls_cipher_set_iv(…)
Algorithm specific
int mbedtls_gcm_starts(…)
int mbedtls_chachapoly_starts(…)

psa_status_t psa_aead_generate_nonce(…)

psa_status_t psa_aead_set_lengths(…)

Generic
int mbedtls_cipher_setup(…)
int mbedtls_cipher_setkey(…)
Algorithm specific
int mbedtls_gcm_setkey(…)
int mbedtls_chachapoly_setkey(…)

psa_status_t psa_aead_decrypt_setup(…)

Generic
int mbedtls_cipher_set_iv(…)
Algorithm specific
int mbedtls_gcm_starts(…)
int mbedtls_chachapoly_starts(…)

psa_status_t psa_aead_set_nonce(…)

Generic
int mbedtls_cipher_update_ad(…)
Algorithm specific
int mbedtls_gcm_starts(…)
int mbedtls_chachapoly_update_aad(…)

psa_status_t psa_aead_update_ad(…)

Generic
int mbedtls_cipher_update(…)
Algorithm specific
int mbedtls_gcm_update(…)
int mbedtls_chachapoly_update(…)

psa_status_t psa_aead_update(…)

Mbed TLS PSA Crypto

Generic
int mbedtls_cipher_finish(…)
Algorithm specific
int mbedtls_gcm_finish(…)
int mbedtls_chachapoly_finish(…)

psa_status_t psa_aead_finish(…)

psa_status_t psa_aead_verify(…)

Generic
void mbedtls_cipher_free(…)
Algorithm specific
int mbedtls_gcm_free(…)
int mbedtls_chachapoly_free(…)

psa_status_t psa_aead_abort(…)

Note:

  • For PSA_ALG_CCM, calling psa_aead_set_lengths() is required.

  • For the other AEAD algorithms, calling psa_aead_set_lengths() is not required.

  • The following situations require the use of a multi-part operation:

  • Processing messages that cannot be assembled in memory.

  • Separating the AEAD authentication tag from the ciphertext.

Quick Reference Examples

AES CCM (One-shot)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t key_buf[] = {
    0xea, 0x4f, 0x6f, 0x3c, 0x2f, 0xed, 0x2b, 0x9d, 0xd9, 0x70, 0x8c, 0x2e, 0x72, 0x1a, 0xe0, 0x0f
  };
  uint8_t nonce_buf[] = {0xf9, 0x75, 0x80, 0x9d, 0xdb, 0x51, 0x72, 0x38, 0x27, 0x45, 0x63, 0x4f};
  uint8_t ad_buf[] = {0x5c, 0x65, 0xd4, 0xf2, 0x61, 0xd2, 0xc5, 0x4f, 0xfe, 0x6a};
  uint8_t plain_msg_buf[] = {0x8d, 0x6c, 0x08, 0x44, 0x6c, 0xb1, 0x0d, 0x9a, 0x20, 0x75};
  uint8_t cipher_tag_buf[32];       // Ciphertext + Tag
  size_t out_len;

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;

  ret = psa_crypto_init();

  // Set up attributes for a AES CCM key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
  psa_set_key_algorithm(&key_attr, PSA_ALG_CCM);

  // Import a volatile plain key for AES CCM
  ret = psa_import_key(&key_attr, key_buf, sizeof(key_buf), &key_id);

  // AES CCM encryption and descryption
  // Expected ciphertext: e2 2f 37 3b eb f6 4a 3e 9b 87
  // Expected tag: 75 2b f9 db 34 dc 4d 43 3f 00 f5 5c 3f 53 0c 89
  ret = psa_aead_encrypt(key_id, PSA_ALG_CCM,
                        nonce_buf, sizeof(nonce_buf),
                        ad_buf, sizeof(ad_buf),
                        plain_msg_buf, sizeof(plain_msg_buf),
                        cipher_tag_buf, sizeof(cipher_tag_buf),
                        &out_len);
  ret = psa_aead_decrypt(key_id, PSA_ALG_CCM,
                        nonce_buf, sizeof(nonce_buf),
                        ad_buf, sizeof(ad_buf),
                        cipher_tag_buf, out_len,
                        plain_msg_buf, sizeof(plain_msg_buf),
                        &out_len);

  // Destroy a volatile plain key for AES CCM
  ret = psa_destroy_key(key_id);
}

Notes:

  • There are two ways to change the CCM authentication tag length (default 16 bytes).

    1. Replace all AEAD algorithm PSA_ALG_CCM with PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length) for the desired size of the authentication tag in bytes.

    2. Replace the AEAD algorithm PSA_ALG_CCM in the psa_set_key_algorithm(&key_attr, PSA_ALG_CCM) function with PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, min_tag_length) to set the minimum authentication tag length in bytes. Replace the AEAD algorithm PSA_ALG_CCM in psa_aead_encrypt() and psa_aead_decrypt() with PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length) to set the desired tag length (≥ min_tag_length and ≤ PSA_AEAD_TAG_LENGTH(PSA_KEY_TYPE_AES, 256, PSA_ALG_CCM)) in bytes.

AES GCM (One-shot)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t key_buf[] = {
    0xea, 0x4f, 0x6f, 0x3c, 0x2f, 0xed, 0x2b, 0x9d, 0xd9, 0x70, 0x8c, 0x2e, 0x72, 0x1a, 0xe0, 0x0f
  };
  uint8_t nonce_buf[] = {0xf9, 0x75, 0x80, 0x9d, 0xdb, 0x51, 0x72, 0x38, 0x27, 0x45, 0x63, 0x4f};
  uint8_t ad_buf[] = {0x5c, 0x65, 0xd4, 0xf2, 0x61, 0xd2, 0xc5, 0x4f, 0xfe, 0x6a};
  uint8_t plain_msg_buf[] = {0x8d, 0x6c, 0x08, 0x44, 0x6c, 0xb1, 0x0d, 0x9a, 0x20, 0x75};
  uint8_t cipher_tag_buf[32]; // Ciphertext + Tag
  size_t out_len;

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;

  ret = psa_crypto_init();

  // Set up attributes for a AES GCM key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
  psa_set_key_algorithm(&key_attr, PSA_ALG_GCM);

  // Import a volatile plain key for AES GCM
  ret = psa_import_key(&key_attr, key_buf, sizeof(key_buf), &key_id);

  // AES GCM encryption and decryption
  // Expected ciphertext: 0f 51 f7 a8 3c 5b 5a a7 96 b9
  // Expected tag: 70 25 9c dd fe 8f 9a 15 a5 c5 eb 48 5a f5 78 fb
  ret = psa_aead_encrypt(key_id, PSA_ALG_GCM,
                          nonce_buf, sizeof(nonce_buf),
                          ad_buf, sizeof(ad_buf),
                          plain_msg_buf, sizeof(plain_msg_buf),
                          cipher_tag_buf, sizeof(cipher_tag_buf),
                          &out_len);

  ret = psa_aead_decrypt(key_id, PSA_ALG_GCM,
                          nonce_buf, sizeof(nonce_buf),
                          ad_buf, sizeof(ad_buf),
                          cipher_tag_buf, out_len,
                          plain_msg_buf, sizeof(plain_msg_buf),
                          &out_len);
                          
  // Destroy a volatile plain key for AES GCM
  ret = psa_destroy_key(key_id);
}

Notes:

  • There are two ways to change the GCM authentication tag length (default 16 bytes).

    1. Replace all AEAD algorithm PSA_ALG_GCM with PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, tag_length) for the desired size of the authentication tag in bytes.

    2. Replace the AEAD algorithm PSA_ALG_GCM in the psa_set_key_algorithm(&key_attr, PSA_ALG_GCM) function with PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_GCM, min_tag_length) to set the minimum authentication tag length in bytes. Replace the AEAD algorithm PSA_ALG_GCM in psa_aead_encrypt() and psa_aead_decrypt() with PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, tag_length) to set the desired tag length (≥ min_tag_length and ≤ PSA_AEAD_TAG_LENGTH(PSA_KEY_TYPE_AES, 256, PSA_ALG_GCM)) in bytes.

CHACHA20_POLY1305 (One-shot)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t key_buf[] = {
    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
  };
  uint8_t nonce_buf[] = {0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47};
  uint8_t ad_buf[] = {0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7};
  uint8_t plain_msg_buf[] = {
    0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
    0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
    0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
    0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
    0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
    0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
    0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
    0x74, 0x2e
  };
  uint8_t cipher_tag_buf[130]; // Ciphertext + Tag
  size_t out_len;

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;
  
  ret = psa_crypto_init();

  // Set up attributes for a CHACHA20_POLY1305 key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_CHACHA20);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
  psa_set_key_algorithm(&key_attr, PSA_ALG_CHACHA20_POLY1305);

  // Import a volatile plain key for CHACHA20_POLY1305
  ret = psa_import_key(&key_attr, key_buf, sizeof(key_buf), &key_id);

  // CHACHA20_POLY1305 encryption
  // Expected ciphertext:
  // d3 1a 8d 34 64 8e 60 db 7b 86 af bc 53 ef 7e c2 a4 ad ed 51 29 6e 08 fe a9 e2 b5 a7 36 ee 62 d6
  // 3d be a4 5e 8c a9 67 12 82 fa fb 69 da 92 72 8b 1a 71 de 0a 9e 06 0b 29 05 d6 a5 b6 7e cd 3b 36
  // 92 dd bd 7f 2d 77 8b 8c 98 03 ae e3 28 09 1b 58 fa b3 24 e4 fa d6 75 94 55 85 80 8b 48 31 d7 bc
  // 3f f4 de f0 8e 4b 7a 9d e5 76 d2 65 86 ce c6 4b 61 16
  // Expected tag: 1a e1 0b 59 4f 09 e2 6a 7e 90 2e cb d0 60 06 91
  ret = psa_aead_encrypt(key_id,
                        PSA_ALG_CHACHA20_POLY1305,
                        nonce_buf,
                        sizeof(nonce_buf),
                        ad_buf,
                        sizeof(ad_buf),
                        plain_msg_buf,
                        sizeof(plain_msg_buf),
                        cipher_tag_buf,
                        sizeof(cipher_tag_buf),
                        &out_len);

  // CHACHA20_POLY1305 decryption
  ret = psa_aead_decrypt(key_id,
                        PSA_ALG_CHACHA20_POLY1305,
                        nonce_buf,
                        sizeof(nonce_buf),
                        ad_buf,
                        sizeof(ad_buf),
                        cipher_tag_buf,
                        out_len,
                        plain_msg_buf,
                        sizeof(plain_msg_buf),
                        &out_len);

  // Destroy a volatile plain key for CHACHA20_POLY1305
  ret = psa_destroy_key(key_id);
}

AES CCM (Streaming)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t key_buf[] = {
    0x9c, 0xde, 0xba, 0xee, 0xe8, 0x69, 0x0b, 0x68, 0x75, 0x10, 0x70, 0x69, 0x1f, 0x49, 0x59, 0x36,
    0x68, 0xa6, 0xde, 0x12, 0xd3, 0xa9, 0x48, 0xb3, 0x8d, 0xdb, 0xd3, 0xf7, 0x52, 0x18, 0xb2, 0xd4
  };
  uint8_t nonce_buf[] = {0xaf, 0x1a, 0x97, 0xd4, 0x31, 0x51, 0xf5, 0xea, 0x9c, 0x48, 0xad, 0x36, 0xa3};
  uint8_t ad_buf[] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x10, 0x11, 0x12, 0x13
  };
  uint8_t plain_msg_buf[] = {
    0x3c, 0xbb, 0x08, 0xf1, 0x33, 0x27, 0x0e, 0x44, 0x54, 0xbc, 0xaa, 0xa0, 0xf2, 0x0f, 0x6d, 0x63,
    0xc3, 0x8b, 0x65, 0x72, 0xe7, 0x66
  };
  uint8_t cipher_buf[22];
  uint8_t tag_buf[16];
  size_t tag_len;
  size_t out_len;
  uint32_t out_total;
  uint32_t stream_cnt;
  uint32_t stream_block_size = 14;                      // Block size for streaming

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;
  psa_aead_operation_t aead_op;

  ret = psa_crypto_init();

  // Set up attributes for a AES CCM key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
  psa_set_key_algorithm(&key_attr, PSA_ALG_CCM);

  // Import a volatile plain key for AES CCM
  ret = psa_import_key(&key_attr, key_buf, sizeof(key_buf), &key_id);

  // AES CCM stream encryption and decryption
  // Expected ciphertext:
  // 39 66 93 0a 2a e8 fd d8 f4 0e 70 07 f3 fd e0 bd 6e b4 8a 46 e6 d2
  // Expected tag: 7c 0c 1b a4 bf d2 bd 21 5b 0c d9 21 f0 6a 8f 3b
  aead_op = psa_aead_operation_init();
  ret = psa_aead_encrypt_setup(&aead_op, key_id, PSA_ALG_CCM);
  ret = psa_aead_set_lengths(&aead_op, sizeof(ad_buf), sizeof(plain_msg_buf));
  ret = psa_aead_set_nonce(&aead_op, nonce_buf, sizeof(nonce_buf));
  ret = psa_aead_update_ad(&aead_op, ad_buf, sizeof(ad_buf));

  stream_cnt = 0;                                             // Streaming block
  out_total = 0;
  while ((sizeof(plain_msg_buf) - (stream_cnt * stream_block_size)) > stream_block_size) {
    ret = psa_aead_update(&aead_op,
                          plain_msg_buf + (stream_cnt * stream_block_size), stream_block_size,
                          cipher_buf + out_total, sizeof(cipher_buf) - out_total,
                          &out_len);
                          stream_cnt++;
    out_total += out_len;
  }
    ret = psa_aead_update(&aead_op,                         // Last block
                          plain_msg_buf + (stream_cnt * stream_block_size),
                          sizeof(plain_msg_buf) - (stream_cnt * stream_block_size),
                          cipher_buf + out_total, sizeof(cipher_buf) - out_total,
                          &out_len);
    out_total += out_len;

    ret = psa_aead_finish(&aead_op,                         // Generate tag
                          cipher_buf + out_total, sizeof(cipher_buf) - out_total,
                          &out_len,
                          tag_buf, sizeof(tag_buf),
                          &tag_len);
  out_total += out_len;

  aead_op = psa_aead_operation_init();
  ret = psa_aead_decrypt_setup(&aead_op, key_id, PSA_ALG_CCM);
  ret = psa_aead_set_lengths(&aead_op, sizeof(ad_buf), sizeof(plain_msg_buf));
  ret = psa_aead_set_nonce(&aead_op, nonce_buf, sizeof(nonce_buf));
  ret = psa_aead_update_ad(&aead_op, ad_buf, sizeof(ad_buf));

  stream_cnt = 0;                                           // Streaming block
  out_total = 0;
  while ((sizeof(cipher_buf) - (stream_cnt * stream_block_size)) > stream_block_size) {
    ret = psa_aead_update(&aead_op,
                          cipher_buf + (stream_cnt * stream_block_size), stream_block_size,
                          plain_msg_buf + out_total, sizeof(plain_msg_buf) - out_total,
                          &out_len);
                          stream_cnt++;
    out_total += out_len;
  }

    ret = psa_aead_update(&aead_op,                           // Last block
                        cipher_buf + (stream_cnt * stream_block_size),
                        sizeof(cipher_buf) - (stream_cnt * stream_block_size),
                        plain_msg_buf + out_total, sizeof(plain_msg_buf) - out_total,
                        &out_len);
    out_total += out_len;
    ret = psa_aead_verify(&aead_op,                           // Verify tag
                          plain_msg_buf + out_total, sizeof(plain_msg_buf) - out_total,
                          &out_len,
                          tag_buf, sizeof(tag_buf));
    out_total += out_len;

    // Destroy a volatile plain key for AES CCM
    ret = psa_destroy_key(key_id);
}

AES GCM (Streaming)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t key_buf[] = {
    0x5f, 0xe0, 0x1c, 0x4b, 0xaf, 0x01, 0xcb, 0xe0, 0x77, 0x96, 0xd5, 0xaa, 0xef, 0x6e, 0xc1, 0xf4,
    0x51, 0x93, 0xa9, 0x8a, 0x22, 0x35, 0x94, 0xae, 0x4f, 0x0e, 0xf4, 0x95, 0x2e, 0x82, 0xe3, 0x30
  };
  uint8_t nonce_buf[] = {0xbd, 0x58, 0x73, 0x21, 0x56, 0x6c, 0x7f, 0x1a, 0x5d, 0xd8, 0x65, 0x2d};
  uint8_t ad_buf[] = {
    0x90, 0x13, 0x61, 0x78, 0x17, 0xdd, 0xa9, 0x47, 0xe1, 0x35, 0xee, 0x6d, 0xd3, 0x65, 0x33, 0x82
  };
  uint8_t plain_msg_buf[] = {
    0x88, 0x1d, 0xc6, 0xc7, 0xa5, 0xd4, 0x50, 0x9f, 0x3c, 0x4b, 0xd2, 0xda, 0xab, 0x08, 0xf1, 0x65,
    0xdd, 0xc2, 0x04, 0x48, 0x9a, 0xa8, 0x13, 0x45, 0x62, 0xa4, 0xea, 0xc3, 0xd0, 0xbc, 0xad, 0x79,
    0x65, 0x84, 0x7b, 0x10, 0x27, 0x33, 0xbb, 0x63, 0xd1, 0xe5, 0xc5, 0x98, 0xec, 0xe0, 0xc3, 0xe5,
    0xda, 0xdd, 0xdd
  };
  uint8_t cipher_buf[51];
  uint8_t tag_buf[16];
  size_t tag_len;
  size_t out_len;
  uint32_t out_total;
  uint32_t stream_cnt;
  uint32_t stream_block_size = 14;                              // Block size for streaming

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;
  psa_aead_operation_t aead_op;

  ret = psa_crypto_init();

  // Set up attributes for a AES GCM key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
  psa_set_key_algorithm(&key_attr, PSA_ALG_GCM);

  // Import a volatile plain key for AES GCM
  ret = psa_import_key(&key_attr, key_buf, sizeof(key_buf), &key_id);

  // AES GCM stream encryption and decryption
  // Expected ciphertext:
  // 16 e3 75 b4 97 3b 33 9d 3f 74 6c 1c 5a 56 8b c7 52 6e 90 9d df f1 e1 9c 95 c9 4a 6c cf f2 10 c9
  // a4 a4 06 79 de 57 60 c3 96 ac 0e 2c eb 12 34 f9 f5 fe 26
  // Expected tag: ab d3 d2 6d 65 a6 27 5f 7a 4f 56 b4 22 ac ab 49
  aead_op = psa_aead_operation_init();
  ret = psa_aead_encrypt_setup(&aead_op, key_id, PSA_ALG_GCM);
  ret = psa_aead_set_nonce(&aead_op, nonce_buf, sizeof(nonce_buf));
  ret = psa_aead_update_ad(&aead_op, ad_buf, sizeof(ad_buf));

  stream_cnt = 0; // Streaming block
  out_total = 0;
  while ((sizeof(plain_msg_buf) - (stream_cnt * stream_block_size)) > stream_block_size) {
    ret = psa_aead_update(&aead_op,
                          plain_msg_buf + (stream_cnt * stream_block_size), stream_block_size,
                          cipher_buf + out_total, sizeof(cipher_buf) - out_total,
                          &out_len);
                          stream_cnt++;
    out_total += out_len;
    }

    ret = psa_aead_update(&aead_op,                                     // Last block
                        plain_msg_buf + (stream_cnt * stream_block_size),
                        sizeof(plain_msg_buf) - (stream_cnt * stream_block_size),
                        cipher_buf + out_total, sizeof(cipher_buf) - out_total,
                        &out_len);
    out_total += out_len;

    ret = psa_aead_finish(&aead_op,                                       // Generate tag
                        cipher_buf + out_total, sizeof(cipher_buf) - out_total,
                        &out_len,
                        tag_buf, sizeof(tag_buf),
                        &tag_len);
    out_total += out_len;

  aead_op = psa_aead_operation_init();
  ret = psa_aead_decrypt_setup(&aead_op, key_id, PSA_ALG_GCM);
  ret = psa_aead_set_nonce(&aead_op, nonce_buf, sizeof(nonce_buf));
  ret = psa_aead_update_ad(&aead_op, ad_buf, sizeof(ad_buf));

  stream_cnt = 0;                                                       // Streaming block
  out_total = 0;
  while ((sizeof(cipher_buf) - (stream_cnt * stream_block_size)) > stream_block_size) {
    ret = psa_aead_update(&aead_op,
                          cipher_buf + (stream_cnt * stream_block_size), stream_block_size,
                          plain_msg_buf + out_total, sizeof(plain_msg_buf) - out_total,
                          &out_len);
                          stream_cnt++;
    out_total += out_len;
  }

    ret = psa_aead_update(&aead_op,                                         // Last block
                          cipher_buf + (stream_cnt * stream_block_size),
                          sizeof(cipher_buf) - (stream_cnt * stream_block_size),
                          plain_msg_buf + out_total, sizeof(plain_msg_buf) - out_total,
                          &out_len);
    out_total += out_len;

    ret = psa_aead_verify(&aead_op,                                         // Verify tag
                          plain_msg_buf + out_total, sizeof(plain_msg_buf) - out_total,
                          &out_len,
                          tag_buf, sizeof(tag_buf));
    out_total += out_len;

    // Destroy a volatile plain key for AES GCM
    ret = psa_destroy_key(key_id);
}

PSA Crypto Platform Example

Click the View Project Documentation link to open the readme file.

image26image26

The following table describes the implementation status of the PSA Crypto AEAD platform example.

Algorithm

Series 1

Series 2 - VSE

Series 2 - HSE

Remark

AES CCM

Y

Y

Y

Series 1 devices do not support a 192-bit key.

AES GCM

Y

Y

Y

Series 1 devices do not support a 192-bit key.

CHACHA20_POLY1305

Y

Y

Y

Hardware acceleration only on HSE-SVH devices.

Notes:

  • The AEAD platform example uses default nonce (12-byte for GCM) and tag length (16-byte for CCM and GCM).

  • The multi-part AEAD operations are only available on GSDK v4.2.0 and higher.

  • The multi-part AEAD operations for CHACHA20_POLY1305 are not yet implemented.

  • The multi-part AEAD operations for a shortened tag length (AES CCM and GCM) are not yet implemented.

  • The multi-part GCM operations do not support non-12-byte nonce (GCM with Non-Recommended IV Lengths).

  • The AEAD platform example for multi-part AEAD operations is pending for fully-featured multi-part AEAD drivers.

Key Derivation#

A Key Derivation Function (KDF) derives one or many secret keys from a secret value such as a master key, a password, or a pass-phrase using a pseudo-random function. The typical usage of a key derivation function is to use a secret, such as a password or an ECDH shared secret, and a salt to produce a symmetric key and initialization vector (IV) for use with AES.

Algorithms

Algorithm Mbed TLS PSA Crypto

HKDF (SHA-1)

MBEDTLS_MD_SHA1

PSA_ALG_HKDF(PSA_ALG_SHA_1)

HKDF (SHA-2)

MBEDTLS_MD_SHA224
MBEDTLS_MD_SHA256
MBEDTLS_MD_SHA384
MBEDTLS_MD_SHA512

PSA_ALG_HKDF(PSA_ALG_SHA_224)
PSA_ALG_HKDF(PSA_ALG_SHA_256)
PSA_ALG_HKDF(PSA_ALG_SHA_384)
PSA_ALG_HKDF(PSA_ALG_SHA_512)

PBKDF2 (SHA-1)

MBEDTLS_MD_SHA1

PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_1)

PBKDF2 (SHA-2)

MBEDTLS_MD_SHA224
MBEDTLS_MD_SHA256
MBEDTLS_MD_SHA384
MBEDTLS_MD_SHA512

PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_224)
PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256)
PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_384)
PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_512)

PBKDF2 CMAC

PSA_ALG_PBKDF2_AES_CMAC_PRF_128

ECDH + HKDF

PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(hash_alg))

Key Attributes in PSA Crypto

Algorithm

Key Type

Key Size in Bits

Key Usage Flag

- PSA_ALG_HKDF(PSA_ALG_SHA_1)

PSA_KEY_TYPE_DERIVE

Multiple of 8

PSA_KEY_USAGE_DERIVE

- PSA_ALG_HKDF(PSA_ALG_SHA_224)

- PSA_ALG_HKDF(PSA_ALG_SHA_256)

- PSA_ALG_HKDF(PSA_ALG_SHA_384)

- PSA_ALG_HKDF(PSA_ALG_SHA_512)

- PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_1)

- PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_224)

- PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256)

- PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_384)

- PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_512)

PSA_ALG_PBKDF2_AES_CMAC_PRF_128

Security Software Components

Algorithm

Security Software Components

PSA_ALG_HKDF(PSA_ALG_SHA_1)

HKDF and SHA-1

PSA_ALG_HKDF(PSA_ALG_SHA_224)

HKDF and SHA-224

PSA_ALG_HKDF(PSA_ALG_SHA_256)

HKDF and SHA-256

PSA_ALG_HKDF(PSA_ALG_SHA_384)

HKDF and SHA-384

PSA_ALG_HKDF(PSA_ALG_SHA_512)

HKDF and SHA-512

PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_1)

PBKDF2 and SHA-1

PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_224)

PBKDF2 and SHA-224

PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256)

PBKDF2 and SHA-256

PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_384)

PBKDF2 and SHA-384

PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_512)

PBKDF2 and SHA-512

PSA_ALG_PBKDF2_AES_CMAC_PRF_128

PBKDF2

PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(hash_alg))

ECDH and HKDF and SHA-X

Note:

  • It should add the components for the derived key algorithm to implement the HKDF. For example, it requires the CTR Mode component if the derived key algorithm is PSA_ALG_CTR.

  • Refer to Key Agreement (ECDH) to add the ECDH components to derive the shared secret for the ECDH + HKDF algorithm (PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(hash_alg))).

Single-Part Functions

Mbed TLS

PSA Crypto

int mbedtls_hkdf(…)

psa_status_t sl_psa_key_derivation_single_shot(…)

int mbedtls_pkcs5_pbkdf2_hmac(…)

psa_status_t sl_psa_key_derivation_single_shot(…)

Note: The sl_psa_key_derivation_single_shot(…) is a Silicon Labs custom API. It can only use on HSE-SVH devices.

Multi-Part Operations

Mbed TLS

PSA Crypto

psa_key_derivation_operation_t psa_key_derivation_operation_init(void)

psa_status_t psa_key_derivation_setup(…)

psa_status_t psa_key_derivation_get_capacity(…)

psa_status_t psa_key_derivation_set_capacity(…)

psa_status_t psa_key_derivation_input_bytes(…)

psa_status_t psa_key_derivation_input_key(…)

psa_status_t psa_key_derivation_output_bytes(…)

psa_status_t psa_key_derivation_output_key(…)

psa_status_t psa_key_derivation_abort(…)

Note: The multi-part operation allows the data to be processed for KDF in fragments instead of all at once.

Quick Reference Examples HKDF (SHA-256)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t hkdf_ikm[] = {
    0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
    0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
  };
  uint8_t hkdf_salt[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c};
  uint8_t hkdf_info[] = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9};
  uint8_t key_buf[32];
  size_t key_len;
  psa_status_t ret;
  psa_key_id_t master_key_id;
  psa_key_id_t hkdf_key_id;
  psa_key_attributes_t key_attr;
  psa_key_derivation_operation_t kdf_op;

  ret = psa_crypto_init();

  // Set up attributes for a volatile master plain key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_DERIVE);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_DERIVE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_HKDF(PSA_ALG_SHA_256));

  // Import a volatile master plain key
  ret = psa_import_key(&key_attr, hkdf_ikm, sizeof(hkdf_ikm), &master_key_id);

  // Set up attributes for a volatile derived plain key (exportable for verification)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
  psa_set_key_bits(&key_attr, sizeof(key_buf) * 8);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
  psa_set_key_algorithm(&key_attr, PSA_ALG_CTR);

  // Derive (HKDF SHA256) a volatile plain key for AES CTR
  #if defined(SEMAILBOX_PRESENT) && (_SILICON_LABS_SECURITY_FEATURE == _SILICON_LABS_SECURITY_FEATURE_VAULT)

  // Silicon Labs custom API for Secure Vault High devices
  ret = sl_psa_key_derivation_single_shot(PSA_ALG_HKDF(PSA_ALG_SHA_256), master_key_id,
                                          hkdf_info, sizeof(hkdf_info),
                                          hkdf_salt, sizeof(hkdf_salt),
                                          0, &key_attr, &hkdf_key_id);
  #else
  kdf_op = psa_key_derivation_operation_init();
  ret = psa_key_derivation_setup(&kdf_op, PSA_ALG_HKDF(PSA_ALG_SHA_256));
  ret = psa_key_derivation_set_capacity(&kdf_op, sizeof(key_buf));
  ret = psa_key_derivation_input_bytes(&kdf_op, PSA_KEY_DERIVATION_INPUT_SALT, hkdf_salt, sizeof(hkdf_salt));
  ret = psa_key_derivation_input_bytes(&kdf_op, PSA_KEY_DERIVATION_INPUT_INFO, hkdf_info, sizeof(hkdf_info));
  ret = psa_key_derivation_input_key(&kdf_op, PSA_KEY_DERIVATION_INPUT_SECRET, master_key_id);
  ret = psa_key_derivation_output_key(&key_attr, &kdf_op, &hkdf_key_id);
  ret = psa_key_derivation_abort(&kdf_op);
  #endif

  // Export derived volatile plain key (expected value of HKDF SHA256):
  // 3c b2 5f 25 fa ac d5 7a 90 43 4f 64 d0 36 2f 2a 2d 2d 0a 90 cf 1a 5a 4c 5d b0 2d 56 ec c4 c5 bf
  ret = psa_export_key(hkdf_key_id, key_buf, sizeof(key_buf), &key_len);

  // Destroy the master and derived keys
  ret = psa_destroy_key(master_key_id);
  ret = psa_destroy_key(hkdf_key_id);
}

PBKDF2-HMAC-SHA256 (HSE-SVH only)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t pbkdf2_ikm[] = {0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64};
  uint8_t pbkdf2_salt[] = {0x73, 0x61, 0x6c, 0x74};
  uint8_t key_buf[32];
  size_t key_len;
  psa_status_t ret;
  psa_key_id_t master_key_id;
  psa_key_id_t pbkdf2_key_id;
  psa_key_attributes_t key_attr;

  ret = psa_crypto_init();
  // Set up attributes for a volatile master plain key

  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_DERIVE);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_DERIVE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256));

  // Import a volatile master plain key
  ret = psa_import_key(&key_attr, pbkdf2_ikm, sizeof(pbkdf2_ikm), &master_key_id);

  // Set up attributes for a volatile derived plain key (exportable for verification)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
  psa_set_key_bits(&key_attr, sizeof(key_buf) * 8);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
  psa_set_key_algorithm(&key_attr, PSA_ALG_CTR);

  // Derive (PBKDF2 SHA256 with 4096 iterations) a volatile plain key for AES CTR
  // Silicon Labs custom API for Secure Vault High devices
  ret = sl_psa_key_derivation_single_shot(PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256), master_key_id,
                                          NULL, 0,
                                          pbkdf2_salt, sizeof(pbkdf2_salt),
                                          4096, &key_attr, &pbkdf2_key_id);

  // Export derived volatile plain key (expected value of PBKDF2 SHA256 with 4096 iterations):
  // c5 e4 78 d5 92 88 c8 41 aa 53 0d b6 84 5c 4c 8d 96 28 93 a0 01 ce 4e 11 a4 96 38 73 aa 98 13 4a
  ret = psa_export_key(pbkdf2_key_id, key_buf, sizeof(key_buf), &key_len);

  // Destroy the master and derived keys
  ret = psa_destroy_key(master_key_id);
  ret = psa_destroy_key(pbkdf2_key_id);
}

Note: The PBKDF2-HMAC implementation of PSA Crypto is not yet available.

PBKDF2-AES-CMAC-PRF-128 (HSE-SVH only)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t pbkdf2_ikm[] = {0x4a, 0x30, 0x31, 0x4e, 0x4d, 0x45};
  uint8_t pbkdf2_salt[] = {
    0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x37, 0x33, 0x35, 0x63, 0x38, 0x37, 0x62, 0x34, 0x4f, 0x70,
    0x65, 0x6e, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x44, 0x65, 0x6d, 0x6f
  };
  uint8_t key_buf[16];
  size_t key_len;
  psa_status_t ret;
  psa_key_id_t master_key_id;
  psa_key_id_t pbkdf2_key_id;
  psa_key_attributes_t key_attr;

  ret = psa_crypto_init();

  // Set up attributes for a volatile master plain key
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_DERIVE);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_DERIVE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_PBKDF2_AES_CMAC_PRF_128);

  // Import a volatile master plain key
  ret = psa_import_key(&key_attr, pbkdf2_ikm, sizeof(pbkdf2_ikm), &master_key_id);

  // Set up attributes for a volatile derived plain key (exportable for verification)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
  psa_set_key_bits(&key_attr, sizeof(key_buf) * 8);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
  psa_set_key_algorithm(&key_attr, PSA_ALG_CTR);

  // Derive (PBKDF2 AES_CMAC_PRF_128 with 16384 iterations) a volatile plain key for AES CTR
  // Silicon Labs custom API for Secure Vault High devices
  ret = sl_psa_key_derivation_single_shot(PSA_ALG_PBKDF2_AES_CMAC_PRF_128, master_key_id,
                                          NULL, 0,
                                          pbkdf2_salt, sizeof(pbkdf2_salt),
                                          16384, &key_attr, &pbkdf2_key_id);

  // Export derived volatile plain key (expected value of PBKDF2 AES_CMAC_PRF_128 with 16384 iterations):
  // 8b 27 be ed 7e 7a 4d d6 c5 31 38 c8 79 a8 e3 3c
  
  ret = psa_export_key(pbkdf2_key_id, key_buf, sizeof(key_buf), &key_len);

  // Destroy the master and derived keys
  ret = psa_destroy_key(master_key_id);
  ret = psa_destroy_key(pbkdf2_key_id);
}

Note:

  • The PBKDF2-AES-CMAC-PRF-128 implementation of PSA Crypto is not yet available.

  • EFR32xG21B (HSE-SVH) devices do not support PBKDF2-AES-CMAC-PRF-128.

ECDH and HKDF

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t client_private_key[] = {
    0xc8, 0x8f, 0x01, 0xf5, 0x10, 0xd9, 0xac, 0x3f, 0x70, 0xa2, 0x92, 0xda, 0xa2, 0x31, 0x6d, 0xe5,
    0x44, 0xe9, 0xaa, 0xb8, 0xaf, 0xe8, 0x40, 0x49, 0xc6, 0x2a, 0x9c, 0x57, 0x86, 0x2d, 0x14, 0x33
  };
  uint8_t client_public_key[] = { // Uncompressed point format
    0x04, 0xda, 0xd0, 0xb6, 0x53, 0x94, 0x22, 0x1c, 0xf9, 0xb0, 0x51, 0xe1, 0xfe, 0xca, 0x57, 0x87, 0xd0,
    0x98, 0xdf, 0xe6, 0x37, 0xfc, 0x90, 0xb9, 0xef, 0x94, 0x5d, 0x0c, 0x37, 0x72, 0x58, 0x11, 0x80,
    0x52, 0x71, 0xa0, 0x46, 0x1c, 0xdb, 0x82, 0x52, 0xd6, 0x1f, 0x1c, 0x45, 0x6f, 0xa3, 0xe5, 0x9a,
    0xb1, 0xf4, 0x5b, 0x33, 0xac, 0xcf, 0x5f, 0x58, 0x38, 0x9e, 0x05, 0x77, 0xb8, 0x99, 0x0b, 0xb3
  };
  uint8_t server_private_key[] = {
    0xc6, 0xef, 0x9c, 0x5d, 0x78, 0xae, 0x01, 0x2a, 0x01, 0x11, 0x64, 0xac, 0xb3, 0x97, 0xce, 0x20,
    0x88, 0x68, 0x5d, 0x8f, 0x06, 0xbf, 0x9b, 0xe0, 0xb2, 0x83, 0xab, 0x46, 0x47, 0x6b, 0xee, 0x53
  };
  uint8_t server_public_key[] = { // Uncompressed point format
    0x04, 0xd1, 0x2d, 0xfb, 0x52, 0x89, 0xc8, 0xd4, 0xf8, 0x12, 0x08, 0xb7, 0x02, 0x70, 0x39, 0x8c, 0x34,
    0x22, 0x96, 0x97, 0x0a, 0x0b, 0xcc, 0xb7, 0x4c, 0x73, 0x6f, 0xc7, 0x55, 0x44, 0x94, 0xbf, 0x63,
    0x56, 0xfb, 0xf3, 0xca, 0x36, 0x6c, 0xc2, 0x3e, 0x81, 0x57, 0x85, 0x4c, 0x13, 0xc5, 0x8d, 0x6a,
    0xac, 0x23, 0xf0, 0x46, 0xad, 0xa3, 0x0f, 0x83, 0x53, 0xe7, 0x4f, 0x33, 0x03, 0x98, 0x72, 0xab
  };
  uint8_t hkdf_salt[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c};
  uint8_t hkdf_info[] = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9};
  uint8_t key_buf[32];
  size_t key_len;

  psa_status_t ret;
  psa_key_id_t master_key_id;
  psa_key_id_t hkdf_key_id;
  psa_key_attributes_t key_attr;
  psa_key_derivation_operation_t kdf_op;

  ret = psa_crypto_init();

  // Set up attributes for a volatile master plain key (algorithm for ECDH and HKDF)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_DERIVE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)));

  // Import a volatile master plain key (client private key)
  ret = psa_import_key(&key_attr, client_private_key, sizeof(client_private_key),
  &master_key_id);

  // Set up attributes for a volatile derived plain key (exportable for verification)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
  psa_set_key_bits(&key_attr, sizeof(key_buf) * 8);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
  psa_set_key_algorithm(&key_attr, PSA_ALG_CTR);

  // Derive (HKDF SHA256) a volatile plain key from ECDH shared secret (server public key) for AES CTR
  kdf_op = psa_key_derivation_operation_init();
  ret = psa_key_derivation_setup(&kdf_op, PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)));
  ret = psa_key_derivation_set_capacity(&kdf_op, sizeof(key_buf));
  ret = psa_key_derivation_input_bytes(&kdf_op, PSA_KEY_DERIVATION_INPUT_SALT, hkdf_salt, sizeof(hkdf_salt));
  ret = psa_key_derivation_input_bytes(&kdf_op, PSA_KEY_DERIVATION_INPUT_INFO, hkdf_info, sizeof(hkdf_info));
  ret = psa_key_derivation_key_agreement(&kdf_op, PSA_KEY_DERIVATION_INPUT_SECRET, master_key_id, server_public_key,
  sizeof(server_public_key));
  ret = psa_key_derivation_output_key(&key_attr, &kdf_op, &hkdf_key_id);
  ret = psa_key_derivation_abort(&kdf_op);

  // Export derived volatile plain key (client shared secret):
  // B7 CA BD A7 42 60 DE D5 4C 4C 11 FA BC A3 56 4B 77 35 CC 9F 89 E9 BF E8 08 24 8A F3 54 99 B0 55
  ret = psa_export_key(hkdf_key_id, key_buf, sizeof(key_buf), &key_len);

  // Destroy the master and derived keys
  ret = psa_destroy_key(master_key_id);
  ret = psa_destroy_key(hkdf_key_id);

  // Set up attributes for a volatile master plain key (algorithm for ECDH and HKDF)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_DERIVE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)));

  // Import a volatile master plain key (server private key)
  ret = psa_import_key(&key_attr, server_private_key, sizeof(server_private_key),
                      &master_key_id);

  // Set up attributes for a volatile derived plain key (exportable for verification)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
  psa_set_key_bits(&key_attr, sizeof(key_buf) * 8);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
  psa_set_key_algorithm(&key_attr, PSA_ALG_CTR);

  // Derive (HKDF SHA256) a volatile plain key from ECDH shared secret (client public key) for AES CTR
  kdf_op = psa_key_derivation_operation_init();
  ret = psa_key_derivation_setup(&kdf_op, PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)));
  ret = psa_key_derivation_set_capacity(&kdf_op, sizeof(key_buf));
  ret = psa_key_derivation_input_bytes(&kdf_op, PSA_KEY_DERIVATION_INPUT_SALT, hkdf_salt, sizeof(hkdf_salt));
  ret = psa_key_derivation_input_bytes(&kdf_op, PSA_KEY_DERIVATION_INPUT_INFO, hkdf_info, sizeof(hkdf_info));
  ret = psa_key_derivation_key_agreement(&kdf_op, PSA_KEY_DERIVATION_INPUT_SECRET, master_key_id, client_public_key,
                                        sizeof(client_public_key));
  ret = psa_key_derivation_output_key(&key_attr, &kdf_op, &hkdf_key_id);
  ret = psa_key_derivation_abort(&kdf_op);

  // Export derived volatile plain key (server shared secret):
  // B7 CA BD A7 42 60 DE D5 4C 4C 11 FA BC A3 56 4B 77 35 CC 9F 89 E9 BF E8 08 24 8A F3 54 99 B0 55
  ret = psa_export_key(hkdf_key_id, key_buf, sizeof(key_buf), &key_len);

  // Destroy the master and derived keys
  ret = psa_destroy_key(master_key_id);
  ret = psa_destroy_key(hkdf_key_id);
}

PSA Crypto Platform Example

Click the View Project Documentation link to open the readme file.

image27image27

The following table describes the implementation status of the PSA Crypto KDF platform example.

Algorithm

Series 1

Series 2 - VSE

Series 2 - HSE

Remark

HKDF

Y

Y

Y

Hardware acceleration only on HSE-SVH devices with Silicon Labs custom API.

ECDH + HKDF

Y

Y

Y

Hardware acceleration (HKDF) only on HSE-SVH devices with Silicon Labs custom API.

Note:

  • The PBKDF2 implementation of PSA Crypto is not yet available.

  • The ECDH + HKDF algorithm does not apply to the wrapped key.

Asymmetric Cryptographic Operation#

Asymmetric Signature (ECDSA and EdDSA)#

In modern cryptography, the Elliptic-Curve-based signatures (like ECDSA and EdDSA) are widely used because of shorter key lengths, shorter signature lengths, higher security levels (for the same key length), and better performance.

The Elliptic Curve Digital Signature Algorithm (ECDSA) is a cryptographically secure digital signature scheme based on the Elliptic Curve Cryptography (ECC). The Edwards-curve Digital Signature Algorithm (EdDSA) is a fast digital signature algorithm, using elliptic curves in Edwards form (like Ed25519 and Ed448).

Algorithms

Algorithm Mbed TLS PSA Crypto

ECDSA (SHA-1)

PSA_ALG_ECDSA(PSA_ALG_SHA_1)

ECDSA (SHA-2)

PSA_ALG_ECDSA(PSA_ALG_SHA_224)
PSA_ALG_ECDSA(PSA_ALG_SHA_256)
PSA_ALG_ECDSA(PSA_ALG_SHA_384)
PSA_ALG_ECDSA(PSA_ALG_SHA_512)

ECDSA (Any hash algorithm)

PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)

ECDSA (No hashing)

PSA_ALG_ECDSA_ANY

EdDSA

PSA_ALG_PURE_EDDSA

Note: The hash-and-sign algorithms (PSA_ALG_ECDSA(hash_alg) and PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)) include the hashing step for ECDSA.

Key Attributes in PSA Crypto

Algorithm Key Type Key Size in Bits Key Usage Flag
PSA_ALG_ECDSA_ANY PSA_ECC_FAMILY_SECP_R1 secp192r1 : 192
secp224r1 : 224
secp256r1 : 256
secp384r1 : 384
secp521r1 : 521
PSA_KEY_USAGE_SIGN_HASH
PSA_KEY_USAGE_VERIFY_HASH
PSA_ECC_FAMILY_SECP_K1 secp256k1 : 256
PSA_ALG_ECDSA(PSA_ALG_SHA_1)
PSA_ALG_ECDSA(PSA_ALG_SHA_224)
PSA_ALG_ECDSA(PSA_ALG_SHA_256)
PSA_ALG_ECDSA(PSA_ALG_SHA_384)
PSA_ALG_ECDSA(PSA_ALG_SHA_512)
PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
PSA_ECC_FAMILY_SECP_R1 secp192r1 : 192
secp224r1 : 224
secp256r1 : 256
secp384r1 : 384
secp521r1 : 521
PSA_KEY_USAGE_SIGN_MESSAGE
PSA_KEY_USAGE_VERIFY_MESSAGE
PSA_ECC_FAMILY_SECP_K1 secp256k1 : 256
PSA_ALG_PURE_EDDSA PSA_ECC_FAMILY_TWISTED_EDWARDS Edwards25519 : 255 PSA_KEY_USAGE_SIGN_MESSAGE
PSA_KEY_USAGE_VERIFY_MESSAGE

Security Software Components

Algorithm

Security Software Components

PSA_ALG_ECDSA_ANY

ECDSA

PSA_ALG_ECDSA(PSA_ALG_SHA_1)

ECDSA and SHA-1

PSA_ALG_ECDSA(PSA_ALG_SHA_224)

ECDSA and SHA-224

PSA_ALG_ECDSA(PSA_ALG_SHA_256)

ECDSA and SHA-256

PSA_ALG_ECDSA(PSA_ALG_SHA_384)

ECDSA and SHA-384

PSA_ALG_ECDSA(PSA_ALG_SHA_512)

ECDSA and SHA-512

PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)

ECDSA and SHA-X

Algorithm

Security Software Components

PSA_ALG_PURE_EDDSA

EdDSA

PSA_ECC_FAMILY_SECP_R1

Security Software Components

secp192r1

secp192r1

secp224r1

secp224r1

secp256r1

secp256r1

secp384r1

secp384r1

secp521r1

secp521r1

PSA_ECC_FAMILY_SECP_K1

Security Software Components

secp256k1

secp256k1

PSA_ECC_FAMILY_TWISTED_EDWARDS

Security Software Components

Edwards25519

edwards25519

Built-in Key

Security Software Components

secp256r1 keys in SE OTP

Built-In Keys

Functions

Mbed TLS PSA Crypto

Hash-and-sign

Hash-and-sign
psa_status_t psa_sign_message(…)
psa_status_t psa_verify_message(…)

Precomputed hash
int mbedtls_ecdsa_write_signature(…)
int mbedtls_ecdsa_read_signature(…)

Precomputed hash
psa_status_t psa_sign_hash(…)
psa_status_t psa_verify_hash(…)

Quick Reference Examples

ECDSA on secp256r1 (Precomputed Hash)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t hash_data[] = {
    0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
    0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1
  };
  uint8_t public_key[65]; // Uncompressed point format
  size_t pubkey_len;
  uint8_t signature_buf[64];
  size_t signature_len;

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;

  ret = psa_crypto_init();

  // Set up attributes for a volatile private plain key (secp256r1)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
  psa_set_key_bits(&key_attr, 256);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH);
  psa_set_key_algorithm(&key_attr, PSA_ALG_ECDSA_ANY);

  // Generate a random volatile private plain key
  ret = psa_generate_key(&key_attr, &key_id);

  // Sign a hash with a volatile private plain key
  ret = psa_sign_hash(key_id,
                      PSA_ALG_ECDSA_ANY,
                      hash_data,
                      sizeof(hash_data),
                      signature_buf,
                      sizeof(signature_buf),
                      &signature_len);

  // Verify a signature with a volatile private plain key
  ret = psa_verify_hash(key_id,
                        PSA_ALG_ECDSA_ANY,
                        hash_data,
                        sizeof(hash_data),
                        signature_buf,
                        signature_len);

  // Export a public key from a volatile private plain key and then destroy the private key
  ret = psa_export_public_key(key_id,
                              public_key,
                              sizeof(public_key),
                              &pubkey_len);

  ret = psa_destroy_key(key_id);

  // Set up attributes for a public key (secp256r1)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_VERIFY_HASH);
  psa_set_key_algorithm(&key_attr, PSA_ALG_ECDSA_ANY);

  // Import a public key
  ret = psa_import_key(&key_attr, public_key, sizeof(public_key), &key_id);

  // Verify a signature with a public key and then destroy the public key
  ret = psa_verify_hash(key_id,
                        PSA_ALG_ECDSA_ANY,
                        hash_data,
                        sizeof(hash_data),
                        signature_buf,
                        signature_len);

  ret = psa_destroy_key(key_id);
}

ECDSA on secp256r1 (Hash-and-Sign)

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t ecdsa_msg[] = {
    0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31,
    0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a,
    0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
    0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f
  };
  uint8_t public_key[65];                                     // Uncompressed point format
  size_t pubkey_len;
  uint8_t signature_buf[64];
  size_t signature_len;

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;

  ret = psa_crypto_init();

  // Set up attributes for a volatile private plain key (secp256r1)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
  psa_set_key_bits(&key_attr, 256);
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_ECDSA(PSA_ALG_ANY_HASH));

  // Generate a random volatile private plain key
  ret = psa_generate_key(&key_attr, &key_id);

  // Hash-and-Sign (SHA-256) a message with a volatile private plain key
  ret = psa_sign_message(key_id,
                        PSA_ALG_ECDSA(PSA_ALG_SHA_256),
                        ecdsa_msg,
                        sizeof(ecdsa_msg),
                        signature_buf,
                        sizeof(signature_buf),
                        &signature_len);

  // Hash (SHA-256) a message and verify a signature with a volatile private plain key
  ret = psa_verify_message(key_id,
                          PSA_ALG_ECDSA(PSA_ALG_SHA_256),
                          ecdsa_msg,
                          sizeof(ecdsa_msg),
                          signature_buf,
                          signature_len);

  // Export a public key from a volatile private plain key and then destroy the private key
  ret = psa_export_public_key(key_id,
                              public_key,
                              sizeof(public_key),
                              &pubkey_len);

  ret = psa_destroy_key(key_id);

  // Set up attributes for a public key (secp256r1)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_VERIFY_MESSAGE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_ECDSA(PSA_ALG_ANY_HASH));

  // Import a public key
  ret = psa_import_key(&key_attr, public_key, sizeof(public_key), &key_id);

  // Hash (SHA-256) and verify a signature with a public key and then destroy the public key
  ret = psa_verify_message(key_id,
                          PSA_ALG_ECDSA(PSA_ALG_SHA_256),
                          ecdsa_msg,
                          sizeof(ecdsa_msg),
                          signature_buf,
                          signature_len);

  ret = psa_destroy_key(key_id);
}

ECDSA with Built-in Private Device Key (HSE-SVH only)

#include "psa/crypto.h"

void app_process_action(void)
{
#if (_SILICON_LABS_SECURITY_FEATURE == _SILICON_LABS_SECURITY_FEATURE_VAULT)
 uint8_t hash_data[] = {
  0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
  0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1
 };
 uint8_t public_key[65];                                  // Uncompressed point format
 size_t pubkey_len;
 uint8_t signature_buf[64];
 size_t signature_len;

 psa_status_t ret;
 psa_key_id_t key_id;
 psa_key_attributes_t key_attr;

 ret = psa_crypto_init();

 // Sign a hash with a built-in private device key
 ret = psa_sign_hash(SL_SE_BUILTIN_KEY_APPLICATION_ATTESTATION_ID,
                    PSA_ALG_ECDSA_ANY,
                    hash_data,
                    sizeof(hash_data),
                    signature_buf,
                    sizeof(signature_buf),
                    &signature_len);

 // Verify a signature with a built-in private device key
 ret = psa_verify_hash(SL_SE_BUILTIN_KEY_APPLICATION_ATTESTATION_ID,
                      PSA_ALG_ECDSA_ANY,
                      hash_data,
                      sizeof(hash_data),
                      signature_buf,
                      signature_len);

 // Export a built-in public device key
 ret = psa_export_public_key(SL_SE_BUILTIN_KEY_APPLICATION_ATTESTATION_ID,
                            public_key,
                            sizeof(public_key),
                            &pubkey_len);

 // Set up attributes for a public device key
 key_attr = psa_key_attributes_init();
 psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
 psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_VERIFY_HASH);
 psa_set_key_algorithm(&key_attr, PSA_ALG_ECDSA_ANY);

 // Import a public device key
 ret = psa_import_key(&key_attr, public_key, sizeof(public_key), &key_id);

 // Verify a signature with a public device key
 ret = psa_verify_hash(key_id,
                      PSA_ALG_ECDSA_ANY,
                      hash_data,
                      sizeof(hash_data),
                      signature_buf,
                      signature_len);

 // Destroy a public device key
 ret = psa_destroy_key(key_id);
#endif
}

EdDSA on Ed25519 (HSE only)

#include "psa/crypto.h"

void app_process_action(void)
{
#if defined(SEMAILBOX_PRESENT)
  uint8_t eddsa_msg[] = {
    0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31,
    0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a,
    0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
    0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f
  };
  uint8_t ed25519_private[] = {
    0x83, 0x3f, 0xe6, 0x24, 0x09, 0x23, 0x7b, 0x9d, 0x62, 0xec, 0x77, 0x58, 0x75, 0x20, 0x91, 0x1e,
    0x9a, 0x75, 0x9c, 0xec, 0x1d, 0x19, 0x75, 0x5b, 0x7d, 0xa9, 0x01, 0xb9, 0x6d, 0xca, 0x3d, 0x42
  };
  uint8_t ed25519_public[] = {
    0xec, 0x17, 0x2b, 0x93, 0xad, 0x5e, 0x56, 0x3b, 0xf4, 0x93, 0x2c, 0x70, 0xe1, 0x24, 0x50, 0x34,
    0xc3, 0x54, 0x67, 0xef, 0x2e, 0xfd, 0x4d, 0x64, 0xeb, 0xf8, 0x19, 0x68, 0x34, 0x67, 0xe2, 0xbf
  };
  uint8_t signature_buf[64];
  size_t signature_len;

  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;

  ret = psa_crypto_init();

  // Set up attributes for a volatile private plain key (Ed25519)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS));
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_PURE_EDDSA);

  // Import a volatile private plain key
  ret = psa_import_key(&key_attr, ed25519_private, sizeof(ed25519_private), &key_id);

  // Hash-and-Sign a message with a volatile private plain key (expected EdDSA signature):
  // dc 2a 44 59 e7 36 96 33 a5 2b 1b f2 77 83 9a 00 20 10 09 a3 ef bf 3e cb 69 be a2 18 6c 26 b5 89
  // 09 35 1f c9 ac 90 b3 ec fd fb c7 c6 64 31 e0 30 3d ca 17 9c 13 8a c1 7a d9 be f1 17 73 31 a7 04
  ret = psa_sign_message(key_id,
                        PSA_ALG_PURE_EDDSA,
                        eddsa_msg,
                        sizeof(eddsa_msg),
                        signature_buf,
                        sizeof(signature_buf),
                        &signature_len);

  // Destroy a volatile private plain key
  ret = psa_destroy_key(key_id);

  // Set up attributes for a public key (Ed25519)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_TWISTED_EDWARDS));
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_VERIFY_MESSAGE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_PURE_EDDSA);

  // Import a public key
  ret = psa_import_key(&key_attr, ed25519_public, sizeof(ed25519_public), &key_id);

  // Hash a message and verify the signature with a public key
  ret = psa_verify_message(key_id,
                          PSA_ALG_PURE_EDDSA,
                          eddsa_msg,
                          sizeof(eddsa_msg),
                          signature_buf,
                          signature_len);

  // Destroy a public key
  ret = psa_destroy_key(key_id);
#endif
}

PSA Crypto Platform Example

Click the View Project Documentation link to open the readme file.

image28image28

The following table describes the implementation status of the PSA Crypto DSA platform example.

ECC Key

Series 1

Series 2 - VSE

Series 2 - HSE

Remark

secp192r1

Y

Y

Y

secp256r1

Y

Y

Y

secp384r1

Y

Y

Y

Hardware acceleration only on HSE-SVH devices.

secp521r1

Y

Y

Y

Hardware acceleration only on HSE-SVH devices.

Edwards25519

Y

Only on HSE devices with hardware acceleration.

Public Sign Key

Y

Public Command Key

Y

Private Device Key

Y

Only on HSE-SVH devices.

Note:

  • This example does not include secp224r1 and secp256k1. The secp256k1 ECDSA on HSE devices is not yet implemented.

  • The PSA Crypto does not yet support software fallback on the Edwards25519.

  • The HSE-SVM devices require SE firmware v1.2.11 or higher (EFR32xG21) and v2.1.7 or higher (other HSE devices) to support hardware acceleration on Edwards25519. This feature also requires GSDK v4.0.1 or higher.

Key Agreement (ECDH)#

The Elliptic Curve Diffie-Hellman (ECDH) is an anonymous key agreement protocol that allows two parties, each having an elliptic-curve private-public key pair, to establish a shared secret over an insecure channel.

Algorithms

Algorithm

Mbed TLS

PSA Crypto

ECDH

PSA_ALG_ECDH

ECDH and HKDF

PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(hash_alg))

Key Attributes in PSA Crypto

Algorithm Key Type Key Size in Bits Key Usage Flag

PSA_ALG_ECDH

PSA_ECC_FAMILY_SECP_R1

• secp192r1 : 192
• secp224r1 : 224
• secp256r1 : 256
• secp384r1 : 384
• secp521r1 : 521

PSA_KEY_USAGE_DERIVE

PSA_ECC_FAMILY_SECP_K1

secp256k1 : 256

PSA_ECC_FAMILY_MONTGOMERY

• Curve25519 : 255
• Curve448 : 448

Security Software Components

Algorithm

Security Software Components

PSA_ALG_ECDH

ECDH

PSA_ECC_FAMILY_SECP_R1

Security Software Components

secp192r1

secp192r1

secp224r1

secp224r1

secp256r1

secp256r1

secp384r1

secp384r1

secp521r1

secp521r1

PSA_ECC_FAMILY_SECP_K1

Security Software Components

secp256k1

secp256k1

PSA_ECC_FAMILY_MONTGOMERY

Security Software Components

Curve25519

Curve25519

Curve448

Curve448

Functions

Mbed TLS

PSA Crypto

int mbedtls_ecdh_compute_shared(…)

psa_status_t psa_raw_key_agreement(…)

psa_status_t psa_key_derivation_key_agreement(…)

Note: For the psa_key_derivation_key_agreement(…) function, refer to the PSA Crypto KDF quick reference (ECDH and HKDF) and platform examples for details.

Quick Reference Examples ECDH on secp256r1

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t client_private_key[] = {
    0xc8, 0x8f, 0x01, 0xf5, 0x10, 0xd9, 0xac, 0x3f, 0x70, 0xa2, 0x92, 0xda, 0xa2, 0x31, 0x6d, 0xe5,
    0x44, 0xe9, 0xaa, 0xb8, 0xaf, 0xe8, 0x40, 0x49, 0xc6, 0x2a, 0x9c, 0x57, 0x86, 0x2d, 0x14, 0x33
  };

  uint8_t client_public_key[] = { // Uncompressed point format
    0x04, 0xda, 0xd0, 0xb6, 0x53, 0x94, 0x22, 0x1c, 0xf9, 0xb0, 0x51, 0xe1, 0xfe, 0xca, 0x57, 0x87, 0xd0,
    0x98, 0xdf, 0xe6, 0x37, 0xfc, 0x90, 0xb9, 0xef, 0x94, 0x5d, 0x0c, 0x37, 0x72, 0x58, 0x11, 0x80,
    0x52, 0x71, 0xa0, 0x46, 0x1c, 0xdb, 0x82, 0x52, 0xd6, 0x1f, 0x1c, 0x45, 0x6f, 0xa3, 0xe5, 0x9a,
    0xb1, 0xf4, 0x5b, 0x33, 0xac, 0xcf, 0x5f, 0x58, 0x38, 0x9e, 0x05, 0x77, 0xb8, 0x99, 0x0b, 0xb3
  };

  uint8_t server_private_key[] = {
    0xc6, 0xef, 0x9c, 0x5d, 0x78, 0xae, 0x01, 0x2a, 0x01, 0x11, 0x64, 0xac, 0xb3, 0x97, 0xce, 0x20,
    0x88, 0x68, 0x5d, 0x8f, 0x06, 0xbf, 0x9b, 0xe0, 0xb2, 0x83, 0xab, 0x46, 0x47, 0x6b, 0xee, 0x53
  };

  uint8_t server_public_key[] = { // Uncompressed point format
    0x04, 0xd1, 0x2d, 0xfb, 0x52, 0x89, 0xc8, 0xd4, 0xf8, 0x12, 0x08, 0xb7, 0x02, 0x70, 0x39, 0x8c, 0x34,
    0x22, 0x96, 0x97, 0x0a, 0x0b, 0xcc, 0xb7, 0x4c, 0x73, 0x6f, 0xc7, 0x55, 0x44, 0x94, 0xbf, 0x63,
    0x56, 0xfb, 0xf3, 0xca, 0x36, 0x6c, 0xc2, 0x3e, 0x81, 0x57, 0x85, 0x4c, 0x13, 0xc5, 0x8d, 0x6a,
    0xac, 0x23, 0xf0, 0x46, 0xad, 0xa3, 0x0f, 0x83, 0x53, 0xe7, 0x4f, 0x33, 0x03, 0x98, 0x72, 0xab
  };

  // Expected shared secret:
  // d6 84 0f 6b 42 f6 ed af d1 31 16 e0 e1 25 65 20 2f ef 8e 9e ce 7d ce 03 81 24 64 d0 4b 94 42 de
  uint8_t shared_secret_buf[32];
  size_t shared_secret_len;
  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;

  ret = psa_crypto_init();

  // Set up attributes for a volatile client private plain key (secp256r1)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_DERIVE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_ECDH);

  // Import a volatile client private plain key
  ret = psa_import_key(&key_attr, client_private_key, sizeof(client_private_key), &key_id);

  // Perform a key agreement with the server public key and then destroy the client private key
  ret = psa_raw_key_agreement(PSA_ALG_ECDH,
                              key_id,
                              server_public_key,
                              sizeof(server_public_key),
                              shared_secret_buf,
                              sizeof(shared_secret_buf),
                              &shared_secret_len);

  ret = psa_destroy_key(key_id);

  // Set up attributes for a volatile server private plain key (secp256r1)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_DERIVE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_ECDH);

  // Import a volatile server private plain key
  ret = psa_import_key(&key_attr, server_private_key, sizeof(server_private_key), &key_id);

  // Perform a key agreement with the client public key and then destroy the server private key
  ret = psa_raw_key_agreement(PSA_ALG_ECDH,
                              key_id,
                              client_public_key,
                              sizeof(client_public_key),
                              shared_secret_buf,
                              sizeof(shared_secret_buf),
                              &shared_secret_len);

  ret = psa_destroy_key(key_id);
}

ECDH on Curve25519

#include "psa/crypto.h"

void app_process_action(void)
{
  uint8_t client_private_key[] = {
    0xB0, 0x76, 0x51, 0xEA, 0x20, 0xF0, 0x28, 0xA8,0x16, 0xEE, 0x01, 0xB0, 0xD1, 0x06, 0x2A, 0x7C,
    0x81, 0x58, 0xE8, 0x84, 0xE9, 0xBC, 0xC6, 0x1C, 0x5D, 0xAB, 0xDB, 0x4E, 0x38, 0x2F, 0x96, 0x69,
  };

  uint8_t client_public_key[] = {
    0x87, 0xD8, 0x6B, 0xDA, 0xAC, 0x38, 0x3C, 0x85, 0xA6, 0xBC, 0xF8, 0xFC, 0xC6, 0x26, 0xD6, 0x14,
    0x36, 0xE4, 0x8F, 0xDB, 0xFA, 0x5A, 0x45, 0xFE, 0x0C, 0x9E, 0xA8, 0x4B, 0x35, 0x3E, 0xF1, 0x37,
  };

  uint8_t server_private_key[] = {
    0x98, 0x2E, 0xB6, 0x7D, 0x0A, 0x01, 0x57, 0x90, 0xE1, 0x45, 0xF3, 0x67, 0xF6, 0xDA, 0xA6, 0x44,
    0x2C, 0x87, 0xC0, 0xED, 0x3C, 0x36, 0x71, 0xA6, 0x89, 0xC7, 0x49, 0xAC, 0x0D, 0xFE, 0x43, 0x6E,
  };

  uint8_t server_public_key[] = {
    0x0C, 0x04, 0x10, 0x5B, 0xE8, 0x7C, 0xAB, 0x37, 0x21, 0x15, 0x7A, 0x8D, 0x49, 0x85, 0x8C, 0x7A,
    0x9F, 0xC1, 0x46, 0xDA, 0xCC, 0x96, 0xEF, 0x6E, 0xD4, 0xDA, 0x71, 0xBF, 0xED, 0x32, 0x0D, 0x76,
  };

  // Expected shared secret:
  // F2 E6 0E 1C B7 64 BC 48 F2 9D BB 12 FB 12 17 31 32 1D 79 AF 0A 9F AB AD 34 05 A2 07 39 9C 5F 15
  uint8_t shared_secret_buf[32];
  size_t shared_secret_len;
  psa_status_t ret;
  psa_key_id_t key_id;
  psa_key_attributes_t key_attr;

  ret = psa_crypto_init();

  // Set up attributes for a volatile client private plain key (Curve25519)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY));
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_DERIVE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_ECDH);

  // Import a volatile client private plain key
  ret = psa_import_key(&key_attr, client_private_key, sizeof(client_private_key), &key_id);

  // Perform a key agreement with server public key
  ret = psa_raw_key_agreement(PSA_ALG_ECDH,
                              key_id,
                              server_public_key,
                              sizeof(server_public_key),
                              shared_secret_buf,
                              sizeof(shared_secret_buf),
                              &shared_secret_len);

  // Destroy the client private key
  ret = psa_destroy_key(key_id);

  // Set up attributes for a volatile server private plain key (Curve25519)
  key_attr = psa_key_attributes_init();
  psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY));
  psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_DERIVE);
  psa_set_key_algorithm(&key_attr, PSA_ALG_ECDH);

  // Import a volatile server private plain key
  ret = psa_import_key(&key_attr, server_private_key, sizeof(server_private_key), &key_id);

  // Perform a key agreement with client public key
  ret = psa_raw_key_agreement(PSA_ALG_ECDH,
                              key_id,
                              client_public_key,
                              sizeof(client_public_key),
                              shared_secret_buf,
                              sizeof(shared_secret_buf),
                              &shared_secret_len);

  // Destroy the server private key
  ret = psa_destroy_key(key_id);
}

PSA Crypto Platform Example

Click the View Project Documentation link to open the readme file.

image29image29

The following table describes the implementation status of the PSA Crypto ECDH platform example.

ECC Key

Series 1

Series 2 - VSE

Series 2 - HSE

Remark

secp192r1

Y

Y

Y

secp256r1

Y

Y

Y

secp384r1

Y

Y

Y

Hardware acceleration only on HSE-SVH devices.

secp521r1

Y

Y

Y

Hardware acceleration only on HSE-SVH devices.

Curve25519

Y

Y

Y

Hardware acceleration only on HSE devices.

Curve448

Y

Only on HSE-SVH devices with hardware acceleration.

Note:

  • This example does not include secp224r1 and secp256k1. The secp256k1 ECDH on HSE devices is not yet implemented.

  • The PSA Crypto does not yet support software fallback on the Curve448.

  • The HSE-SVM devices require SE firmware v1.2.11 or higher (EFR32xG21) and v2.1.7 or higher (other HSE devices) to support hardware acceleration on Curve25519. This feature also requires GSDK v4.0.1 or higher.

X.509 Certificate#

An X.509 certificate is a digital certificate that uses the widely accepted international X.509 public key infrastructure (PKI) standard to verify that a public key belongs to the user, computer, or service identity contained within the certificate.

An X.509 certificate contains a public key and an identity (a hostname, an organization, an individual). It is either signed by a certificate authority or self-signed. When a certificate is signed by a trusted certificate authority or validated by other means, someone holding that certificate can rely on the public key it contains to establish secure communications with another party or validate documents digitally signed by the corresponding private key.

Algorithms

Algorithm Mbed TLS PSA Crypto

ECDSA (SHA-2)

PSA_ALG_ECDSA(PSA_ALG_SHA_224)
PSA_ALG_ECDSA(PSA_ALG_SHA_256)
PSA_ALG_ECDSA(PSA_ALG_SHA_384)
PSA_ALG_ECDSA(PSA_ALG_SHA_512)

Key Attributes in PSA Crypto

Algorithm

Key Type

Key Size in Bits

Key Usage Flag

• PSA_ALG_ECDSA(PSA_ALG_SHA_224)

PSA_ECC_FAMILY_SECP_R1

• secp192r1 : 192

• PSA_KEY_USAGE_SIGN_HASH

• PSA_ALG_ECDSA(PSA_ALG_SHA_256)

• secp256r1 : 256

• PSA_KEY_USAGE_VERIFY_HASH

• PSA_ALG_ECDSA(PSA_ALG_SHA_384)

• secp384r1 : 384

• PSA_ALG_ECDSA(PSA_ALG_SHA_512)

• secp521r1 : 521

Note: The key usage flag must use PSA_KEY_USAGE_SIGN_HASH and PSA_KEY_USAGE_VERIFY_HASH.

Security Software Components

Algorithm

Security Software Components

PSA_ALG_ECDSA(PSA_ALG_SHA_224)

ECDSA and SHA-224

PSA_ALG_ECDSA(PSA_ALG_SHA_256)

ECDSA amd SHA-256

PSA_ALG_ECDSA(PSA_ALG_SHA_384)

ECDSA and SHA-384

PSA_ALG_ECDSA(PSA_ALG_SHA_512)

ECDSA and SHA-512

PSA_ECC_FAMILY_SECP_R1

Security Software Components

secp192r1

secp192r1

secp256r1

secp256r1

secp384r1

secp384r1

secp521r1

secp521r1

Built-in Key

Security Software Components

secp256r1 keys in SE OTP

Built-In Keys

Item

Security Software Components

SHA-1 for X.509 certificate

SHA-1

Item

Security Software Components

X.509 certificate support

X.509

Using Opaque ECDSA Key to Generate Certificate Signing Request (CSR)

  1. Declare (and allocate) an object of type mbedtls_pk_context (PK context) and an object of type psa_key_id_t (key identifier).

  2. Use the key identifier to generate an ECDSA key or load the built-in ECDSA key. Refer to the Asymmetric Key for details.

  3. Set up the PK context to wrap that PSA key by calling mbedtls_pk_setup_opaque(mbedtls_pk_context \*ctx, const psa_key_id_t key).

  4. Configure the pending CSR object to use that key by calling mbedtls_x509write_csr_set_key(mbedtls_x509write_csr \*ctx, mbedtls_pk_context \*key) on that PK context.

  5. Call any other function that needs to configure and generate the CSR.

  6. After generating the CSR, free the PK context using mbedtls_pk_free(mbedtls_pk_context \*ctx). It only frees the PK context itself and leaves the key identifier untouched.

  7. Either keep using the key identifier or call psa_destroy_key() on it, depending on the application flow.

PSA Crypto Platform Example

Click the View Project Documentation link to open the readme file.

image30image30

The following table describes the implementation status of the PSA Crypto X.509 platform example.

ECDSA Key

Series 1

Series 2 - VSE

Series 2 - HSE

Remark

secp192r1

Y

Y

Y

secp256r1

Y

Y

Y

secp384r1

Y

Y

Y

Hardware acceleration only on HSE-SVH devices.

secp521r1

Y

Y

Y

Hardware acceleration only on HSE-SVH devices.

Private Device Key

Y

Only on HSE-SVH devices.

Note: This example can select the Private Device Key (secp256r1) to generate the root certificate CSR.