1## Getting started with Mbed Crypto 2 3### What is Mbed Crypto? 4 5Mbed Crypto is an open source cryptographic library that supports a wide range of cryptographic operations, including: 6* Key management 7* Hashing 8* Symmetric cryptography 9* Asymmetric cryptography 10* Message authentication (MAC) 11* Key generation and derivation 12* Authenticated encryption with associated data (AEAD) 13 14The Mbed Crypto library is a reference implementation of the cryptography interface of the Arm Platform Security Architecture (PSA). It is written in portable C. 15 16The Mbed Crypto library is distributed under the Apache License, version 2.0. 17 18#### Platform Security Architecture (PSA) 19 20Arm's Platform Security Architecture (PSA) is a holistic set of threat models, 21security analyses, hardware and firmware architecture specifications, and an open source firmware reference implementation. PSA provides a recipe, based on industry best practice, that enables you to design security into both hardware and firmware consistently. Part of the API provided by PSA is the cryptography interface, which provides access to a set of primitives. 22 23### Using Mbed Crypto 24 25* [Getting the Mbed Crypto library](#getting-the-mbed-crypto-library) 26* [Building the Mbed Crypto library](#building-the-mbed-crypto-library) 27* [Using the Mbed Crypto library](#using-the-mbed-crypto-library) 28* [Importing a key](#importing-a-key) 29* [Signing a message using RSA](#signing-a-message-using-RSA) 30* [Encrypting or decrypting using symmetric ciphers](#encrypting-or-decrypting-using-symmetric-ciphers) 31* [Hashing a message](#hashing-a-message) 32* [Deriving a new key from an existing key](#deriving-a-new-key-from-an-existing-key) 33* [Generating a random value](#generating-a-random-value) 34* [Authenticating and encrypting or decrypting a message](#authenticating-and-encrypting-or-decrypting-a-message) 35* [Generating and exporting keys](#generating-and-exporting-keys) 36* [More about the Mbed Crypto library](#more-about-the-mbed-crypto-library) 37 38### Getting the Mbed Crypto library 39 40Mbed Crypto releases are available in the [public GitHub repository](https://github.com/ARMmbed/mbed-crypto). 41 42### Building the Mbed Crypto library 43 44**Prerequisites to building the library with the provided makefiles:** 45* GNU Make. 46* A C toolchain (compiler, linker, archiver). 47* Python 2 or Python 3 (either works) to generate the test code. 48* Perl to run the tests. 49 50If 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. 51 52To select a different compiler, set the `CC` variable to the name or path of the compiler and linker (default: `cc`) and set `AR` to a compatible archiver (default: `ar`); for example: 53``` 54make CC=arm-linux-gnueabi-gcc AR=arm-linux-gnueabi-ar 55``` 56The 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`. 57 58To 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. 59 60### Using the Mbed Crypto library 61 62To use the Mbed Crypto APIs, call `psa_crypto_init()` before calling any other API. This initializes the library. 63 64### Importing a key 65 66To use a key for cryptography operations in Mbed Crypto, you need to first 67import it. The import operation returns the identifier of the key for use 68with other function calls. 69 70**Prerequisites to importing keys:** 71* Initialize the library with a successful call to `psa_crypto_init()`. 72 73This example shows how to import a key: 74```C 75void import_a_key(const uint8_t *key, size_t key_len) 76{ 77 psa_status_t status; 78 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 79 psa_key_id_t key_id; 80 81 printf("Import an AES key...\t"); 82 fflush(stdout); 83 84 /* Initialize PSA Crypto */ 85 status = psa_crypto_init(); 86 if (status != PSA_SUCCESS) { 87 printf("Failed to initialize PSA Crypto\n"); 88 return; 89 } 90 91 /* Set key attributes */ 92 psa_set_key_usage_flags(&attributes, 0); 93 psa_set_key_algorithm(&attributes, 0); 94 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); 95 psa_set_key_bits(&attributes, 128); 96 97 /* Import the key */ 98 status = psa_import_key(&attributes, key, key_len, &key_id); 99 if (status != PSA_SUCCESS) { 100 printf("Failed to import key\n"); 101 return; 102 } 103 printf("Imported a key\n"); 104 105 /* Free the attributes */ 106 psa_reset_key_attributes(&attributes); 107 108 /* Destroy the key */ 109 psa_destroy_key(key_id); 110 111 mbedtls_psa_crypto_free(); 112} 113``` 114 115### Signing a message using RSA 116 117Mbed Crypto supports encrypting, decrypting, signing and verifying messages using public key signature algorithms, such as RSA or ECDSA. 118 119**Prerequisites to performing asymmetric signature operations:** 120* Initialize the library with a successful call to `psa_crypto_init()`. 121* Have a valid key with appropriate attributes set: 122 * Usage flag `PSA_KEY_USAGE_SIGN_HASH` to allow signing. 123 * Usage flag `PSA_KEY_USAGE_VERIFY_HASH` to allow signature verification. 124 * Algorithm set to the desired signature algorithm. 125 126This example shows how to sign a hash that has already been calculated: 127```C 128void sign_a_message_using_rsa(const uint8_t *key, size_t key_len) 129{ 130 psa_status_t status; 131 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 132 uint8_t hash[32] = {0x50, 0xd8, 0x58, 0xe0, 0x98, 0x5e, 0xcc, 0x7f, 133 0x60, 0x41, 0x8a, 0xaf, 0x0c, 0xc5, 0xab, 0x58, 134 0x7f, 0x42, 0xc2, 0x57, 0x0a, 0x88, 0x40, 0x95, 135 0xa9, 0xe8, 0xcc, 0xac, 0xd0, 0xf6, 0x54, 0x5c}; 136 uint8_t signature[PSA_SIGNATURE_MAX_SIZE] = {0}; 137 size_t signature_length; 138 psa_key_id_t key_id; 139 140 printf("Sign a message...\t"); 141 fflush(stdout); 142 143 /* Initialize PSA Crypto */ 144 status = psa_crypto_init(); 145 if (status != PSA_SUCCESS) { 146 printf("Failed to initialize PSA Crypto\n"); 147 return; 148 } 149 150 /* Set key attributes */ 151 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH); 152 psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_SIGN_RAW); 153 psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR); 154 psa_set_key_bits(&attributes, 1024); 155 156 /* Import the key */ 157 status = psa_import_key(&attributes, key, key_len, &key_id); 158 if (status != PSA_SUCCESS) { 159 printf("Failed to import key\n"); 160 return; 161 } 162 163 /* Sign message using the key */ 164 status = psa_sign_hash(key_id, PSA_ALG_RSA_PKCS1V15_SIGN_RAW, 165 hash, sizeof(hash), 166 signature, sizeof(signature), 167 &signature_length); 168 if (status != PSA_SUCCESS) { 169 printf("Failed to sign\n"); 170 return; 171 } 172 173 printf("Signed a message\n"); 174 175 /* Free the attributes */ 176 psa_reset_key_attributes(&attributes); 177 178 /* Destroy the key */ 179 psa_destroy_key(key_id); 180 181 mbedtls_psa_crypto_free(); 182} 183``` 184 185### Using symmetric ciphers 186 187Mbed Crypto supports encrypting and decrypting messages using various symmetric cipher algorithms (both block and stream ciphers). 188 189**Prerequisites to working with the symmetric cipher API:** 190* Initialize the library with a successful call to `psa_crypto_init()`. 191* Have a symmetric key. This key's usage flags must include `PSA_KEY_USAGE_ENCRYPT` to allow encryption or `PSA_KEY_USAGE_DECRYPT` to allow decryption. 192 193**To encrypt a message with a symmetric cipher:** 1941. Allocate an operation (`psa_cipher_operation_t`) structure to pass to the cipher functions. 1951. Initialize the operation structure to zero or to `PSA_CIPHER_OPERATION_INIT`. 1961. Call `psa_cipher_encrypt_setup()` to specify the algorithm and the key to be used. 1971. Call either `psa_cipher_generate_iv()` or `psa_cipher_set_iv()` to generate or set the initialization vector (IV). We recommend calling `psa_cipher_generate_iv()`, unless you require a specific IV value. 1981. Call `psa_cipher_update()` with the message to encrypt. You may call this function multiple times, passing successive fragments of the message on successive calls. 1991. Call `psa_cipher_finish()` to end the operation and output the encrypted message. 200 201This example shows how to encrypt data using an AES (Advanced Encryption Standard) key in CBC (Cipher Block Chaining) mode with no padding (assuming all prerequisites have been fulfilled): 202```c 203void encrypt_with_symmetric_ciphers(const uint8_t *key, size_t key_len) 204{ 205 enum { 206 block_size = PSA_BLOCK_CIPHER_BLOCK_LENGTH(PSA_KEY_TYPE_AES), 207 }; 208 psa_status_t status; 209 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 210 psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING; 211 uint8_t plaintext[block_size] = SOME_PLAINTEXT; 212 uint8_t iv[block_size]; 213 size_t iv_len; 214 uint8_t output[block_size]; 215 size_t output_len; 216 psa_key_id_t key_id; 217 psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; 218 219 printf("Encrypt with cipher...\t"); 220 fflush(stdout); 221 222 /* Initialize PSA Crypto */ 223 status = psa_crypto_init(); 224 if (status != PSA_SUCCESS) 225 { 226 printf("Failed to initialize PSA Crypto\n"); 227 return; 228 } 229 230 /* Import a key */ 231 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); 232 psa_set_key_algorithm(&attributes, alg); 233 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); 234 psa_set_key_bits(&attributes, 128); 235 status = psa_import_key(&attributes, key, key_len, &key_id); 236 if (status != PSA_SUCCESS) { 237 printf("Failed to import a key\n"); 238 return; 239 } 240 psa_reset_key_attributes(&attributes); 241 242 /* Encrypt the plaintext */ 243 status = psa_cipher_encrypt_setup(&operation, key_id, alg); 244 if (status != PSA_SUCCESS) { 245 printf("Failed to begin cipher operation\n"); 246 return; 247 } 248 status = psa_cipher_generate_iv(&operation, iv, sizeof(iv), &iv_len); 249 if (status != PSA_SUCCESS) { 250 printf("Failed to generate IV\n"); 251 return; 252 } 253 status = psa_cipher_update(&operation, plaintext, sizeof(plaintext), 254 output, sizeof(output), &output_len); 255 if (status != PSA_SUCCESS) { 256 printf("Failed to update cipher operation\n"); 257 return; 258 } 259 status = psa_cipher_finish(&operation, output + output_len, 260 sizeof(output) - output_len, &output_len); 261 if (status != PSA_SUCCESS) { 262 printf("Failed to finish cipher operation\n"); 263 return; 264 } 265 printf("Encrypted plaintext\n"); 266 267 /* Clean up cipher operation context */ 268 psa_cipher_abort(&operation); 269 270 /* Destroy the key */ 271 psa_destroy_key(key_id); 272 273 mbedtls_psa_crypto_free(); 274} 275``` 276 277**To decrypt a message with a symmetric cipher:** 2781. Allocate an operation (`psa_cipher_operation_t`) structure to pass to the cipher functions. 2791. Initialize the operation structure to zero or to `PSA_CIPHER_OPERATION_INIT`. 2801. Call `psa_cipher_decrypt_setup()` to specify the algorithm and the key to be used. 2811. Call `psa_cipher_set_iv()` with the IV for the decryption. 2821. Call `psa_cipher_update()` with the message to encrypt. You may call this function multiple times, passing successive fragments of the message on successive calls. 2831. Call `psa_cipher_finish()` to end the operation and output the decrypted message. 284 285This example shows how to decrypt encrypted data using an AES key in CBC mode with no padding 286(assuming all prerequisites have been fulfilled): 287```c 288void decrypt_with_symmetric_ciphers(const uint8_t *key, size_t key_len) 289{ 290 enum { 291 block_size = PSA_BLOCK_CIPHER_BLOCK_LENGTH(PSA_KEY_TYPE_AES), 292 }; 293 psa_status_t status; 294 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 295 psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING; 296 psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; 297 uint8_t ciphertext[block_size] = SOME_CIPHERTEXT; 298 uint8_t iv[block_size] = ENCRYPTED_WITH_IV; 299 uint8_t output[block_size]; 300 size_t output_len; 301 psa_key_id_t key_id; 302 303 printf("Decrypt with cipher...\t"); 304 fflush(stdout); 305 306 /* Initialize PSA Crypto */ 307 status = psa_crypto_init(); 308 if (status != PSA_SUCCESS) 309 { 310 printf("Failed to initialize PSA Crypto\n"); 311 return; 312 } 313 314 /* Import a key */ 315 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT); 316 psa_set_key_algorithm(&attributes, alg); 317 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); 318 psa_set_key_bits(&attributes, 128); 319 status = psa_import_key(&attributes, key, key_len, &key_id); 320 if (status != PSA_SUCCESS) { 321 printf("Failed to import a key\n"); 322 return; 323 } 324 psa_reset_key_attributes(&attributes); 325 326 /* Decrypt the ciphertext */ 327 status = psa_cipher_decrypt_setup(&operation, key_id, alg); 328 if (status != PSA_SUCCESS) { 329 printf("Failed to begin cipher operation\n"); 330 return; 331 } 332 status = psa_cipher_set_iv(&operation, iv, sizeof(iv)); 333 if (status != PSA_SUCCESS) { 334 printf("Failed to set IV\n"); 335 return; 336 } 337 status = psa_cipher_update(&operation, ciphertext, sizeof(ciphertext), 338 output, sizeof(output), &output_len); 339 if (status != PSA_SUCCESS) { 340 printf("Failed to update cipher operation\n"); 341 return; 342 } 343 status = psa_cipher_finish(&operation, output + output_len, 344 sizeof(output) - output_len, &output_len); 345 if (status != PSA_SUCCESS) { 346 printf("Failed to finish cipher operation\n"); 347 return; 348 } 349 printf("Decrypted ciphertext\n"); 350 351 /* Clean up cipher operation context */ 352 psa_cipher_abort(&operation); 353 354 /* Destroy the key */ 355 psa_destroy_key(key_id); 356 357 mbedtls_psa_crypto_free(); 358} 359``` 360 361#### Handling cipher operation contexts 362 363After 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()`. 364 365The call to `psa_cipher_abort()` frees any resources associated with the operation, except for the operation structure itself. 366 367Mbed Crypto implicitly calls `psa_cipher_abort()` when: 368* A call to `psa_cipher_generate_iv()`, `psa_cipher_set_iv()` or `psa_cipher_update()` fails (returning any status other than `PSA_SUCCESS`). 369* A call to `psa_cipher_finish()` succeeds or fails. 370 371After an implicit or explicit call to `psa_cipher_abort()`, the operation structure is invalidated; in other words, you cannot reuse the operation structure for the same operation. You can, however, reuse the operation structure for a different operation by calling either `psa_cipher_encrypt_setup()` or `psa_cipher_decrypt_setup()` again. 372 373You must call `psa_cipher_abort()` at some point for any operation that is initialized successfully (by a successful call to `psa_cipher_encrypt_setup()` or `psa_cipher_decrypt_setup()`). 374 375Making multiple sequential calls to `psa_cipher_abort()` on an operation that is terminated (either implicitly or explicitly) is safe and has no effect. 376 377### Hashing a message 378 379Mbed Crypto lets you compute and verify hashes using various hashing 380algorithms. 381 382**Prerequisites to working with the hash APIs:** 383* Initialize the library with a successful call to `psa_crypto_init()`. 384 385**To calculate a hash:** 3861. Allocate an operation structure (`psa_hash_operation_t`) to pass to the hash functions. 3871. Initialize the operation structure to zero or to `PSA_HASH_OPERATION_INIT`. 3881. Call `psa_hash_setup()` to specify the hash algorithm. 3891. Call `psa_hash_update()` with the message to encrypt. You may call this function multiple times, passing successive fragments of the message on successive calls. 3901. Call `psa_hash_finish()` to calculate the hash, or `psa_hash_verify()` to compare the computed hash with an expected hash value. 391 392This example shows how to calculate the SHA-256 hash of a message: 393```c 394 psa_status_t status; 395 psa_algorithm_t alg = PSA_ALG_SHA_256; 396 psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; 397 unsigned char input[] = { 'a', 'b', 'c' }; 398 unsigned char actual_hash[PSA_HASH_MAX_SIZE]; 399 size_t actual_hash_len; 400 401 printf("Hash a message...\t"); 402 fflush(stdout); 403 404 /* Initialize PSA Crypto */ 405 status = psa_crypto_init(); 406 if (status != PSA_SUCCESS) { 407 printf("Failed to initialize PSA Crypto\n"); 408 return; 409 } 410 411 /* Compute hash of message */ 412 status = psa_hash_setup(&operation, alg); 413 if (status != PSA_SUCCESS) { 414 printf("Failed to begin hash operation\n"); 415 return; 416 } 417 status = psa_hash_update(&operation, input, sizeof(input)); 418 if (status != PSA_SUCCESS) { 419 printf("Failed to update hash operation\n"); 420 return; 421 } 422 status = psa_hash_finish(&operation, actual_hash, sizeof(actual_hash), 423 &actual_hash_len); 424 if (status != PSA_SUCCESS) { 425 printf("Failed to finish hash operation\n"); 426 return; 427 } 428 429 printf("Hashed a message\n"); 430 431 /* Clean up hash operation context */ 432 psa_hash_abort(&operation); 433 434 mbedtls_psa_crypto_free(); 435``` 436 437This example shows how to verify the SHA-256 hash of a message: 438```c 439 psa_status_t status; 440 psa_algorithm_t alg = PSA_ALG_SHA_256; 441 psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; 442 unsigned char input[] = { 'a', 'b', 'c' }; 443 unsigned char expected_hash[] = { 444 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 445 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 446 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad 447 }; 448 size_t expected_hash_len = PSA_HASH_LENGTH(alg); 449 450 printf("Verify a hash...\t"); 451 fflush(stdout); 452 453 /* Initialize PSA Crypto */ 454 status = psa_crypto_init(); 455 if (status != PSA_SUCCESS) { 456 printf("Failed to initialize PSA Crypto\n"); 457 return; 458 } 459 460 /* Verify message hash */ 461 status = psa_hash_setup(&operation, alg); 462 if (status != PSA_SUCCESS) { 463 printf("Failed to begin hash operation\n"); 464 return; 465 } 466 status = psa_hash_update(&operation, input, sizeof(input)); 467 if (status != PSA_SUCCESS) { 468 printf("Failed to update hash operation\n"); 469 return; 470 } 471 status = psa_hash_verify(&operation, expected_hash, expected_hash_len); 472 if (status != PSA_SUCCESS) { 473 printf("Failed to verify hash\n"); 474 return; 475 } 476 477 printf("Verified a hash\n"); 478 479 /* Clean up hash operation context */ 480 psa_hash_abort(&operation); 481 482 mbedtls_psa_crypto_free(); 483``` 484 485The API provides the macro `PSA_HASH_LENGTH`, which returns the expected hash length (in bytes) for the specified algorithm. 486 487#### Handling hash operation contexts 488 489After a successful call to `psa_hash_setup()`, you can 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. 490 491Mbed Crypto implicitly calls `psa_hash_abort()` when: 4921. A call to `psa_hash_update()` fails (returning any status other than `PSA_SUCCESS`). 4931. A call to `psa_hash_finish()` succeeds or fails. 4941. A call to `psa_hash_verify()` succeeds or fails. 495 496After an implicit or explicit call to `psa_hash_abort()`, the operation structure is invalidated; in other words, you cannot reuse the operation structure for the same operation. You can, however, reuse the operation structure for a different operation by calling `psa_hash_setup()` again. 497 498You must call `psa_hash_abort()` at some point for any operation that is initialized successfully (by a successful call to `psa_hash_setup()`) . 499 500Making 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. 501 502### Generating a random value 503 504Mbed Crypto can generate random data. 505 506**Prerequisites to generating random data:** 507* Initialize the library with a successful call to `psa_crypto_init()`. 508 509<span class="notes">**Note:** To generate a random key, use `psa_generate_key()` instead of `psa_generate_random()`.</span> 510 511This example shows how to generate ten bytes of random data by calling `psa_generate_random()`: 512```C 513 psa_status_t status; 514 uint8_t random[10] = { 0 }; 515 516 printf("Generate random...\t"); 517 fflush(stdout); 518 519 /* Initialize PSA Crypto */ 520 status = psa_crypto_init(); 521 if (status != PSA_SUCCESS) { 522 printf("Failed to initialize PSA Crypto\n"); 523 return; 524 } 525 526 status = psa_generate_random(random, sizeof(random)); 527 if (status != PSA_SUCCESS) { 528 printf("Failed to generate a random value\n"); 529 return; 530 } 531 532 printf("Generated random data\n"); 533 534 /* Clean up */ 535 mbedtls_psa_crypto_free(); 536``` 537 538### Deriving a new key from an existing key 539 540Mbed Crypto provides a key derivation API that lets you derive new keys from 541existing ones. The key derivation API has functions to take inputs, including 542other keys and data, and functions to generate outputs, such as new keys or 543other data. 544 545You must first initialize and set up a key derivation context, 546provided with a key and, optionally, other data. Then, use the key derivation context to either read derived data to a buffer or send derived data directly to a key slot. 547 548See the documentation for the particular algorithm (such as HKDF or the TLS1.2 PRF) for 549information about which inputs to pass when, and when you can obtain which outputs. 550 551**Prerequisites to working with the key derivation APIs:** 552* Initialize the library with a successful call to `psa_crypto_init()`. 553* Use a key with the appropriate attributes set: 554 * Usage flags set for key derivation (`PSA_KEY_USAGE_DERIVE`) 555 * Key type set to `PSA_KEY_TYPE_DERIVE`. 556 * Algorithm set to a key derivation algorithm 557 (for example, `PSA_ALG_HKDF(PSA_ALG_SHA_256)`). 558 559**To derive a new AES-CTR 128-bit encryption key into a given key slot using HKDF 560with a given key, salt and info:** 561 5621. Set up the key derivation context using the `psa_key_derivation_setup()` 563function, specifying the derivation algorithm `PSA_ALG_HKDF(PSA_ALG_SHA_256)`. 5641. Provide an optional salt with `psa_key_derivation_input_bytes()`. 5651. Provide info with `psa_key_derivation_input_bytes()`. 5661. Provide a secret with `psa_key_derivation_input_key()`, referencing a key that 567 can be used for key derivation. 5681. Set the key attributes desired for the new derived key. We'll set 569 the `PSA_KEY_USAGE_ENCRYPT` usage flag and the `PSA_ALG_CTR` algorithm for this 570 example. 5711. Derive the key by calling `psa_key_derivation_output_key()`. 5721. Clean up the key derivation context. 573 574At this point, the derived key slot holds a new 128-bit AES-CTR encryption key 575derived from the key, salt and info provided: 576```C 577 psa_status_t status; 578 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 579 static const unsigned char key[] = { 580 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 581 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 582 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 583 0x0b }; 584 static const unsigned char salt[] = { 585 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 586 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }; 587 static const unsigned char info[] = { 588 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 589 0xf7, 0xf8, 0xf9 }; 590 psa_algorithm_t alg = PSA_ALG_HKDF(PSA_ALG_SHA_256); 591 psa_key_derivation_operation_t operation = 592 PSA_KEY_DERIVATION_OPERATION_INIT; 593 size_t derived_bits = 128; 594 size_t capacity = PSA_BITS_TO_BYTES(derived_bits); 595 psa_key_id_t base_key; 596 psa_key_id_t derived_key; 597 598 printf("Derive a key (HKDF)...\t"); 599 fflush(stdout); 600 601 /* Initialize PSA Crypto */ 602 status = psa_crypto_init(); 603 if (status != PSA_SUCCESS) { 604 printf("Failed to initialize PSA Crypto\n"); 605 return; 606 } 607 608 /* Import a key for use in key derivation. If such a key has already been 609 * generated or imported, you can skip this part. */ 610 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); 611 psa_set_key_algorithm(&attributes, alg); 612 psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE); 613 status = psa_import_key(&attributes, key, sizeof(key), &base_key); 614 if (status != PSA_SUCCESS) { 615 printf("Failed to import a key\n"); 616 return; 617 } 618 psa_reset_key_attributes(&attributes); 619 620 /* Derive a key */ 621 status = psa_key_derivation_setup(&operation, alg); 622 if (status != PSA_SUCCESS) { 623 printf("Failed to begin key derivation\n"); 624 return; 625 } 626 status = psa_key_derivation_set_capacity(&operation, capacity); 627 if (status != PSA_SUCCESS) { 628 printf("Failed to set capacity\n"); 629 return; 630 } 631 status = psa_key_derivation_input_bytes(&operation, 632 PSA_KEY_DERIVATION_INPUT_SALT, 633 salt, sizeof(salt)); 634 if (status != PSA_SUCCESS) { 635 printf("Failed to input salt (extract)\n"); 636 return; 637 } 638 status = psa_key_derivation_input_key(&operation, 639 PSA_KEY_DERIVATION_INPUT_SECRET, 640 base_key); 641 if (status != PSA_SUCCESS) { 642 printf("Failed to input key (extract)\n"); 643 return; 644 } 645 status = psa_key_derivation_input_bytes(&operation, 646 PSA_KEY_DERIVATION_INPUT_INFO, 647 info, sizeof(info)); 648 if (status != PSA_SUCCESS) { 649 printf("Failed to input info (expand)\n"); 650 return; 651 } 652 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); 653 psa_set_key_algorithm(&attributes, PSA_ALG_CTR); 654 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); 655 psa_set_key_bits(&attributes, 128); 656 status = psa_key_derivation_output_key(&attributes, &operation, 657 &derived_key); 658 if (status != PSA_SUCCESS) { 659 printf("Failed to derive key\n"); 660 return; 661 } 662 psa_reset_key_attributes(&attributes); 663 664 printf("Derived key\n"); 665 666 /* Clean up key derivation operation */ 667 psa_key_derivation_abort(&operation); 668 669 /* Destroy the keys */ 670 psa_destroy_key(derived_key); 671 psa_destroy_key(base_key); 672 673 mbedtls_psa_crypto_free(); 674``` 675 676### Authenticating and encrypting or decrypting a message 677 678Mbed Crypto provides a simple way to authenticate and encrypt with associated data (AEAD), supporting the `PSA_ALG_CCM` algorithm. 679 680**Prerequisites to working with the AEAD cipher APIs:** 681* Initialize the library with a successful call to `psa_crypto_init()`. 682* The key attributes for the key used for derivation must have the `PSA_KEY_USAGE_ENCRYPT` or `PSA_KEY_USAGE_DECRYPT` usage flags. 683 684This example shows how to authenticate and encrypt a message: 685```C 686 psa_status_t status; 687 static const uint8_t key[] = { 688 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 689 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF }; 690 static const uint8_t nonce[] = { 691 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 692 0x08, 0x09, 0x0A, 0x0B }; 693 static const uint8_t additional_data[] = { 694 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25, 695 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 }; 696 static const uint8_t input_data[] = { 697 0xB9, 0x6B, 0x49, 0xE2, 0x1D, 0x62, 0x17, 0x41, 698 0x63, 0x28, 0x75, 0xDB, 0x7F, 0x6C, 0x92, 0x43, 699 0xD2, 0xD7, 0xC2 }; 700 uint8_t *output_data = NULL; 701 size_t output_size = 0; 702 size_t output_length = 0; 703 size_t tag_length = 16; 704 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 705 psa_key_id_t key_id; 706 707 printf("Authenticate encrypt...\t"); 708 fflush(stdout); 709 710 /* Initialize PSA Crypto */ 711 status = psa_crypto_init(); 712 if (status != PSA_SUCCESS) { 713 printf("Failed to initialize PSA Crypto\n"); 714 return; 715 } 716 717 output_size = sizeof(input_data) + tag_length; 718 output_data = (uint8_t *)malloc(output_size); 719 if (!output_data) { 720 printf("Out of memory\n"); 721 return; 722 } 723 724 /* Import a key */ 725 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); 726 psa_set_key_algorithm(&attributes, PSA_ALG_CCM); 727 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); 728 psa_set_key_bits(&attributes, 128); 729 status = psa_import_key(&attributes, key, sizeof(key), &key_id); 730 psa_reset_key_attributes(&attributes); 731 732 /* Authenticate and encrypt */ 733 status = psa_aead_encrypt(key_id, PSA_ALG_CCM, 734 nonce, sizeof(nonce), 735 additional_data, sizeof(additional_data), 736 input_data, sizeof(input_data), 737 output_data, output_size, 738 &output_length); 739 if (status != PSA_SUCCESS) { 740 printf("Failed to authenticate and encrypt\n"); 741 return; 742 } 743 744 printf("Authenticated and encrypted\n"); 745 746 /* Clean up */ 747 free(output_data); 748 749 /* Destroy the key */ 750 psa_destroy_key(key_id); 751 752 mbedtls_psa_crypto_free(); 753``` 754 755This example shows how to authenticate and decrypt a message: 756 757```C 758 psa_status_t status; 759 static const uint8_t key_data[] = { 760 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 761 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF }; 762 static const uint8_t nonce[] = { 763 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 764 0x08, 0x09, 0x0A, 0x0B }; 765 static const uint8_t additional_data[] = { 766 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25, 767 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 }; 768 static const uint8_t input_data[] = { 769 0x20, 0x30, 0xE0, 0x36, 0xED, 0x09, 0xA0, 0x45, 0xAF, 0x3C, 0xBA, 0xEE, 770 0x0F, 0xC8, 0x48, 0xAF, 0xCD, 0x89, 0x54, 0xF4, 0xF6, 0x3F, 0x28, 0x9A, 771 0xA1, 0xDD, 0xB2, 0xB8, 0x09, 0xCD, 0x7C, 0xE1, 0x46, 0xE9, 0x98 }; 772 uint8_t *output_data = NULL; 773 size_t output_size = 0; 774 size_t output_length = 0; 775 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 776 psa_key_id_t key_id; 777 778 printf("Authenticate decrypt...\t"); 779 fflush(stdout); 780 781 /* Initialize PSA Crypto */ 782 status = psa_crypto_init(); 783 if (status != PSA_SUCCESS) { 784 printf("Failed to initialize PSA Crypto\n"); 785 return; 786 } 787 788 output_size = sizeof(input_data); 789 output_data = (uint8_t *)malloc(output_size); 790 if (!output_data) { 791 printf("Out of memory\n"); 792 return; 793 } 794 795 /* Import a key */ 796 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT); 797 psa_set_key_algorithm(&attributes, PSA_ALG_CCM); 798 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); 799 psa_set_key_bits(&attributes, 128); 800 status = psa_import_key(&attributes, key_data, sizeof(key_data), &key_id); 801 if (status != PSA_SUCCESS) { 802 printf("Failed to import a key\n"); 803 return; 804 } 805 psa_reset_key_attributes(&attributes); 806 807 /* Authenticate and decrypt */ 808 status = psa_aead_decrypt(key_id, PSA_ALG_CCM, 809 nonce, sizeof(nonce), 810 additional_data, sizeof(additional_data), 811 input_data, sizeof(input_data), 812 output_data, output_size, 813 &output_length); 814 if (status != PSA_SUCCESS) { 815 printf("Failed to authenticate and decrypt %ld\n", status); 816 return; 817 } 818 819 printf("Authenticated and decrypted\n"); 820 821 /* Clean up */ 822 free(output_data); 823 824 /* Destroy the key */ 825 psa_destroy_key(key_id); 826 827 mbedtls_psa_crypto_free(); 828``` 829 830### Generating and exporting keys 831 832Mbed Crypto provides a simple way to generate a key or key pair. 833 834**Prerequisites to using key generation and export APIs:** 835* Initialize the library with a successful call to `psa_crypto_init()`. 836 837**To generate an ECDSA key:** 8381. Set the desired key attributes for key generation by calling 839 `psa_set_key_algorithm()` with the chosen ECDSA algorithm (such as 840 `PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)`). You only want to export the public key, not the key pair (or private key); therefore, do not set `PSA_KEY_USAGE_EXPORT`. 8411. Generate a key by calling `psa_generate_key()`. 8421. Export the generated public key by calling `psa_export_public_key()`: 843```C 844 enum { 845 key_bits = 256, 846 }; 847 psa_status_t status; 848 size_t exported_length = 0; 849 static uint8_t exported[PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits)]; 850 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 851 psa_key_id_t key_id; 852 853 printf("Generate a key pair...\t"); 854 fflush(stdout); 855 856 /* Initialize PSA Crypto */ 857 status = psa_crypto_init(); 858 if (status != PSA_SUCCESS) { 859 printf("Failed to initialize PSA Crypto\n"); 860 return; 861 } 862 863 /* Generate a key */ 864 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH); 865 psa_set_key_algorithm(&attributes, 866 PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)); 867 psa_set_key_type(&attributes, 868 PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); 869 psa_set_key_bits(&attributes, key_bits); 870 status = psa_generate_key(&attributes, &key_id); 871 if (status != PSA_SUCCESS) { 872 printf("Failed to generate key\n"); 873 return; 874 } 875 psa_reset_key_attributes(&attributes); 876 877 status = psa_export_public_key(key_id, exported, sizeof(exported), 878 &exported_length); 879 if (status != PSA_SUCCESS) { 880 printf("Failed to export public key %ld\n", status); 881 return; 882 } 883 884 printf("Exported a public key\n"); 885 886 /* Destroy the key */ 887 psa_destroy_key(key_id); 888 889 mbedtls_psa_crypto_free(); 890``` 891 892### More about the PSA Crypto API 893 894For more information about the PSA Crypto API, please see the [PSA Cryptography API Specification](https://armmbed.github.io/mbed-crypto/html/index.html). 895