From 884738a2d65104879b59d9d11ee322c438a39f85 Mon Sep 17 00:00:00 2001 From: Jaeden Amero Date: Fri, 16 Aug 2019 17:58:31 +0100 Subject: [PATCH] getting_started: Update for PSA Crypto API 1.0b3 --- docs/getting_started.md | 769 +++++++++++++++++++++++++++++----------- 1 file changed, 564 insertions(+), 205 deletions(-) diff --git a/docs/getting_started.md b/docs/getting_started.md index 9ab4f8f6c..4d380e088 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -63,35 +63,50 @@ To use the Mbed Crypto APIs, call `psa_crypto_init()` before calling any other A ### Importing a key -To use a key for cryptography operations in Mbed Crypto, you need to first import it into a key slot. Each slot can store only one key at a time. The slot where the key is stored must be unoccupied, and valid for a key of the chosen type. +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 to importing keys: +Prerequisites for importing keys: * Initialize the library with a successful call to `psa_crypto_init`. -Importing a key and checking key information: -1. Import a key pair into key slot `1`. -1. Test the information stored in this slot: +Importing a key: ```C - int key_slot = 1; - uint8_t *data = "KEY_PAIR_KEY_DATA"; - size_t data_size; - psa_key_type_t type = PSA_KEY_TYPE_RSA_PUBLIC_KEY; - size_t got_bits; - psa_key_type_t got_type; - size_t expected_bits = data_size; - psa_key_type_t type = PSA_KEY_TYPE_RAW_DATA; - size_t export_size = data_size; + psa_status_t status; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + uint8_t data[] = AES_KEY; + psa_key_handle_t handle; - psa_crypto_init(); + 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(key_slot, type, data, data_size); + 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"); - /* Test the key information */ - status = psa_get_key_information(slot, &got_type, &got_bits); + /* Free the attributes */ + psa_reset_key_attributes(&attributes); /* Destroy the key */ - psa_destroy_key(key_slot); + psa_destroy_key(handle); + mbedtls_psa_crypto_free(); ``` @@ -99,48 +114,70 @@ Importing a key and checking key information: Mbed Crypto provides support for encrypting, decrypting, signing and verifying messages using public key signature algorithms (such as RSA or ECDSA). -Prerequisites to working with the asymmetric cipher API: +Prerequisites for performing asymmetric signature operations: * Initialize the library with a successful call to `psa_crypto_init`. -* Configure the key policy accordingly: - * `PSA_KEY_USAGE_SIGN` to allow signing. - * `PSA_KEY_USAGE_VERIFY` to allow signature verification. -* Have a valid key in the key slot. +* Have a valid key with appropriate attributes set: + * Usage flag `PSA_KEY_USAGE_SIGN` to allow signing. + * Usage flag `PSA_KEY_USAGE_VERIFY` to allow signature verification. + * Algorithm set to desired signature algorithm. -To sign a given message `payload` using RSA: -1. Set the key policy of the chosen key slot by calling `psa_key_policy_set_usage()` with the `PSA_KEY_USAGE_SIGN` parameter and the algorithm `PSA_ALG_RSA_PKCS1V15_SIGN_RAW`. -This allows the key in the key slot to be used for RSA signing. -1. Import the key into the key slot by calling `psa_import_key()`. You can use an already imported key instead of importing a new one. -1. Call `psa_asymmetric_sign()` and get the output buffer that contains the signature: +To sign a given `hash` using RSA: +1. Call `psa_asymmetric_sign()` and get the output buffer that contains the + signature: ```C psa_status_t status; - int key_slot = 1; - unsigned char key[] = "RSA_KEY"; - unsigned char payload[] = "ASYMMETRIC_INPUT_FOR_SIGN"; - psa_key_policy_t policy = PSA_KEY_POLICY_INIT; - unsigned char signature[PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE] = {0}; + 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 */ - psa_key_policy_set_usage(&policy, PSA_KEY_USAGE_SIGN, - PSA_ALG_RSA_PKCS1V15_SIGN_RAW); - status = psa_set_key_policy(key_slot, &policy); + status = psa_import_key(&attributes, key, sizeof(key), &handle); + if (status != PSA_SUCCESS) { + printf("Failed to import key\n"); + return; + } - status = psa_import_key(key_slot, PSA_KEY_TYPE_RSA_KEY_PAIR, - key, sizeof(key)); - - /* Sing message using the key */ - status = psa_asymmetric_sign(key_slot, PSA_ALG_RSA_PKCS1V15_SIGN_RAW, - payload, sizeof(payload), + /* 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(key_slot); + psa_destroy_key(handle); + mbedtls_psa_crypto_free(); ``` -### Encrypting or decrypting using symmetric ciphers +### Using symmetric ciphers Mbed Crypto provides support for encrypting and decrypting messages using various symmetric cipher algorithms (both block and stream ciphers). @@ -156,32 +193,78 @@ Encrypting a message with a symmetric cipher: 1. Call `psa_cipher_update` one or more times, passing either the whole or only a fragment of the message each time. 1. Call `psa_cipher_finish` to end the operation and output the encrypted message. -Encrypting random data using an AES key in cipher block chain (CBC) mode with no padding (assuming all prerequisites have been fulfilled): +Encrypting data using an AES key in cipher block chain (CBC) mode with no padding (assuming all prerequisites have been fulfilled): ```c - psa_key_slot_t key_slot = 1; + 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; - size_t block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES); - unsigned char input[block_size]; - unsigned char iv[block_size]; + uint8_t plaintext[block_size] = SOME_PLAINTEXT; + uint8_t iv[block_size]; size_t iv_len; - unsigned char output[block_size]; + 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; - /* generate some random data to be encrypted */ - psa_generate_random(input, sizeof(input)); + 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"); - /* encrypt the key */ - psa_cipher_encrypt_setup(&operation, key_slot, alg); - psa_cipher_generate_iv(&operation, iv, sizeof(iv), &iv_len); - psa_cipher_update(&operation, input, sizeof(input), - output, sizeof(output), - &output_len); - psa_cipher_finish(&operation, - output + output_len, sizeof(output) - output_len, - &output_len); /* 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: @@ -194,31 +277,75 @@ Decrypting a message with a symmetric cipher: Decrypting encrypted data using an AES key in CBC mode with no padding (assuming all prerequisites have been fulfilled): ```c - psa_key_slot_t key_slot = 1; + 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; - size_t block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES); - unsigned char input[block_size]; - unsigned char iv[block_size]; - size_t iv_len; - unsigned char output[block_size]; + 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; - /* setup input data */ - fetch_iv(iv, sizeof(iv)); /* fetch the IV used when the data was encrypted */ - fetch_input(input, sizeof(input)); /* fetch the data to be decrypted */ + 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"); - /* encrypt the encrypted data */ - psa_cipher_decrypt_setup(&operation, key_slot, alg); - psa_cipher_set_iv(&operation, iv, sizeof(iv)); - psa_cipher_update(&operation, input, sizeof(input), - output, sizeof(output), - &output_len); - psa_cipher_finish(&operation, - output + output_len, sizeof(output) - output_len, - &output_len); /* Clean up cipher operation context */ psa_cipher_abort(&operation); + + /* Destroy the key */ + psa_destroy_key(handle); + + mbedtls_psa_crypto_free(); ``` #### Handling cipher operation contexts @@ -237,9 +364,8 @@ Multiple sequential calls to `psa_cipher_abort` on an operation that has already ### Hashing a message -Mbed Crypto lets you compute and verify hashes using various hashing algorithms. - -The current implementation supports the following hash algorithms: `MD2`, `MD4`, `MD5`, `RIPEMD160`, `SHA-1`, `SHA-224`, `SHA-256`, `SHA-384`, and `SHA-512`. +Mbed Crypto lets you compute and verify hashes using various hashing +algorithms. Prerequisites to working with the hash APIs: * Initialize the library with a successful call to `psa_crypto_init`. @@ -252,25 +378,54 @@ To calculate a hash: Calculate the `SHA-256` hash of a message: ```c + psa_status_t status; psa_algorithm_t alg = PSA_ALG_SHA_256; - psa_hash_operation_t operation; + 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 */ - psa_hash_setup(&operation, alg); - psa_hash_update(&operation, input, sizeof(input)); - psa_hash_finish(&operation, actual_hash, sizeof(actual_hash), &actual_hash_len); + 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: ```c + psa_status_t status; psa_algorithm_t alg = PSA_ALG_SHA_256; - psa_hash_operation_t operation; + 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, @@ -279,10 +434,39 @@ Verify the `SHA-256` hash of a message: }; 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 */ - psa_hash_setup(&operation, alg); - psa_hash_update(&operation, input, sizeof(input)); - psa_hash_verify(&operation, expected_hash, expected_hash_len); + 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. @@ -304,86 +488,172 @@ Multiple sequential calls to `psa_hash_abort` on an operation that has already b ### Generating a random value -Mbed Crypto can generate random data. +Mbed Crypto can generate random data. To generate a random key, use +`psa_generate_key()` instead of `psa_generate_random()` Prerequisites to random generation: -* Initialize the library with a successful call to `psa_crypto_init`. +* Initialize the library with a successful call to `psa_crypto_init()`. Generate a random, ten-byte piece of data: 1. Generate random bytes by calling `psa_generate_random()`: ```C psa_status_t status; uint8_t random[10] = { 0 }; - psa_crypto_init(); - status = psa_generate_random(random, sizeof(random)); + 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(); ``` ### Deriving a new key from an existing key -Mbed Crypto provides a key derivation API that lets you derive new keys from existing ones. Key derivation is based upon the generator abstraction. A generator 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 imported into a key slot. +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: * Initialize the library with a successful call to `psa_crypto_init`. -* Configure the key policy for the key used for derivation (`PSA_KEY_USAGE_DERIVE`) -* The key type must be `PSA_KEY_TYPE_DERIVE`. +* Use a key with the appropriate attributes set: + * Usage flags set for key derivation (`PSA_KEY_USAGE_DERIVE`) + * Key type set to `PSA_KEY_TYPE_DERIVE`. + * Algorithm set to a key derivation algorithm + (`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 label: -1. Set the key policy for key derivation by calling `psa_key_policy_set_usage()` with `PSA_KEY_USAGE_DERIVE` parameter, and the algorithm `PSA_ALG_HKDF(PSA_ALG_SHA_256)`. -1. Import the key into the key slot by calling `psa_import_key()`. You can skip this step and the previous one if the key has already been imported into a known key slot. -1. Set up the generator using the `psa_key_derivation` function providing a key slot containing a key that can be used for key derivation and a salt and label (Note: salt and label are optional). -1. Initiate a key policy to for the derived key by calling `psa_key_policy_set_usage()` with `PSA_KEY_USAGE_ENCRYPT` parameter and the algorithm `PSA_ALG_CTR`. -1. Set the key policy to the derived key slot. -1. Import a key from generator into the desired key slot using (`psa_key_derivation_output_key`). -1. Clean up generator. +Deriving a new AES-CTR 128-bit encryption key into a given key slot using HKDF +with a given key, salt and info: +1. Set up the key derivation context using the `psa_key_derivation_setup` +function, specifying the derivation algorithm `PSA_ALG_HKDF(PSA_ALG_SHA_256)`. +1. Provide an optional salt with `psa_key_derivation_input_bytes`. +1. Provide info with `psa_key_derivation_input_bytes`. +1. Provide secret with `psa_key_derivation_input_key`, referencing a key that + can be used for key derivation. +1. Set the key attributes desired for the new derived key. We'll set + `PSA_KEY_USAGE_ENCRYPT` parameter and the algorithm `PSA_ALG_CTR` for this + example. +1. Derive the key by calling `psa_key_derivation_output_key()`. +1. Clean up the key derivation context. -At this point the derived key slot holds a new 128-bit AES-CTR encryption key derived from the key, salt and label provided: +At this point the derived key slot holds a new 128-bit AES-CTR encryption key +derived from the key, salt and info provided: ```C - psa_key_slot_t base_key = 1; - psa_key_slot_t derived_key = 2; - psa_key_policy_t policy = PSA_KEY_POLICY_INIT; - - unsigned char key[] = { + 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 }; - - unsigned char salt[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }; - - unsigned char label[] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, - 0xf7, 0xf8, 0xf9 }; - + 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_policy_t policy = PSA_KEY_POLICY_INIT; - psa_key_derivation_operation_t generator = PSA_KEY_DERIVATION_OPERATION_INIT; + 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 imported you can skip this part */ - psa_key_policy_set_usage(&policy, PSA_KEY_USAGE_DERIVE, alg); - status = psa_set_key_policy(base_key, &policy); + /* 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); - status = psa_import_key(base_key, PSA_KEY_TYPE_DERIVE, key, sizeof(key)); + /* 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); - /* Derive a key into a key slot*/ - status = psa_key_derivation(&generator, base_key, alg, salt, sizeof(salt), - label, sizeof(label), capacity); + printf("Derived key\n"); - psa_key_policy_set_usage(&policy, PSA_KEY_USAGE_ENCRYPT, PSA_ALG_CTR); + /* Clean up key derivation operation */ + psa_key_derivation_abort(&operation); - psa_set_key_policy(derived_key, &policy); + /* Destroy the keys */ + psa_destroy_key(derived_key); + psa_destroy_key(base_key); - psa_key_derivation_output_key(derived_key, PSA_KEY_TYPE_AES, derived_bits, &generator); - - /* Clean up generator and key */ - psa_key_derivation_abort(&generator); - /* as part of clean up you may want to clean up the keys used by calling: - * psa_destroy_key( base_key ); or psa_destroy_key( derived_key ); */ mbedtls_psa_crypto_free(); ``` @@ -393,95 +663,152 @@ Mbed Crypto provides a simple way for authenticate and encrypt with associated d Prerequisites to working with the AEAD ciphers APIs: * Initialize the library with a successful call to `psa_crypto_init`. -* The key policy for the key used for derivation must be configured accordingly (`PSA_KEY_USAGE_ENCRYPT` or `PSA_KEY_USAGE_DECRYPT`). +* The key attributes for the key used for derivation must have usage flags + `PSA_KEY_USAGE_ENCRYPT` or `PSA_KEY_USAGE_DECRYPT`. To authenticate and encrypt a message: ```C - int slot = 1; psa_status_t status; - unsigned char key[] = { 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF }; - - unsigned char nonce[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B }; - - unsigned char additional_data[] = { 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25, 0x20, - 0xC3, 0x3C, 0x49, 0xFD, 0x70 }; - - unsigned char input_data[] = { 0xB9, 0x6B, 0x49, 0xE2, 0x1D, 0x62, 0x17, 0x41, - 0x63, 0x28, 0x75, 0xDB, 0x7F, 0x6C, 0x92, 0x43, - 0xD2, 0xD7, 0xC2 }; - unsigned char *output_data = NULL; + 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_policy_t policy = PSA_KEY_POLICY_INIT; + 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 = malloc(output_size); - status = psa_crypto_init(); + output_data = (uint8_t *)malloc(output_size); + if (!output_data) { + printf("Out of memory\n"); + return; + } - psa_key_policy_set_usage(&policy, PSA_KEY_USAGE_ENCRYPT, PSA_ALG_CCM); - status = psa_set_key_policy(slot, &policy); + /* 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); - status = psa_import_key(slot, PSA_KEY_TYPE_AES, key, sizeof(key)); - - status = psa_aead_encrypt(slot, PSA_ALG_CCM, + /* 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); - psa_destroy_key(slot); - mbedtls_free(output_data); mbedtls_psa_crypto_free(); ``` To authenticate and decrypt a message: ```C - int slot = 1; psa_status_t status; - unsigned char key[] = { + static const uint8_t key[] = { 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF - }; - - unsigned char nonce[] = { 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25, 0x20, 0xC3, - 0x3C, 0x49, 0xFD, 0x70 - }; - - unsigned char additional_data[] = { 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25, 0x20, - 0xC3, 0x3C, 0x49, 0xFD, 0x70 - }; - unsigned char input_data[] = { 0xB9, 0x6B, 0x49, 0xE2, 0x1D, 0x62, 0x17, 0x41, - 0x63, 0x28, 0x75, 0xDB, 0x7F, 0x6C, 0x92, 0x43, - 0xD2, 0xD7, 0xC2 - }; - unsigned char *output_data = NULL; + 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_policy_t policy = PSA_KEY_POLICY_INIT; + 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 = malloc(output_size); - status = psa_crypto_init(); + output_data = (uint8_t *)malloc(output_size); + if (!output_data) { + printf("Out of memory\n"); + return; + } - psa_key_policy_set_usage(&policy, PSA_KEY_USAGE_DECRYPT, PSA_ALG_CCM); - status = psa_set_key_policy(slot, &policy); + /* 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); - status = psa_import_key(slot, PSA_KEY_TYPE_AES, key, sizeof(key)); - - status = psa_aead_decrypt(slot, PSA_ALG_CCM, + /* 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); - psa_destroy_key(slot); - mbedtls_free(output_data); mbedtls_psa_crypto_free(); ``` @@ -492,29 +819,61 @@ Mbed Crypto provides a simple way to generate a key or key pair. Prerequisites to using key generation and export APIs: * Initialize the library with a successful call to `psa_crypto_init`. -Generate a piece of random 128-bit AES data: -1. Set the key policy for key generation by calling `psa_key_policy_set_usage()` with the `PSA_KEY_USAGE_EXPORT` parameter and the algorithm `PSA_ALG_GCM`. -1. Generate a random AES key by calling `psa_generate_key()`. -1. Export the generated key by calling `psa_export_key()`: +Generate an ECDSA key: +1. Set the desired key attributes for key generation by calling + `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). +1. Generate a key by calling `psa_generate_key()`. +1. Export the generated public key by calling `psa_export_public_key()` +: ```C - int slot = 1; - size_t bits = 128; - size_t exported_size = bits; + enum { + key_bits = 256, + }; + psa_status_t status; size_t exported_length = 0; - uint8_t *exported = malloc(exported_size); - psa_key_policy_t policy = PSA_KEY_POLICY_INIT; + 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; - psa_crypto_init(); + printf("Generate a key pair...\t"); + fflush(stdout); - psa_key_policy_set_usage(&policy, PSA_KEY_USAGE_EXPORT, PSA_ALG_GCM); - psa_set_key_policy(slot, &policy); + /* Initialize PSA Crypto */ + status = psa_crypto_init(); + if (status != PSA_SUCCESS) { + printf("Failed to initialize PSA Crypto\n"); + return; + } /* Generate a key */ - psa_generate_key(slot, PSA_KEY_TYPE_AES, bits); + 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); - psa_export_key(slot, exported, exported_size, &exported_length) + 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); - psa_destroy_key(slot); mbedtls_psa_crypto_free(); ```