blob: de257a912c325a3dfcef4e60525c44d85176c5b6 [file] [log] [blame] [view]
mohammad160387a7eeb2018-11-01 11:25:49 +02001## 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,
Guy Wildc03c0fc2019-09-03 13:18:04 +030021security 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.
mohammad160387a7eeb2018-11-01 11:25:49 +020022
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
Guy Wildc03c0fc2019-09-03 13:18:04 +030040Mbed Crypto releases are available in the [public GitHub repository](https://github.com/ARMmbed/mbed-crypto).
mohammad160387a7eeb2018-11-01 11:25:49 +020041
42### Building the Mbed Crypto library
43
Guy Wildc03c0fc2019-09-03 13:18:04 +030044**Prerequisites to building the library with the provided makefiles:**
mohammad160387a7eeb2018-11-01 11:25:49 +020045* 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
Guy Wildc03c0fc2019-09-03 13:18:04 +030050If 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.
mohammad160387a7eeb2018-11-01 11:25:49 +020051
Guy Wildc03c0fc2019-09-03 13:18:04 +030052To 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:
mohammad160387a7eeb2018-11-01 11:25:49 +020053```
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
Jaeden Amero884738a2019-08-16 17:58:31 +010066To use a key for cryptography operations in Mbed Crypto, you need to first
Guy Wildc03c0fc2019-09-03 13:18:04 +030067import it. After you import the key, you'll be given a handle that refers to the key for use
Jaeden Amero884738a2019-08-16 17:58:31 +010068with other function calls.
mohammad160387a7eeb2018-11-01 11:25:49 +020069
Guy Wild802b19f2019-09-03 16:40:44 +030070**Prerequisites to importing keys:**
Guy Wildc03c0fc2019-09-03 13:18:04 +030071* Initialize the library with a successful call to `psa_crypto_init()`.
mohammad160387a7eeb2018-11-01 11:25:49 +020072
Guy Wildc03c0fc2019-09-03 13:18:04 +030073This example shows how to import a key:
mohammad160387a7eeb2018-11-01 11:25:49 +020074```C
Jaeden Amero884738a2019-08-16 17:58:31 +010075 psa_status_t status;
76 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
77 uint8_t data[] = AES_KEY;
78 psa_key_handle_t handle;
mohammad160387a7eeb2018-11-01 11:25:49 +020079
Jaeden Amero884738a2019-08-16 17:58:31 +010080 printf("Import an AES key...\t");
81 fflush(stdout);
82
83 /* Initialize PSA Crypto */
84 status = psa_crypto_init();
85 if (status != PSA_SUCCESS) {
86 printf("Failed to initialize PSA Crypto\n");
87 return;
88 }
89
90 /* Set key attributes */
91 psa_set_key_usage_flags(&attributes, 0);
92 psa_set_key_algorithm(&attributes, 0);
93 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
94 psa_set_key_bits(&attributes, 128);
mohammad160387a7eeb2018-11-01 11:25:49 +020095
96 /* Import the key */
Jaeden Amero884738a2019-08-16 17:58:31 +010097 status = psa_import_key(&attributes, data, sizeof(data), &handle);
98 if (status != PSA_SUCCESS) {
99 printf("Failed to import key\n");
100 return;
101 }
102 printf("Imported a key\n");
mohammad160387a7eeb2018-11-01 11:25:49 +0200103
Jaeden Amero884738a2019-08-16 17:58:31 +0100104 /* Free the attributes */
105 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200106
107 /* Destroy the key */
Jaeden Amero884738a2019-08-16 17:58:31 +0100108 psa_destroy_key(handle);
109
mohammad160387a7eeb2018-11-01 11:25:49 +0200110 mbedtls_psa_crypto_free();
111```
112
113### Signing a message using RSA
114
Guy Wildc03c0fc2019-09-03 13:18:04 +0300115Mbed Crypto supports encrypting, decrypting, signing and verifying messages using public key signature algorithms, such as RSA or ECDSA.
mohammad160387a7eeb2018-11-01 11:25:49 +0200116
Guy Wildc03c0fc2019-09-03 13:18:04 +0300117**Prerequisites to performing asymmetric signature operations:**
118* Initialize the library with a successful call to `psa_crypto_init()`.
Jaeden Amero884738a2019-08-16 17:58:31 +0100119* Have a valid key with appropriate attributes set:
120 * Usage flag `PSA_KEY_USAGE_SIGN` to allow signing.
121 * Usage flag `PSA_KEY_USAGE_VERIFY` to allow signature verification.
Guy Wildc03c0fc2019-09-03 13:18:04 +0300122 * Algorithm set to the desired signature algorithm.
mohammad160387a7eeb2018-11-01 11:25:49 +0200123
Guy Wildc03c0fc2019-09-03 13:18:04 +0300124This example shows how to sign a given hash using RSA, call `psa_asymmetric_sign()` and get the output buffer that contains the signature:
mohammad160387a7eeb2018-11-01 11:25:49 +0200125```C
126 psa_status_t status;
Jaeden Amero884738a2019-08-16 17:58:31 +0100127 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
128 uint8_t key[] = RSA_KEY;
129 uint8_t hash[] = "INPUT_FOR_SIGN";
130 uint8_t signature[PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE] = {0};
mohammad160387a7eeb2018-11-01 11:25:49 +0200131 size_t signature_length;
Jaeden Amero884738a2019-08-16 17:58:31 +0100132 psa_key_handle_t handle;
mohammad160387a7eeb2018-11-01 11:25:49 +0200133
Jaeden Amero884738a2019-08-16 17:58:31 +0100134 printf("Sign a message...\t");
135 fflush(stdout);
136
137 /* Initialize PSA Crypto */
mohammad160387a7eeb2018-11-01 11:25:49 +0200138 status = psa_crypto_init();
Jaeden Amero884738a2019-08-16 17:58:31 +0100139 if (status != PSA_SUCCESS) {
140 printf("Failed to initialize PSA Crypto\n");
141 return;
142 }
143
144 /* Set key attributes */
145 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN);
146 psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_SIGN_RAW);
147 psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
148 psa_set_key_bits(&attributes, 1024);
mohammad160387a7eeb2018-11-01 11:25:49 +0200149
150 /* Import the key */
Jaeden Amero884738a2019-08-16 17:58:31 +0100151 status = psa_import_key(&attributes, key, sizeof(key), &handle);
152 if (status != PSA_SUCCESS) {
153 printf("Failed to import key\n");
154 return;
155 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200156
Jaeden Amero884738a2019-08-16 17:58:31 +0100157 /* Sign message using the key */
158 status = psa_asymmetric_sign(handle, PSA_ALG_RSA_PKCS1V15_SIGN_RAW,
159 hash, sizeof(hash),
mohammad160387a7eeb2018-11-01 11:25:49 +0200160 signature, sizeof(signature),
161 &signature_length);
Jaeden Amero884738a2019-08-16 17:58:31 +0100162 if (status != PSA_SUCCESS) {
163 printf("Failed to sign\n");
164 return;
165 }
166
167 printf("Signed a message\n");
168
169 /* Free the attributes */
170 psa_reset_key_attributes(&attributes);
171
mohammad160387a7eeb2018-11-01 11:25:49 +0200172 /* Destroy the key */
Jaeden Amero884738a2019-08-16 17:58:31 +0100173 psa_destroy_key(handle);
174
mohammad160387a7eeb2018-11-01 11:25:49 +0200175 mbedtls_psa_crypto_free();
176```
177
Jaeden Amero884738a2019-08-16 17:58:31 +0100178### Using symmetric ciphers
mohammad160387a7eeb2018-11-01 11:25:49 +0200179
Guy Wildc03c0fc2019-09-03 13:18:04 +0300180Mbed Crypto supports encrypting and decrypting messages using various symmetric cipher algorithms (both block and stream ciphers).
mohammad160387a7eeb2018-11-01 11:25:49 +0200181
Guy Wildc03c0fc2019-09-03 13:18:04 +0300182**Prerequisites to working with the symmetric cipher API:**
183* Initialize the library with a successful call to `psa_crypto_init()`.
184* Configure the key policy accordingly (set `PSA_KEY_USAGE_ENCRYPT` to allow encryption or `PSA_KEY_USAGE_DECRYPT` to allow decryption).
mohammad160387a7eeb2018-11-01 11:25:49 +0200185* Have a valid key in the key slot.
186
Guy Wildc03c0fc2019-09-03 13:18:04 +0300187**To encrypt a message with a symmetric cipher:**
mohammad160387a7eeb2018-11-01 11:25:49 +02001881. Allocate an operation (`psa_cipher_operation_t`) structure to pass to the cipher functions.
Guy Wildc03c0fc2019-09-03 13:18:04 +03001891. Call `psa_cipher_encrypt_setup()` to initialize the operation structure and specify the algorithm and the key to be used.
1901. Call either `psa_cipher_generate_iv()` or `psa_cipher_set_iv()` to generate or set the initialization vector (IV). We recommended calling `psa_cipher_generate_iv()`, unless you require a specific IV value.
Guy Wild802b19f2019-09-03 16:40:44 +03001911. Call `psa_cipher_update()` one or more times, passing the whole message or a fragment of the message on each call.
Guy Wildc03c0fc2019-09-03 13:18:04 +03001921. Call `psa_cipher_finish()` to end the operation and output the encrypted message.
mohammad160387a7eeb2018-11-01 11:25:49 +0200193
Guy Wild802b19f2019-09-03 16:40:44 +0300194This example shows how to encrypt data using an Advanced Encryption Standard (AES) key in Cipher Block Chaining (CBC) mode with no padding (assuming all prerequisites have been fulfilled):
mohammad160387a7eeb2018-11-01 11:25:49 +0200195```c
Jaeden Amero884738a2019-08-16 17:58:31 +0100196 enum {
197 block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES),
198 };
199 psa_status_t status;
200 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200201 psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING;
Jaeden Amero884738a2019-08-16 17:58:31 +0100202 uint8_t plaintext[block_size] = SOME_PLAINTEXT;
203 uint8_t iv[block_size];
mohammad160387a7eeb2018-11-01 11:25:49 +0200204 size_t iv_len;
Jaeden Amero884738a2019-08-16 17:58:31 +0100205 uint8_t key[] = AES_KEY;
206 uint8_t output[block_size];
mohammad160387a7eeb2018-11-01 11:25:49 +0200207 size_t output_len;
Jaeden Amero884738a2019-08-16 17:58:31 +0100208 psa_key_handle_t handle;
209 psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200210
Jaeden Amero884738a2019-08-16 17:58:31 +0100211 printf("Encrypt with cipher...\t");
212 fflush(stdout);
mohammad160387a7eeb2018-11-01 11:25:49 +0200213
Jaeden Amero884738a2019-08-16 17:58:31 +0100214 /* Initialize PSA Crypto */
215 status = psa_crypto_init();
216 if (status != PSA_SUCCESS)
217 {
218 printf("Failed to initialize PSA Crypto\n");
219 return;
220 }
221
222 /* Import a key */
223 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
224 psa_set_key_algorithm(&attributes, alg);
225 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
226 psa_set_key_bits(&attributes, 128);
227 status = psa_import_key(&attributes, key, sizeof(key), &handle);
228 if (status != PSA_SUCCESS) {
229 printf("Failed to import a key\n");
230 return;
231 }
232 psa_reset_key_attributes(&attributes);
233
234 /* Encrypt the plaintext */
235 status = psa_cipher_encrypt_setup(&operation, handle, alg);
236 if (status != PSA_SUCCESS) {
237 printf("Failed to begin cipher operation\n");
238 return;
239 }
240 status = psa_cipher_generate_iv(&operation, iv, sizeof(iv), &iv_len);
241 if (status != PSA_SUCCESS) {
242 printf("Failed to generate IV\n");
243 return;
244 }
245 status = psa_cipher_update(&operation, plaintext, sizeof(plaintext),
246 output, sizeof(output), &output_len);
247 if (status != PSA_SUCCESS) {
248 printf("Failed to update cipher operation\n");
249 return;
250 }
251 status = psa_cipher_finish(&operation, output + output_len,
252 sizeof(output) - output_len, &output_len);
253 if (status != PSA_SUCCESS) {
254 printf("Failed to finish cipher operation\n");
255 return;
256 }
257 printf("Encrypted plaintext\n");
258
mohammad160387a7eeb2018-11-01 11:25:49 +0200259 /* Clean up cipher operation context */
260 psa_cipher_abort(&operation);
Jaeden Amero884738a2019-08-16 17:58:31 +0100261
262 /* Destroy the key */
263 psa_destroy_key(handle);
264
265 mbedtls_psa_crypto_free();
mohammad160387a7eeb2018-11-01 11:25:49 +0200266```
267
Guy Wildc03c0fc2019-09-03 13:18:04 +0300268**To decrypt a message with a symmetric cipher:**
mohammad160387a7eeb2018-11-01 11:25:49 +02002691. Allocate an operation (`psa_cipher_operation_t`) structure to pass to the cipher functions.
Guy Wildc03c0fc2019-09-03 13:18:04 +03002701. Call `psa_cipher_decrypt_setup()` to initialize the operation structure and to specify the algorithm and the key to be used.
2711. Call `psa_cipher_set_iv()` with the IV for the decryption.
Guy Wild802b19f2019-09-03 16:40:44 +03002721. Call `psa_cipher_update()` one or more times, passing the whole message or a fragment of the message on each call.
Guy Wildc03c0fc2019-09-03 13:18:04 +03002731. Call `psa_cipher_finish()` to end the operation and output the decrypted message.
mohammad160387a7eeb2018-11-01 11:25:49 +0200274
Guy Wildc03c0fc2019-09-03 13:18:04 +0300275This example shows how to decrypt encrypted data using an AES key in CBC mode with no padding
mohammad160387a7eeb2018-11-01 11:25:49 +0200276(assuming all prerequisites have been fulfilled):
277```c
Jaeden Amero884738a2019-08-16 17:58:31 +0100278 enum {
279 block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES),
280 };
281 psa_status_t status;
282 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200283 psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING;
Jaeden Amero884738a2019-08-16 17:58:31 +0100284 psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
285 uint8_t ciphertext[block_size] = SOME_CIPHERTEXT;
286 uint8_t iv[block_size] = ENCRYPTED_WITH_IV;
287 uint8_t key[] = AES_KEY;
288 uint8_t output[block_size];
mohammad160387a7eeb2018-11-01 11:25:49 +0200289 size_t output_len;
Jaeden Amero884738a2019-08-16 17:58:31 +0100290 psa_key_handle_t handle;
mohammad160387a7eeb2018-11-01 11:25:49 +0200291
Jaeden Amero884738a2019-08-16 17:58:31 +0100292 printf("Decrypt with cipher...\t");
293 fflush(stdout);
mohammad160387a7eeb2018-11-01 11:25:49 +0200294
Jaeden Amero884738a2019-08-16 17:58:31 +0100295 /* Initialize PSA Crypto */
296 status = psa_crypto_init();
297 if (status != PSA_SUCCESS)
298 {
299 printf("Failed to initialize PSA Crypto\n");
300 return;
301 }
302
303 /* Import a key */
304 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
305 psa_set_key_algorithm(&attributes, alg);
306 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
307 psa_set_key_bits(&attributes, 128);
308 status = psa_import_key(&attributes, key, sizeof(key), &handle);
309 if (status != PSA_SUCCESS) {
310 printf("Failed to import a key\n");
311 return;
312 }
313 psa_reset_key_attributes(&attributes);
314
315 /* Decrypt the ciphertext */
316 status = psa_cipher_decrypt_setup(&operation, handle, alg);
317 if (status != PSA_SUCCESS) {
318 printf("Failed to begin cipher operation\n");
319 return;
320 }
321 status = psa_cipher_set_iv(&operation, iv, sizeof(iv));
322 if (status != PSA_SUCCESS) {
323 printf("Failed to set IV\n");
324 return;
325 }
326 status = psa_cipher_update(&operation, ciphertext, sizeof(ciphertext),
327 output, sizeof(output), &output_len);
328 if (status != PSA_SUCCESS) {
329 printf("Failed to update cipher operation\n");
330 return;
331 }
332 status = psa_cipher_finish(&operation, output + output_len,
333 sizeof(output) - output_len, &output_len);
334 if (status != PSA_SUCCESS) {
335 printf("Failed to finish cipher operation\n");
336 return;
337 }
338 printf("Decrypted ciphertext\n");
339
mohammad160387a7eeb2018-11-01 11:25:49 +0200340 /* Clean up cipher operation context */
341 psa_cipher_abort(&operation);
Jaeden Amero884738a2019-08-16 17:58:31 +0100342
343 /* Destroy the key */
344 psa_destroy_key(handle);
345
346 mbedtls_psa_crypto_free();
mohammad160387a7eeb2018-11-01 11:25:49 +0200347```
348
349#### Handling cipher operation contexts
350
Guy Wildc03c0fc2019-09-03 13:18:04 +0300351After 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()`.
mohammad160387a7eeb2018-11-01 11:25:49 +0200352
Guy Wildc03c0fc2019-09-03 13:18:04 +0300353The call to `psa_cipher_abort()` frees any resources associated with the operation, except for the operation structure itself.
mohammad160387a7eeb2018-11-01 11:25:49 +0200354
Guy Wildc03c0fc2019-09-03 13:18:04 +0300355Mbed Crypto implicitly calls `psa_cipher_abort()` when:
356* A call to `psa_cipher_generate_iv()`, `psa_cipher_set_iv()` or `psa_cipher_update()` fails (returning any status other than `PSA_SUCCESS`).
357* A call to `psa_cipher_finish()` succeeds or fails.
mohammad160387a7eeb2018-11-01 11:25:49 +0200358
Guy Wildc03c0fc2019-09-03 13:18:04 +0300359After 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.
mohammad160387a7eeb2018-11-01 11:25:49 +0200360
Guy Wildc03c0fc2019-09-03 13:18:04 +0300361You 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()`).
362
363Making multiple sequential calls to `psa_cipher_abort()` on an operation that is terminated (either implicitly or explicitly) is safe and has no effect.
mohammad160387a7eeb2018-11-01 11:25:49 +0200364
365### Hashing a message
366
Jaeden Amero884738a2019-08-16 17:58:31 +0100367Mbed Crypto lets you compute and verify hashes using various hashing
368algorithms.
mohammad160387a7eeb2018-11-01 11:25:49 +0200369
Guy Wildc03c0fc2019-09-03 13:18:04 +0300370**Prerequisites to working with the hash APIs:**
371* Initialize the library with a successful call to `psa_crypto_init()`.
mohammad160387a7eeb2018-11-01 11:25:49 +0200372
Guy Wildc03c0fc2019-09-03 13:18:04 +0300373**To calculate a hash:**
mohammad160387a7eeb2018-11-01 11:25:49 +02003741. Allocate an operation structure (`psa_hash_operation_t`) to pass to the hash functions.
Guy Wildc03c0fc2019-09-03 13:18:04 +03003751. Call `psa_hash_setup()` to initialize the operation structure and specify the hash algorithm.
Guy Wild802b19f2019-09-03 16:40:44 +03003761. Call `psa_hash_update()` one or more times, passing the whole message or a fragment of the message on each call.
Guy Wildc03c0fc2019-09-03 13:18:04 +03003771. Call `psa_hash_finish()` to calculate the hash, or `psa_hash_verify()` to compare the computed hash with an expected hash value.
mohammad160387a7eeb2018-11-01 11:25:49 +0200378
Guy Wildc03c0fc2019-09-03 13:18:04 +0300379This example shows how to calculate the `SHA-256` hash of a message:
mohammad160387a7eeb2018-11-01 11:25:49 +0200380```c
Jaeden Amero884738a2019-08-16 17:58:31 +0100381 psa_status_t status;
mohammad160387a7eeb2018-11-01 11:25:49 +0200382 psa_algorithm_t alg = PSA_ALG_SHA_256;
Jaeden Amero884738a2019-08-16 17:58:31 +0100383 psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200384 unsigned char input[] = { 'a', 'b', 'c' };
385 unsigned char actual_hash[PSA_HASH_MAX_SIZE];
386 size_t actual_hash_len;
387
Jaeden Amero884738a2019-08-16 17:58:31 +0100388 printf("Hash a message...\t");
389 fflush(stdout);
390
391 /* Initialize PSA Crypto */
392 status = psa_crypto_init();
393 if (status != PSA_SUCCESS) {
394 printf("Failed to initialize PSA Crypto\n");
395 return;
396 }
397
mohammad160387a7eeb2018-11-01 11:25:49 +0200398 /* Compute hash of message */
Jaeden Amero884738a2019-08-16 17:58:31 +0100399 status = psa_hash_setup(&operation, alg);
400 if (status != PSA_SUCCESS) {
401 printf("Failed to begin hash operation\n");
402 return;
403 }
404 status = psa_hash_update(&operation, input, sizeof(input));
405 if (status != PSA_SUCCESS) {
406 printf("Failed to update hash operation\n");
407 return;
408 }
409 status = psa_hash_finish(&operation, actual_hash, sizeof(actual_hash),
410 &actual_hash_len);
411 if (status != PSA_SUCCESS) {
412 printf("Failed to finish hash operation\n");
413 return;
414 }
415
416 printf("Hashed a message\n");
mohammad160387a7eeb2018-11-01 11:25:49 +0200417
418 /* Clean up hash operation context */
419 psa_hash_abort(&operation);
Jaeden Amero884738a2019-08-16 17:58:31 +0100420
421 mbedtls_psa_crypto_free();
mohammad160387a7eeb2018-11-01 11:25:49 +0200422```
423
Guy Wildc03c0fc2019-09-03 13:18:04 +0300424This example shows how to verify the `SHA-256` hash of a message:
mohammad160387a7eeb2018-11-01 11:25:49 +0200425```c
Jaeden Amero884738a2019-08-16 17:58:31 +0100426 psa_status_t status;
mohammad160387a7eeb2018-11-01 11:25:49 +0200427 psa_algorithm_t alg = PSA_ALG_SHA_256;
Jaeden Amero884738a2019-08-16 17:58:31 +0100428 psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200429 unsigned char input[] = { 'a', 'b', 'c' };
430 unsigned char expected_hash[] = {
431 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde,
432 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
433 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad
434 };
435 size_t expected_hash_len = PSA_HASH_SIZE(alg);
436
Jaeden Amero884738a2019-08-16 17:58:31 +0100437 printf("Verify a hash...\t");
438 fflush(stdout);
439
440 /* Initialize PSA Crypto */
441 status = psa_crypto_init();
442 if (status != PSA_SUCCESS) {
443 printf("Failed to initialize PSA Crypto\n");
444 return;
445 }
446
mohammad160387a7eeb2018-11-01 11:25:49 +0200447 /* Verify message hash */
Jaeden Amero884738a2019-08-16 17:58:31 +0100448 status = psa_hash_setup(&operation, alg);
449 if (status != PSA_SUCCESS) {
450 printf("Failed to begin hash operation\n");
451 return;
452 }
453 status = psa_hash_update(&operation, input, sizeof(input));
454 if (status != PSA_SUCCESS) {
455 printf("Failed to update hash operation\n");
456 return;
457 }
458 status = psa_hash_verify(&operation, expected_hash, expected_hash_len);
459 if (status != PSA_SUCCESS) {
460 printf("Failed to verify hash\n");
461 return;
462 }
463
464 printf("Verified a hash\n");
465
466 /* Clean up hash operation context */
467 psa_hash_abort(&operation);
468
469 mbedtls_psa_crypto_free();
mohammad160387a7eeb2018-11-01 11:25:49 +0200470```
471
472The API provides the macro `PSA_HASH_SIZE`, which returns the expected hash length (in bytes) for the specified algorithm.
473
474#### Handling hash operation contexts
475
Guy Wildc03c0fc2019-09-03 13:18:04 +0300476After a successful call to `psa_hash_setup()` initializes the operation structure, 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.
mohammad160387a7eeb2018-11-01 11:25:49 +0200477
Guy Wildc03c0fc2019-09-03 13:18:04 +0300478Mbed Crypto implicitly calls `psa_hash_abort()` when:
4791. A call to `psa_hash_update()` fails (returning any status other than `PSA_SUCCESS`).
4801. A call to `psa_hash_finish()` succeeds or fails.
4811. A call to `psa_hash_verify()` succeeds or fails.
mohammad160387a7eeb2018-11-01 11:25:49 +0200482
Guy Wildc03c0fc2019-09-03 13:18:04 +0300483After 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.
mohammad160387a7eeb2018-11-01 11:25:49 +0200484
Guy Wildc03c0fc2019-09-03 13:18:04 +0300485You must call `psa_hash_abort()` at some point for any operation that is initialized successfully (by a successful call to `psa_hash_setup()`) .
mohammad160387a7eeb2018-11-01 11:25:49 +0200486
Guy Wildc03c0fc2019-09-03 13:18:04 +0300487Making 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.
mohammad160387a7eeb2018-11-01 11:25:49 +0200488
489### Generating a random value
490
Guy Wildc03c0fc2019-09-03 13:18:04 +0300491Mbed Crypto can generate random data.
mohammad160387a7eeb2018-11-01 11:25:49 +0200492
Guy Wild802b19f2019-09-03 16:40:44 +0300493**Prerequisites to generating random data:**
Jaeden Amero884738a2019-08-16 17:58:31 +0100494* Initialize the library with a successful call to `psa_crypto_init()`.
mohammad160387a7eeb2018-11-01 11:25:49 +0200495
Guy Wild802b19f2019-09-03 16:40:44 +0300496<span class="notes">**Note:** To generate a random key, use `psa_generate_key()` instead of `psa_generate_random()`.</span>
497
498This example shows how to generate ten bytes of random data by calling `psa_generate_random()`:
mohammad160387a7eeb2018-11-01 11:25:49 +0200499```C
500 psa_status_t status;
501 uint8_t random[10] = { 0 };
mohammad160387a7eeb2018-11-01 11:25:49 +0200502
Jaeden Amero884738a2019-08-16 17:58:31 +0100503 printf("Generate random...\t");
504 fflush(stdout);
505
506 /* Initialize PSA Crypto */
507 status = psa_crypto_init();
508 if (status != PSA_SUCCESS) {
509 printf("Failed to initialize PSA Crypto\n");
510 return;
511 }
512
513 status = psa_generate_random(random, sizeof(random));
514 if (status != PSA_SUCCESS) {
515 printf("Failed to generate a random value\n");
516 return;
517 }
518
519 printf("Generated random data\n");
520
521 /* Clean up */
mohammad160387a7eeb2018-11-01 11:25:49 +0200522 mbedtls_psa_crypto_free();
523```
524
525### Deriving a new key from an existing key
526
Jaeden Amero884738a2019-08-16 17:58:31 +0100527Mbed Crypto provides a key derivation API that lets you derive new keys from
528existing ones. The key derivation API has functions to take inputs, including
529other keys and data, and functions to generate outputs, such as new keys or
Guy Wildc03c0fc2019-09-03 13:18:04 +0300530other data.
mohammad160387a7eeb2018-11-01 11:25:49 +0200531
Guy Wildc03c0fc2019-09-03 13:18:04 +0300532You must first initialize and set up a key derivation context,
533provided 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.
534
535See the documentation for the particular algorithm (such as HKDF or the TLS1.2 PRF) for
536information about which inputs to pass when, and when you can obtain which outputs.
537
538**Prerequisites to working with the key derivation APIs:**
539* Initialize the library with a successful call to `psa_crypto_init()`.
Jaeden Amero884738a2019-08-16 17:58:31 +0100540* Use a key with the appropriate attributes set:
541 * Usage flags set for key derivation (`PSA_KEY_USAGE_DERIVE`)
542 * Key type set to `PSA_KEY_TYPE_DERIVE`.
543 * Algorithm set to a key derivation algorithm
544 (`PSA_ALG_HKDF(PSA_ALG_SHA_256)`).
mohammad160387a7eeb2018-11-01 11:25:49 +0200545
Guy Wildc03c0fc2019-09-03 13:18:04 +0300546**To derive a new AES-CTR 128-bit encryption key into a given key slot using HKDF
547with a given key, salt and information:**
548
5491. Set up the key derivation context using the `psa_key_derivation_setup()`
Jaeden Amero884738a2019-08-16 17:58:31 +0100550function, specifying the derivation algorithm `PSA_ALG_HKDF(PSA_ALG_SHA_256)`.
Guy Wildc03c0fc2019-09-03 13:18:04 +03005511. Provide an optional salt with `psa_key_derivation_input_bytes()`.
Guy Wild802b19f2019-09-03 16:40:44 +03005521. Provide `info` with `psa_key_derivation_input_bytes()`.
5531. Provide `secret` with `psa_key_derivation_input_key()`, referencing a key that
Jaeden Amero884738a2019-08-16 17:58:31 +0100554 can be used for key derivation.
5551. Set the key attributes desired for the new derived key. We'll set
Guy Wildc03c0fc2019-09-03 13:18:04 +0300556 the `PSA_KEY_USAGE_ENCRYPT` parameter and the `PSA_ALG_CTR` algorithm for this
Jaeden Amero884738a2019-08-16 17:58:31 +0100557 example.
5581. Derive the key by calling `psa_key_derivation_output_key()`.
5591. Clean up the key derivation context.
mohammad160387a7eeb2018-11-01 11:25:49 +0200560
Guy Wildc03c0fc2019-09-03 13:18:04 +0300561At this point, the derived key slot holds a new 128-bit AES-CTR encryption key
562derived from the key, salt and information provided:
mohammad160387a7eeb2018-11-01 11:25:49 +0200563```C
Jaeden Amero884738a2019-08-16 17:58:31 +0100564 psa_status_t status;
565 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
566 static const unsigned char key[] = {
mohammad160387a7eeb2018-11-01 11:25:49 +0200567 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
568 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
569 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
570 0x0b };
Jaeden Amero884738a2019-08-16 17:58:31 +0100571 static const unsigned char salt[] = {
572 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
573 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c };
574 static const unsigned char info[] = {
575 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
576 0xf7, 0xf8, 0xf9 };
mohammad160387a7eeb2018-11-01 11:25:49 +0200577 psa_algorithm_t alg = PSA_ALG_HKDF(PSA_ALG_SHA_256);
Jaeden Amero884738a2019-08-16 17:58:31 +0100578 psa_key_derivation_operation_t operation =
579 PSA_KEY_DERIVATION_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200580 size_t derived_bits = 128;
581 size_t capacity = PSA_BITS_TO_BYTES(derived_bits);
Jaeden Amero884738a2019-08-16 17:58:31 +0100582 psa_key_handle_t base_key;
583 psa_key_handle_t derived_key;
mohammad160387a7eeb2018-11-01 11:25:49 +0200584
Jaeden Amero884738a2019-08-16 17:58:31 +0100585 printf("Derive a key (HKDF)...\t");
586 fflush(stdout);
587
588 /* Initialize PSA Crypto */
mohammad160387a7eeb2018-11-01 11:25:49 +0200589 status = psa_crypto_init();
Jaeden Amero884738a2019-08-16 17:58:31 +0100590 if (status != PSA_SUCCESS) {
591 printf("Failed to initialize PSA Crypto\n");
592 return;
593 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200594
Jaeden Amero884738a2019-08-16 17:58:31 +0100595 /* Import a key for use in key derivation. If such a key has already been
596 * generated or imported, you can skip this part. */
597 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
598 psa_set_key_algorithm(&attributes, alg);
599 psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE);
600 status = psa_import_key(&attributes, key, sizeof(key), &base_key);
601 if (status != PSA_SUCCESS) {
602 printf("Failed to import a key\n");
603 return;
604 }
605 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200606
Jaeden Amero884738a2019-08-16 17:58:31 +0100607 /* Derive a key */
608 status = psa_key_derivation_setup(&operation, alg);
609 if (status != PSA_SUCCESS) {
610 printf("Failed to begin key derivation\n");
611 return;
612 }
613 status = psa_key_derivation_set_capacity(&operation, capacity);
614 if (status != PSA_SUCCESS) {
615 printf("Failed to set capacity\n");
616 return;
617 }
618 status = psa_key_derivation_input_bytes(&operation,
619 PSA_KEY_DERIVATION_INPUT_SALT,
620 salt, sizeof(salt));
621 if (status != PSA_SUCCESS) {
622 printf("Failed to input salt (extract)\n");
623 return;
624 }
625 status = psa_key_derivation_input_key(&operation,
626 PSA_KEY_DERIVATION_INPUT_SECRET,
627 base_key);
628 if (status != PSA_SUCCESS) {
629 printf("Failed to input key (extract)\n");
630 return;
631 }
632 status = psa_key_derivation_input_bytes(&operation,
633 PSA_KEY_DERIVATION_INPUT_INFO,
634 info, sizeof(info));
635 if (status != PSA_SUCCESS) {
636 printf("Failed to input info (expand)\n");
637 return;
638 }
639 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
640 psa_set_key_algorithm(&attributes, PSA_ALG_CTR);
641 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
642 psa_set_key_bits(&attributes, 128);
643 status = psa_key_derivation_output_key(&attributes, &operation,
644 &derived_key);
645 if (status != PSA_SUCCESS) {
646 printf("Failed to derive key\n");
647 return;
648 }
649 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200650
Jaeden Amero884738a2019-08-16 17:58:31 +0100651 printf("Derived key\n");
mohammad160387a7eeb2018-11-01 11:25:49 +0200652
Jaeden Amero884738a2019-08-16 17:58:31 +0100653 /* Clean up key derivation operation */
654 psa_key_derivation_abort(&operation);
mohammad160387a7eeb2018-11-01 11:25:49 +0200655
Jaeden Amero884738a2019-08-16 17:58:31 +0100656 /* Destroy the keys */
657 psa_destroy_key(derived_key);
658 psa_destroy_key(base_key);
mohammad160387a7eeb2018-11-01 11:25:49 +0200659
mohammad160387a7eeb2018-11-01 11:25:49 +0200660 mbedtls_psa_crypto_free();
661```
662
663### Authenticating and encrypting or decrypting a message
664
Guy Wildc03c0fc2019-09-03 13:18:04 +0300665Mbed Crypto provides a simple way to authenticate and encrypt with associated data (AEAD), supporting the `PSA_ALG_CCM` algorithm.
mohammad160387a7eeb2018-11-01 11:25:49 +0200666
Guy Wildc03c0fc2019-09-03 13:18:04 +0300667**Prerequisites to working with the AEAD cipher APIs:**
668* Initialize the library with a successful call to `psa_crypto_init()`.
669* The key attributes for the key used for derivation must have the `PSA_KEY_USAGE_ENCRYPT` or `PSA_KEY_USAGE_DECRYPT` usage flags.
mohammad160387a7eeb2018-11-01 11:25:49 +0200670
Guy Wildc03c0fc2019-09-03 13:18:04 +0300671This example shows how to authenticate and encrypt a message:
mohammad160387a7eeb2018-11-01 11:25:49 +0200672```C
mohammad160387a7eeb2018-11-01 11:25:49 +0200673 psa_status_t status;
Jaeden Amero884738a2019-08-16 17:58:31 +0100674 static const uint8_t key[] = {
675 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
676 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF };
677 static const uint8_t nonce[] = {
678 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
679 0x08, 0x09, 0x0A, 0x0B };
680 static const uint8_t additional_data[] = {
681 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25,
682 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 };
683 static const uint8_t input_data[] = {
684 0xB9, 0x6B, 0x49, 0xE2, 0x1D, 0x62, 0x17, 0x41,
685 0x63, 0x28, 0x75, 0xDB, 0x7F, 0x6C, 0x92, 0x43,
686 0xD2, 0xD7, 0xC2 };
687 uint8_t *output_data = NULL;
mohammad160387a7eeb2018-11-01 11:25:49 +0200688 size_t output_size = 0;
689 size_t output_length = 0;
690 size_t tag_length = 16;
Jaeden Amero884738a2019-08-16 17:58:31 +0100691 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
692 psa_key_handle_t handle;
693
694 printf("Authenticate encrypt...\t");
695 fflush(stdout);
696
697 /* Initialize PSA Crypto */
698 status = psa_crypto_init();
699 if (status != PSA_SUCCESS) {
700 printf("Failed to initialize PSA Crypto\n");
701 return;
702 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200703
704 output_size = sizeof(input_data) + tag_length;
Jaeden Amero884738a2019-08-16 17:58:31 +0100705 output_data = (uint8_t *)malloc(output_size);
706 if (!output_data) {
707 printf("Out of memory\n");
708 return;
709 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200710
Jaeden Amero884738a2019-08-16 17:58:31 +0100711 /* Import a key */
712 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
713 psa_set_key_algorithm(&attributes, PSA_ALG_CCM);
714 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
715 psa_set_key_bits(&attributes, 128);
716 status = psa_import_key(&attributes, key, sizeof(key), &handle);
717 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200718
Jaeden Amero884738a2019-08-16 17:58:31 +0100719 /* Authenticate and encrypt */
720 status = psa_aead_encrypt(handle, PSA_ALG_CCM,
mohammad160387a7eeb2018-11-01 11:25:49 +0200721 nonce, sizeof(nonce),
722 additional_data, sizeof(additional_data),
723 input_data, sizeof(input_data),
724 output_data, output_size,
725 &output_length);
Jaeden Amero884738a2019-08-16 17:58:31 +0100726 if (status != PSA_SUCCESS) {
727 printf("Failed to authenticate and encrypt\n");
728 return;
729 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200730
Jaeden Amero884738a2019-08-16 17:58:31 +0100731 printf("Authenticated and encrypted\n");
732
733 /* Clean up */
734 free(output_data);
735
736 /* Destroy the key */
737 psa_destroy_key(handle);
738
mohammad160387a7eeb2018-11-01 11:25:49 +0200739 mbedtls_psa_crypto_free();
740```
741
Guy Wildc03c0fc2019-09-03 13:18:04 +0300742This example shows how to authenticate and decrypt a message:
mohammad160387a7eeb2018-11-01 11:25:49 +0200743
744```C
mohammad160387a7eeb2018-11-01 11:25:49 +0200745 psa_status_t status;
Jaeden Amero884738a2019-08-16 17:58:31 +0100746 static const uint8_t key[] = {
mohammad160387a7eeb2018-11-01 11:25:49 +0200747 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
Jaeden Amero884738a2019-08-16 17:58:31 +0100748 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF };
749 static const uint8_t nonce[] = {
750 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
751 0x08, 0x09, 0x0A, 0x0B };
752 static const uint8_t additional_data[] = {
753 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25,
754 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 };
755 static const uint8_t input_data[] = {
756 0x20, 0x30, 0xE0, 0x36, 0xED, 0x09, 0xA0, 0x45, 0xAF, 0x3C, 0xBA, 0xEE,
757 0x0F, 0xC8, 0x48, 0xAF, 0xCD, 0x89, 0x54, 0xF4, 0xF6, 0x3F, 0x28, 0x9A,
758 0xA1, 0xDD, 0xB2, 0xB8, 0x09, 0xCD, 0x7C, 0xE1, 0x46, 0xE9, 0x98 };
759 uint8_t *output_data = NULL;
mohammad160387a7eeb2018-11-01 11:25:49 +0200760 size_t output_size = 0;
761 size_t output_length = 0;
Jaeden Amero884738a2019-08-16 17:58:31 +0100762 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
763 psa_key_handle_t handle;
764
765 printf("Authenticate decrypt...\t");
766 fflush(stdout);
767
768 /* Initialize PSA Crypto */
769 status = psa_crypto_init();
770 if (status != PSA_SUCCESS) {
771 printf("Failed to initialize PSA Crypto\n");
772 return;
773 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200774
775 output_size = sizeof(input_data);
Jaeden Amero884738a2019-08-16 17:58:31 +0100776 output_data = (uint8_t *)malloc(output_size);
777 if (!output_data) {
778 printf("Out of memory\n");
779 return;
780 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200781
Jaeden Amero884738a2019-08-16 17:58:31 +0100782 /* Import a key */
783 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
784 psa_set_key_algorithm(&attributes, PSA_ALG_CCM);
785 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
786 psa_set_key_bits(&attributes, 128);
787 status = psa_import_key(&attributes, key, sizeof(key), &handle);
788 if (status != PSA_SUCCESS) {
789 printf("Failed to import a key\n");
790 return;
791 }
792 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200793
Jaeden Amero884738a2019-08-16 17:58:31 +0100794 /* Authenticate and decrypt */
795 status = psa_aead_decrypt(handle, PSA_ALG_CCM,
mohammad160387a7eeb2018-11-01 11:25:49 +0200796 nonce, sizeof(nonce),
797 additional_data, sizeof(additional_data),
798 input_data, sizeof(input_data),
799 output_data, output_size,
800 &output_length);
Jaeden Amero884738a2019-08-16 17:58:31 +0100801 if (status != PSA_SUCCESS) {
802 printf("Failed to authenticate and decrypt %ld\n", status);
803 return;
804 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200805
Jaeden Amero884738a2019-08-16 17:58:31 +0100806 printf("Authenticated and decrypted\n");
807
808 /* Clean up */
809 free(output_data);
810
811 /* Destroy the key */
812 psa_destroy_key(handle);
813
mohammad160387a7eeb2018-11-01 11:25:49 +0200814 mbedtls_psa_crypto_free();
815```
816
817### Generating and exporting keys
818
819Mbed Crypto provides a simple way to generate a key or key pair.
820
Guy Wildc03c0fc2019-09-03 13:18:04 +0300821**Prerequisites to using key generation and export APIs:**
822* Initialize the library with a successful call to `psa_crypto_init()`.
mohammad160387a7eeb2018-11-01 11:25:49 +0200823
Guy Wildc03c0fc2019-09-03 13:18:04 +0300824**To generate an ECDSA key:**
Jaeden Amero884738a2019-08-16 17:58:31 +01008251. Set the desired key attributes for key generation by calling
826 `psa_set_key_algorithm()` with the chosen ECDSA algorithm (such as
Guy Wildc03c0fc2019-09-03 13:18:04 +0300827 `PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)`). Do not set
Guy Wild802b19f2019-09-03 16:40:44 +0300828 `PSA_KEY_USAGE_EXPORT`; we only want to export the public key, not the key
Jaeden Amero884738a2019-08-16 17:58:31 +0100829 pair (or private key).
8301. Generate a key by calling `psa_generate_key()`.
Guy Wildc03c0fc2019-09-03 13:18:04 +03008311. Export the generated public key by calling `psa_export_public_key()`:
mohammad160387a7eeb2018-11-01 11:25:49 +0200832```C
Jaeden Amero884738a2019-08-16 17:58:31 +0100833 enum {
834 key_bits = 256,
835 };
836 psa_status_t status;
mohammad160387a7eeb2018-11-01 11:25:49 +0200837 size_t exported_length = 0;
Jaeden Amero884738a2019-08-16 17:58:31 +0100838 static uint8_t exported[PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits)];
839 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
840 psa_key_handle_t handle;
mohammad160387a7eeb2018-11-01 11:25:49 +0200841
Jaeden Amero884738a2019-08-16 17:58:31 +0100842 printf("Generate a key pair...\t");
843 fflush(stdout);
mohammad160387a7eeb2018-11-01 11:25:49 +0200844
Jaeden Amero884738a2019-08-16 17:58:31 +0100845 /* Initialize PSA Crypto */
846 status = psa_crypto_init();
847 if (status != PSA_SUCCESS) {
848 printf("Failed to initialize PSA Crypto\n");
849 return;
850 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200851
852 /* Generate a key */
Jaeden Amero884738a2019-08-16 17:58:31 +0100853 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN);
854 psa_set_key_algorithm(&attributes,
855 PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
856 psa_set_key_type(&attributes,
857 PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1));
858 psa_set_key_bits(&attributes, key_bits);
859 status = psa_generate_key(&attributes, &handle);
860 if (status != PSA_SUCCESS) {
861 printf("Failed to generate key\n");
862 return;
863 }
864 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200865
Jaeden Amero884738a2019-08-16 17:58:31 +0100866 status = psa_export_public_key(handle, exported, sizeof(exported),
867 &exported_length);
868 if (status != PSA_SUCCESS) {
869 printf("Failed to export public key %ld\n", status);
870 return;
871 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200872
Jaeden Amero884738a2019-08-16 17:58:31 +0100873 printf("Exported a public key\n");
874
875 /* Destroy the key */
876 psa_destroy_key(handle);
877
mohammad160387a7eeb2018-11-01 11:25:49 +0200878 mbedtls_psa_crypto_free();
879```
880
Guy Wild802b19f2019-09-03 16:40:44 +0300881### More about the Mbed Crypto API
mohammad160387a7eeb2018-11-01 11:25:49 +0200882
Guy Wildc03c0fc2019-09-03 13:18:04 +0300883For more information about PSA Crypto, download the *PSA Cryptography API* PDF under [PSA APIs](https://developer.arm.com/architectures/security-architectures/platform-security-architecture#implement).