Mbed Crypto is an open source cryptographic library that supports a wide range of cryptographic operations, including:
The Mbed Crypto library is a reference implementation of the cryptography interface of the Arm Platform Security Architecture (PSA). It is written in portable C.
The Mbed Crypto library is distributed under the Apache License, version 2.0.
Arm's Platform Security Architecture (PSA) is a holistic set of threat models, security analyses, hardware and firmware architecture specifications, and an open source firmware reference implementation. PSA provides a recipe, based on industry best practice, that allows security to be consistently designed in, at both a hardware and firmware level. Part of the API provided by PSA is the cryptography interface, which provides access to a set of primitives.
Mbed Crypto releases are available in the public Github repository.
You need the following tools to build the library with the provided makefiles:
If you have a C compiler such as GCC or Clang, just run make
in the top-level directory to build the library, a set of unit tests and some sample programs.
To select a different compiler, set the CC
variable to name or path of the compiler and linker (default: cc
) and set AR
to a compatible archiver (default: ar
), such as:
make CC=arm-linux-gnueabi-gcc AR=arm-linux-gnueabi-ar
The provided makefiles pass options to the compiler that assume a GCC-like command line syntax. To use a different compiler, you may need to pass different values for CFLAGS
, WARNINGS_CFLAGS
and LDFLAGS
.
To run the unit tests on the host machine, run make test
from the top-level directory. If you are cross-compiling, copy the test executable from the tests
directory to the target machine.
To use the Mbed Crypto APIs, call psa_crypto_init()
before calling any other API. This initializes the library.
To use a key for cryptography operations in Mbed Crypto, you need to first import it. Upon importing, you'll be given a handle to refer to the key for use with other function calls.
Prerequisites for importing keys:
psa_crypto_init
.Importing a key:
psa_status_t status; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; uint8_t data[] = AES_KEY; psa_key_handle_t handle; printf("Import an AES key...\t"); fflush(stdout); /* Initialize PSA Crypto */ status = psa_crypto_init(); if (status != PSA_SUCCESS) { printf("Failed to initialize PSA Crypto\n"); return; } /* Set key attributes */ psa_set_key_usage_flags(&attributes, 0); psa_set_key_algorithm(&attributes, 0); psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); psa_set_key_bits(&attributes, 128); /* Import the key */ status = psa_import_key(&attributes, data, sizeof(data), &handle); if (status != PSA_SUCCESS) { printf("Failed to import key\n"); return; } printf("Imported a key\n"); /* Free the attributes */ psa_reset_key_attributes(&attributes); /* Destroy the key */ psa_destroy_key(handle); mbedtls_psa_crypto_free();
Mbed Crypto provides support for encrypting, decrypting, signing and verifying messages using public key signature algorithms (such as RSA or ECDSA).
Prerequisites for performing asymmetric signature operations:
psa_crypto_init
.PSA_KEY_USAGE_SIGN
to allow signing.PSA_KEY_USAGE_VERIFY
to allow signature verification.To sign a given hash
using RSA:
psa_asymmetric_sign()
and get the output buffer that contains the signature:psa_status_t status; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; uint8_t key[] = RSA_KEY; uint8_t hash[] = "INPUT_FOR_SIGN"; uint8_t signature[PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE] = {0}; size_t signature_length; psa_key_handle_t handle; printf("Sign a message...\t"); fflush(stdout); /* Initialize PSA Crypto */ status = psa_crypto_init(); if (status != PSA_SUCCESS) { printf("Failed to initialize PSA Crypto\n"); return; } /* Set key attributes */ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN); psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_SIGN_RAW); psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR); psa_set_key_bits(&attributes, 1024); /* Import the key */ status = psa_import_key(&attributes, key, sizeof(key), &handle); if (status != PSA_SUCCESS) { printf("Failed to import key\n"); return; } /* Sign message using the key */ status = psa_asymmetric_sign(handle, PSA_ALG_RSA_PKCS1V15_SIGN_RAW, hash, sizeof(hash), signature, sizeof(signature), &signature_length); if (status != PSA_SUCCESS) { printf("Failed to sign\n"); return; } printf("Signed a message\n"); /* Free the attributes */ psa_reset_key_attributes(&attributes); /* Destroy the key */ psa_destroy_key(handle); mbedtls_psa_crypto_free();
Mbed Crypto provides support for encrypting and decrypting messages using various symmetric cipher algorithms (both block and stream ciphers).
Prerequisites to working with the symmetric cipher API:
psa_crypto_init
.PSA_KEY_USAGE_ENCRYPT
to allow encryption or PSA_KEY_USAGE_DECRYPT
to allow decryption).Encrypting a message with a symmetric cipher:
psa_cipher_operation_t
) structure to pass to the cipher functions.psa_cipher_encrypt_setup
to initialize the operation structure and specify the algorithm and the key to be used.psa_cipher_generate_iv
or psa_cipher_set_iv
to generate or set the initialization vector (IV). We recommended psa_cipher_generate_iv
, unless you require a specific IV value.psa_cipher_update
one or more times, passing either the whole or only a fragment of the message each time.psa_cipher_finish
to end the operation and output the encrypted message.Encrypting data using an AES key in cipher block chain (CBC) mode with no padding (assuming all prerequisites have been fulfilled):
enum { block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES), }; psa_status_t status; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING; uint8_t plaintext[block_size] = SOME_PLAINTEXT; uint8_t iv[block_size]; size_t iv_len; uint8_t key[] = AES_KEY; uint8_t output[block_size]; size_t output_len; psa_key_handle_t handle; psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; printf("Encrypt with cipher...\t"); fflush(stdout); /* Initialize PSA Crypto */ status = psa_crypto_init(); if (status != PSA_SUCCESS) { printf("Failed to initialize PSA Crypto\n"); return; } /* Import a key */ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); psa_set_key_algorithm(&attributes, alg); psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); psa_set_key_bits(&attributes, 128); status = psa_import_key(&attributes, key, sizeof(key), &handle); if (status != PSA_SUCCESS) { printf("Failed to import a key\n"); return; } psa_reset_key_attributes(&attributes); /* Encrypt the plaintext */ status = psa_cipher_encrypt_setup(&operation, handle, alg); if (status != PSA_SUCCESS) { printf("Failed to begin cipher operation\n"); return; } status = psa_cipher_generate_iv(&operation, iv, sizeof(iv), &iv_len); if (status != PSA_SUCCESS) { printf("Failed to generate IV\n"); return; } status = psa_cipher_update(&operation, plaintext, sizeof(plaintext), output, sizeof(output), &output_len); if (status != PSA_SUCCESS) { printf("Failed to update cipher operation\n"); return; } status = psa_cipher_finish(&operation, output + output_len, sizeof(output) - output_len, &output_len); if (status != PSA_SUCCESS) { printf("Failed to finish cipher operation\n"); return; } printf("Encrypted plaintext\n"); /* Clean up cipher operation context */ psa_cipher_abort(&operation); /* Destroy the key */ psa_destroy_key(handle); mbedtls_psa_crypto_free();
Decrypting a message with a symmetric cipher:
psa_cipher_operation_t
) structure to pass to the cipher functions.psa_cipher_decrypt_setup
to initialize the operation structure and to specify the algorithm and the key to be used.psa_cipher_set_iv
with the IV for the decryption.psa_cipher_update
one or more times passing either the whole or only a fragment of the message each time.psa_cipher_finish
to end the operation and output the decrypted message.Decrypting encrypted data using an AES key in CBC mode with no padding (assuming all prerequisites have been fulfilled):
enum { block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES), }; psa_status_t status; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING; psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; uint8_t ciphertext[block_size] = SOME_CIPHERTEXT; uint8_t iv[block_size] = ENCRYPTED_WITH_IV; uint8_t key[] = AES_KEY; uint8_t output[block_size]; size_t output_len; psa_key_handle_t handle; printf("Decrypt with cipher...\t"); fflush(stdout); /* Initialize PSA Crypto */ status = psa_crypto_init(); if (status != PSA_SUCCESS) { printf("Failed to initialize PSA Crypto\n"); return; } /* Import a key */ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT); psa_set_key_algorithm(&attributes, alg); psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); psa_set_key_bits(&attributes, 128); status = psa_import_key(&attributes, key, sizeof(key), &handle); if (status != PSA_SUCCESS) { printf("Failed to import a key\n"); return; } psa_reset_key_attributes(&attributes); /* Decrypt the ciphertext */ status = psa_cipher_decrypt_setup(&operation, handle, alg); if (status != PSA_SUCCESS) { printf("Failed to begin cipher operation\n"); return; } status = psa_cipher_set_iv(&operation, iv, sizeof(iv)); if (status != PSA_SUCCESS) { printf("Failed to set IV\n"); return; } status = psa_cipher_update(&operation, ciphertext, sizeof(ciphertext), output, sizeof(output), &output_len); if (status != PSA_SUCCESS) { printf("Failed to update cipher operation\n"); return; } status = psa_cipher_finish(&operation, output + output_len, sizeof(output) - output_len, &output_len); if (status != PSA_SUCCESS) { printf("Failed to finish cipher operation\n"); return; } printf("Decrypted ciphertext\n"); /* Clean up cipher operation context */ psa_cipher_abort(&operation); /* Destroy the key */ psa_destroy_key(handle); mbedtls_psa_crypto_free();
Once you've initialized the operation structure with a successful call to psa_cipher_encrypt_setup
or psa_cipher_decrypt_setup
, you can terminate the operation at any time by calling psa_cipher_abort
.
The call to psa_cipher_abort
frees any resources associated with the operation (except for the operation structure itself). An implicit call to psa_cipher_abort
occurs when any of these conditions occur:
psa_cipher_generate_iv
, psa_cipher_set_iv
or psa_cipher_update
has failed (returning any status other than PSA_SUCCESS
).psa_cipher_finish
.Once psa_cipher_abort
has been called (either implicitly by the implementation or explicitly by the user), the operation structure is invalidated and may not be reused for the same operation. However, the operation structure may be reused for a different operation by calling either psa_cipher_encrypt_setup
or psa_cipher_decrypt_setup
again.
For an operation that has been initialized successfully (by a successful call to psa_cipher_encrypt_setup
or psa_cipher_decrypt_setup
) it is imperative that at some time psa_cipher_abort
is called.
Multiple sequential calls to psa_cipher_abort
on an operation that has already been terminated (either implicitly or explicitly) are safe and have no effect.
Mbed Crypto lets you compute and verify hashes using various hashing algorithms.
Prerequisites to working with the hash APIs:
psa_crypto_init
.To calculate a hash:
psa_hash_operation_t
) to pass to the hash functions.psa_hash_setup
to initialize the operation structure and specify the hash algorithm.psa_hash_update
one or more times, passing either the whole or only a fragment of the message each time.psa_hash_finish
to calculate the hash, or psa_hash_verify
to compare the computed hash with an expected hash value.Calculate the SHA-256
hash of a message:
psa_status_t status; psa_algorithm_t alg = PSA_ALG_SHA_256; psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; unsigned char input[] = { 'a', 'b', 'c' }; unsigned char actual_hash[PSA_HASH_MAX_SIZE]; size_t actual_hash_len; printf("Hash a message...\t"); fflush(stdout); /* Initialize PSA Crypto */ status = psa_crypto_init(); if (status != PSA_SUCCESS) { printf("Failed to initialize PSA Crypto\n"); return; } /* Compute hash of message */ status = psa_hash_setup(&operation, alg); if (status != PSA_SUCCESS) { printf("Failed to begin hash operation\n"); return; } status = psa_hash_update(&operation, input, sizeof(input)); if (status != PSA_SUCCESS) { printf("Failed to update hash operation\n"); return; } status = psa_hash_finish(&operation, actual_hash, sizeof(actual_hash), &actual_hash_len); if (status != PSA_SUCCESS) { printf("Failed to finish hash operation\n"); return; } printf("Hashed a message\n"); /* Clean up hash operation context */ psa_hash_abort(&operation); mbedtls_psa_crypto_free();
Verify the SHA-256
hash of a message:
psa_status_t status; psa_algorithm_t alg = PSA_ALG_SHA_256; psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; unsigned char input[] = { 'a', 'b', 'c' }; unsigned char expected_hash[] = { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }; size_t expected_hash_len = PSA_HASH_SIZE(alg); printf("Verify a hash...\t"); fflush(stdout); /* Initialize PSA Crypto */ status = psa_crypto_init(); if (status != PSA_SUCCESS) { printf("Failed to initialize PSA Crypto\n"); return; } /* Verify message hash */ status = psa_hash_setup(&operation, alg); if (status != PSA_SUCCESS) { printf("Failed to begin hash operation\n"); return; } status = psa_hash_update(&operation, input, sizeof(input)); if (status != PSA_SUCCESS) { printf("Failed to update hash operation\n"); return; } status = psa_hash_verify(&operation, expected_hash, expected_hash_len); if (status != PSA_SUCCESS) { printf("Failed to verify hash\n"); return; } printf("Verified a hash\n"); /* Clean up hash operation context */ psa_hash_abort(&operation); mbedtls_psa_crypto_free();
The API provides the macro PSA_HASH_SIZE
, which returns the expected hash length (in bytes) for the specified algorithm.
Once the operation structure has been successfully initialized by a successful call to psa_hash_setup
, it's possible to terminate the operation at any time by calling psa_hash_abort
. The call to psa_hash_abort
frees any resources associated with the operation (except for the operation structure itself).
An implicit call to psa_hash_abort
occurs when any of these conditions occur:
psa_hash_update
has failed (returning any status other than PSA_SUCCESS
).psa_hash_finish
.psa_hash_verify
.Once psa_hash_abort
has been called (either implicitly by the implementation or explicitly by the user), the operation structure is invalidated and may not be reused for the same operation. However, the operation structure may be reused for a different operation by calling psa_hash_setup
again.
For an operation that has been initialized successfully (by a successful call to psa_hash_setup
) it is imperative that at some time psa_hash_abort
is called.
Multiple sequential calls to psa_hash_abort
on an operation that has already been terminated (either implicitly or explicitly) is safe and has no effect.
Mbed Crypto can generate random data. To generate a random key, use psa_generate_key()
instead of psa_generate_random()
Prerequisites to random generation:
psa_crypto_init()
.Generate a random, ten-byte piece of data:
psa_generate_random()
:psa_status_t status; uint8_t random[10] = { 0 }; printf("Generate random...\t"); fflush(stdout); /* Initialize PSA Crypto */ status = psa_crypto_init(); if (status != PSA_SUCCESS) { printf("Failed to initialize PSA Crypto\n"); return; } status = psa_generate_random(random, sizeof(random)); if (status != PSA_SUCCESS) { printf("Failed to generate a random value\n"); return; } printf("Generated random data\n"); /* Clean up */ mbedtls_psa_crypto_free();
Mbed Crypto provides a key derivation API that lets you derive new keys from existing ones. The key derivation API has functions to take inputs, including other keys and data, and functions to generate outputs, such as new keys or other data. A key derivation context must first be initialized and set up, provided with a key and optionally other data, and then derived data can be read from it either to a buffer or directly sent to a key slot. Refer to the documentation for the particular algorithm (such as HKDF or the TLS1.2 PRF) for information on which inputs to pass when and when you can obtain which outputs.
Prerequisites to working with the key derivation APIs:
psa_crypto_init
.PSA_KEY_USAGE_DERIVE
)PSA_KEY_TYPE_DERIVE
.PSA_ALG_HKDF(PSA_ALG_SHA_256)
).Deriving a new AES-CTR 128-bit encryption key into a given key slot using HKDF with a given key, salt and info:
psa_key_derivation_setup
function, specifying the derivation algorithm PSA_ALG_HKDF(PSA_ALG_SHA_256)
.psa_key_derivation_input_bytes
.psa_key_derivation_input_bytes
.psa_key_derivation_input_key
, referencing a key that can be used for key derivation.PSA_KEY_USAGE_ENCRYPT
parameter and the algorithm PSA_ALG_CTR
for this example.psa_key_derivation_output_key()
.At this point the derived key slot holds a new 128-bit AES-CTR encryption key derived from the key, salt and info provided:
psa_status_t status; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; static const unsigned char key[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b }; static const unsigned char salt[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }; static const unsigned char info[] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 }; psa_algorithm_t alg = PSA_ALG_HKDF(PSA_ALG_SHA_256); psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; size_t derived_bits = 128; size_t capacity = PSA_BITS_TO_BYTES(derived_bits); psa_key_handle_t base_key; psa_key_handle_t derived_key; printf("Derive a key (HKDF)...\t"); fflush(stdout); /* Initialize PSA Crypto */ status = psa_crypto_init(); if (status != PSA_SUCCESS) { printf("Failed to initialize PSA Crypto\n"); return; } /* Import a key for use in key derivation. If such a key has already been * generated or imported, you can skip this part. */ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); psa_set_key_algorithm(&attributes, alg); psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE); status = psa_import_key(&attributes, key, sizeof(key), &base_key); if (status != PSA_SUCCESS) { printf("Failed to import a key\n"); return; } psa_reset_key_attributes(&attributes); /* Derive a key */ status = psa_key_derivation_setup(&operation, alg); if (status != PSA_SUCCESS) { printf("Failed to begin key derivation\n"); return; } status = psa_key_derivation_set_capacity(&operation, capacity); if (status != PSA_SUCCESS) { printf("Failed to set capacity\n"); return; } status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SALT, salt, sizeof(salt)); if (status != PSA_SUCCESS) { printf("Failed to input salt (extract)\n"); return; } status = psa_key_derivation_input_key(&operation, PSA_KEY_DERIVATION_INPUT_SECRET, base_key); if (status != PSA_SUCCESS) { printf("Failed to input key (extract)\n"); return; } status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_INFO, info, sizeof(info)); if (status != PSA_SUCCESS) { printf("Failed to input info (expand)\n"); return; } psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); psa_set_key_algorithm(&attributes, PSA_ALG_CTR); psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); psa_set_key_bits(&attributes, 128); status = psa_key_derivation_output_key(&attributes, &operation, &derived_key); if (status != PSA_SUCCESS) { printf("Failed to derive key\n"); return; } psa_reset_key_attributes(&attributes); printf("Derived key\n"); /* Clean up key derivation operation */ psa_key_derivation_abort(&operation); /* Destroy the keys */ psa_destroy_key(derived_key); psa_destroy_key(base_key); mbedtls_psa_crypto_free();
Mbed Crypto provides a simple way for authenticate and encrypt with associated data (AEAD) supporting PSA_ALG_CCM
algorithm.
Prerequisites to working with the AEAD ciphers APIs:
psa_crypto_init
.PSA_KEY_USAGE_ENCRYPT
or PSA_KEY_USAGE_DECRYPT
.To authenticate and encrypt a message:
psa_status_t status; static const uint8_t key[] = { 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF }; static const uint8_t nonce[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B }; static const uint8_t additional_data[] = { 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25, 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 }; static const uint8_t input_data[] = { 0xB9, 0x6B, 0x49, 0xE2, 0x1D, 0x62, 0x17, 0x41, 0x63, 0x28, 0x75, 0xDB, 0x7F, 0x6C, 0x92, 0x43, 0xD2, 0xD7, 0xC2 }; uint8_t *output_data = NULL; size_t output_size = 0; size_t output_length = 0; size_t tag_length = 16; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_handle_t handle; printf("Authenticate encrypt...\t"); fflush(stdout); /* Initialize PSA Crypto */ status = psa_crypto_init(); if (status != PSA_SUCCESS) { printf("Failed to initialize PSA Crypto\n"); return; } output_size = sizeof(input_data) + tag_length; output_data = (uint8_t *)malloc(output_size); if (!output_data) { printf("Out of memory\n"); return; } /* Import a key */ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); psa_set_key_algorithm(&attributes, PSA_ALG_CCM); psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); psa_set_key_bits(&attributes, 128); status = psa_import_key(&attributes, key, sizeof(key), &handle); psa_reset_key_attributes(&attributes); /* Authenticate and encrypt */ status = psa_aead_encrypt(handle, PSA_ALG_CCM, nonce, sizeof(nonce), additional_data, sizeof(additional_data), input_data, sizeof(input_data), output_data, output_size, &output_length); if (status != PSA_SUCCESS) { printf("Failed to authenticate and encrypt\n"); return; } printf("Authenticated and encrypted\n"); /* Clean up */ free(output_data); /* Destroy the key */ psa_destroy_key(handle); mbedtls_psa_crypto_free();
To authenticate and decrypt a message:
psa_status_t status; static const uint8_t key[] = { 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF }; static const uint8_t nonce[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B }; static const uint8_t additional_data[] = { 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25, 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 }; static const uint8_t input_data[] = { 0x20, 0x30, 0xE0, 0x36, 0xED, 0x09, 0xA0, 0x45, 0xAF, 0x3C, 0xBA, 0xEE, 0x0F, 0xC8, 0x48, 0xAF, 0xCD, 0x89, 0x54, 0xF4, 0xF6, 0x3F, 0x28, 0x9A, 0xA1, 0xDD, 0xB2, 0xB8, 0x09, 0xCD, 0x7C, 0xE1, 0x46, 0xE9, 0x98 }; uint8_t *output_data = NULL; size_t output_size = 0; size_t output_length = 0; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_handle_t handle; printf("Authenticate decrypt...\t"); fflush(stdout); /* Initialize PSA Crypto */ status = psa_crypto_init(); if (status != PSA_SUCCESS) { printf("Failed to initialize PSA Crypto\n"); return; } output_size = sizeof(input_data); output_data = (uint8_t *)malloc(output_size); if (!output_data) { printf("Out of memory\n"); return; } /* Import a key */ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT); psa_set_key_algorithm(&attributes, PSA_ALG_CCM); psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); psa_set_key_bits(&attributes, 128); status = psa_import_key(&attributes, key, sizeof(key), &handle); if (status != PSA_SUCCESS) { printf("Failed to import a key\n"); return; } psa_reset_key_attributes(&attributes); /* Authenticate and decrypt */ status = psa_aead_decrypt(handle, PSA_ALG_CCM, nonce, sizeof(nonce), additional_data, sizeof(additional_data), input_data, sizeof(input_data), output_data, output_size, &output_length); if (status != PSA_SUCCESS) { printf("Failed to authenticate and decrypt %ld\n", status); return; } printf("Authenticated and decrypted\n"); /* Clean up */ free(output_data); /* Destroy the key */ psa_destroy_key(handle); mbedtls_psa_crypto_free();
Mbed Crypto provides a simple way to generate a key or key pair.
Prerequisites to using key generation and export APIs:
psa_crypto_init
.Generate an ECDSA key:
psa_set_key_algorithm()
with the chosen ECDSA algorithm (such as PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)
). We don't set PSA_KEY_USAGE_EXPORT
as we only want to export the public key, not the key pair (or private key).psa_generate_key()
.psa_export_public_key()
:enum { key_bits = 256, }; psa_status_t status; size_t exported_length = 0; static uint8_t exported[PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits)]; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_handle_t handle; printf("Generate a key pair...\t"); fflush(stdout); /* Initialize PSA Crypto */ status = psa_crypto_init(); if (status != PSA_SUCCESS) { printf("Failed to initialize PSA Crypto\n"); return; } /* Generate a key */ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN); psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)); psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1)); psa_set_key_bits(&attributes, key_bits); status = psa_generate_key(&attributes, &handle); if (status != PSA_SUCCESS) { printf("Failed to generate key\n"); return; } psa_reset_key_attributes(&attributes); status = psa_export_public_key(handle, exported, sizeof(exported), &exported_length); if (status != PSA_SUCCESS) { printf("Failed to export public key %ld\n", status); return; } printf("Exported a public key\n"); /* Destroy the key */ psa_destroy_key(handle); mbedtls_psa_crypto_free();
More information on Mbed Crypto.
More information on PSA Crypto.