blob: 41a0c2567c1f2e8dc7d2bd8fd30510978febd1f1 [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 Wild5033fdd2019-09-04 09:14:55 +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 Wild5033fdd2019-09-04 09:14:55 +030067import it. Importing the key creates 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 Wild5033fdd2019-09-04 09:14:55 +0300124This example shows how to sign a hash that has already been calculated:
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;
Guy Wild5033fdd2019-09-04 09:14:55 +0300129 uint8_t hash[32] = {0x50, 0xd8, 0x58, 0xe0, 0x98, 0x5e, 0xcc, 0x7f,
130 0x60, 0x41, 0x8a, 0xaf, 0x0c, 0xc5, 0xab, 0x58,
131 0x7f, 0x42, 0xc2, 0x57, 0x0a, 0x88, 0x40, 0x95,
132 0xa9, 0xe8, 0xcc, 0xac, 0xd0, 0xf6, 0x54, 0x5c};
Jaeden Amero884738a2019-08-16 17:58:31 +0100133 uint8_t signature[PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE] = {0};
mohammad160387a7eeb2018-11-01 11:25:49 +0200134 size_t signature_length;
Jaeden Amero884738a2019-08-16 17:58:31 +0100135 psa_key_handle_t handle;
mohammad160387a7eeb2018-11-01 11:25:49 +0200136
Jaeden Amero884738a2019-08-16 17:58:31 +0100137 printf("Sign a message...\t");
138 fflush(stdout);
139
140 /* Initialize PSA Crypto */
mohammad160387a7eeb2018-11-01 11:25:49 +0200141 status = psa_crypto_init();
Jaeden Amero884738a2019-08-16 17:58:31 +0100142 if (status != PSA_SUCCESS) {
143 printf("Failed to initialize PSA Crypto\n");
144 return;
145 }
146
147 /* Set key attributes */
148 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN);
149 psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_SIGN_RAW);
150 psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
151 psa_set_key_bits(&attributes, 1024);
mohammad160387a7eeb2018-11-01 11:25:49 +0200152
153 /* Import the key */
Jaeden Amero884738a2019-08-16 17:58:31 +0100154 status = psa_import_key(&attributes, key, sizeof(key), &handle);
155 if (status != PSA_SUCCESS) {
156 printf("Failed to import key\n");
157 return;
158 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200159
Jaeden Amero884738a2019-08-16 17:58:31 +0100160 /* Sign message using the key */
161 status = psa_asymmetric_sign(handle, PSA_ALG_RSA_PKCS1V15_SIGN_RAW,
162 hash, sizeof(hash),
mohammad160387a7eeb2018-11-01 11:25:49 +0200163 signature, sizeof(signature),
164 &signature_length);
Jaeden Amero884738a2019-08-16 17:58:31 +0100165 if (status != PSA_SUCCESS) {
166 printf("Failed to sign\n");
167 return;
168 }
169
170 printf("Signed a message\n");
171
172 /* Free the attributes */
173 psa_reset_key_attributes(&attributes);
174
mohammad160387a7eeb2018-11-01 11:25:49 +0200175 /* Destroy the key */
Jaeden Amero884738a2019-08-16 17:58:31 +0100176 psa_destroy_key(handle);
177
mohammad160387a7eeb2018-11-01 11:25:49 +0200178 mbedtls_psa_crypto_free();
179```
180
Jaeden Amero884738a2019-08-16 17:58:31 +0100181### Using symmetric ciphers
mohammad160387a7eeb2018-11-01 11:25:49 +0200182
Guy Wildc03c0fc2019-09-03 13:18:04 +0300183Mbed Crypto supports encrypting and decrypting messages using various symmetric cipher algorithms (both block and stream ciphers).
mohammad160387a7eeb2018-11-01 11:25:49 +0200184
Guy Wildc03c0fc2019-09-03 13:18:04 +0300185**Prerequisites to working with the symmetric cipher API:**
186* Initialize the library with a successful call to `psa_crypto_init()`.
Guy Wild5033fdd2019-09-04 09:14:55 +0300187* Have a handle to 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.
mohammad160387a7eeb2018-11-01 11:25:49 +0200188
Guy Wildc03c0fc2019-09-03 13:18:04 +0300189**To encrypt a message with a symmetric cipher:**
mohammad160387a7eeb2018-11-01 11:25:49 +02001901. Allocate an operation (`psa_cipher_operation_t`) structure to pass to the cipher functions.
Guy Wildc03c0fc2019-09-03 13:18:04 +03001911. Call `psa_cipher_encrypt_setup()` to initialize the operation structure and specify the algorithm and the key to be used.
1921. 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 +03001931. 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 +03001941. Call `psa_cipher_finish()` to end the operation and output the encrypted message.
mohammad160387a7eeb2018-11-01 11:25:49 +0200195
Guy Wild802b19f2019-09-03 16:40:44 +0300196This 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 +0200197```c
Jaeden Amero884738a2019-08-16 17:58:31 +0100198 enum {
199 block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES),
200 };
201 psa_status_t status;
202 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200203 psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING;
Jaeden Amero884738a2019-08-16 17:58:31 +0100204 uint8_t plaintext[block_size] = SOME_PLAINTEXT;
205 uint8_t iv[block_size];
mohammad160387a7eeb2018-11-01 11:25:49 +0200206 size_t iv_len;
Jaeden Amero884738a2019-08-16 17:58:31 +0100207 uint8_t key[] = AES_KEY;
208 uint8_t output[block_size];
mohammad160387a7eeb2018-11-01 11:25:49 +0200209 size_t output_len;
Jaeden Amero884738a2019-08-16 17:58:31 +0100210 psa_key_handle_t handle;
211 psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200212
Jaeden Amero884738a2019-08-16 17:58:31 +0100213 printf("Encrypt with cipher...\t");
214 fflush(stdout);
mohammad160387a7eeb2018-11-01 11:25:49 +0200215
Jaeden Amero884738a2019-08-16 17:58:31 +0100216 /* Initialize PSA Crypto */
217 status = psa_crypto_init();
218 if (status != PSA_SUCCESS)
219 {
220 printf("Failed to initialize PSA Crypto\n");
221 return;
222 }
223
224 /* Import a key */
225 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
226 psa_set_key_algorithm(&attributes, alg);
227 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
228 psa_set_key_bits(&attributes, 128);
229 status = psa_import_key(&attributes, key, sizeof(key), &handle);
230 if (status != PSA_SUCCESS) {
231 printf("Failed to import a key\n");
232 return;
233 }
234 psa_reset_key_attributes(&attributes);
235
236 /* Encrypt the plaintext */
237 status = psa_cipher_encrypt_setup(&operation, handle, alg);
238 if (status != PSA_SUCCESS) {
239 printf("Failed to begin cipher operation\n");
240 return;
241 }
242 status = psa_cipher_generate_iv(&operation, iv, sizeof(iv), &iv_len);
243 if (status != PSA_SUCCESS) {
244 printf("Failed to generate IV\n");
245 return;
246 }
247 status = psa_cipher_update(&operation, plaintext, sizeof(plaintext),
248 output, sizeof(output), &output_len);
249 if (status != PSA_SUCCESS) {
250 printf("Failed to update cipher operation\n");
251 return;
252 }
253 status = psa_cipher_finish(&operation, output + output_len,
254 sizeof(output) - output_len, &output_len);
255 if (status != PSA_SUCCESS) {
256 printf("Failed to finish cipher operation\n");
257 return;
258 }
259 printf("Encrypted plaintext\n");
260
mohammad160387a7eeb2018-11-01 11:25:49 +0200261 /* Clean up cipher operation context */
262 psa_cipher_abort(&operation);
Jaeden Amero884738a2019-08-16 17:58:31 +0100263
264 /* Destroy the key */
265 psa_destroy_key(handle);
266
267 mbedtls_psa_crypto_free();
mohammad160387a7eeb2018-11-01 11:25:49 +0200268```
269
Guy Wildc03c0fc2019-09-03 13:18:04 +0300270**To decrypt a message with a symmetric cipher:**
mohammad160387a7eeb2018-11-01 11:25:49 +02002711. Allocate an operation (`psa_cipher_operation_t`) structure to pass to the cipher functions.
Guy Wildc03c0fc2019-09-03 13:18:04 +03002721. Call `psa_cipher_decrypt_setup()` to initialize the operation structure and to specify the algorithm and the key to be used.
2731. Call `psa_cipher_set_iv()` with the IV for the decryption.
Guy Wild802b19f2019-09-03 16:40:44 +03002741. 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 +03002751. Call `psa_cipher_finish()` to end the operation and output the decrypted message.
mohammad160387a7eeb2018-11-01 11:25:49 +0200276
Guy Wildc03c0fc2019-09-03 13:18:04 +0300277This example shows how to decrypt encrypted data using an AES key in CBC mode with no padding
mohammad160387a7eeb2018-11-01 11:25:49 +0200278(assuming all prerequisites have been fulfilled):
279```c
Jaeden Amero884738a2019-08-16 17:58:31 +0100280 enum {
281 block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES),
282 };
283 psa_status_t status;
284 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200285 psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING;
Jaeden Amero884738a2019-08-16 17:58:31 +0100286 psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
287 uint8_t ciphertext[block_size] = SOME_CIPHERTEXT;
288 uint8_t iv[block_size] = ENCRYPTED_WITH_IV;
289 uint8_t key[] = AES_KEY;
290 uint8_t output[block_size];
mohammad160387a7eeb2018-11-01 11:25:49 +0200291 size_t output_len;
Jaeden Amero884738a2019-08-16 17:58:31 +0100292 psa_key_handle_t handle;
mohammad160387a7eeb2018-11-01 11:25:49 +0200293
Jaeden Amero884738a2019-08-16 17:58:31 +0100294 printf("Decrypt with cipher...\t");
295 fflush(stdout);
mohammad160387a7eeb2018-11-01 11:25:49 +0200296
Jaeden Amero884738a2019-08-16 17:58:31 +0100297 /* Initialize PSA Crypto */
298 status = psa_crypto_init();
299 if (status != PSA_SUCCESS)
300 {
301 printf("Failed to initialize PSA Crypto\n");
302 return;
303 }
304
305 /* Import a key */
306 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
307 psa_set_key_algorithm(&attributes, alg);
308 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
309 psa_set_key_bits(&attributes, 128);
310 status = psa_import_key(&attributes, key, sizeof(key), &handle);
311 if (status != PSA_SUCCESS) {
312 printf("Failed to import a key\n");
313 return;
314 }
315 psa_reset_key_attributes(&attributes);
316
317 /* Decrypt the ciphertext */
318 status = psa_cipher_decrypt_setup(&operation, handle, alg);
319 if (status != PSA_SUCCESS) {
320 printf("Failed to begin cipher operation\n");
321 return;
322 }
323 status = psa_cipher_set_iv(&operation, iv, sizeof(iv));
324 if (status != PSA_SUCCESS) {
325 printf("Failed to set IV\n");
326 return;
327 }
328 status = psa_cipher_update(&operation, ciphertext, sizeof(ciphertext),
329 output, sizeof(output), &output_len);
330 if (status != PSA_SUCCESS) {
331 printf("Failed to update cipher operation\n");
332 return;
333 }
334 status = psa_cipher_finish(&operation, output + output_len,
335 sizeof(output) - output_len, &output_len);
336 if (status != PSA_SUCCESS) {
337 printf("Failed to finish cipher operation\n");
338 return;
339 }
340 printf("Decrypted ciphertext\n");
341
mohammad160387a7eeb2018-11-01 11:25:49 +0200342 /* Clean up cipher operation context */
343 psa_cipher_abort(&operation);
Jaeden Amero884738a2019-08-16 17:58:31 +0100344
345 /* Destroy the key */
346 psa_destroy_key(handle);
347
348 mbedtls_psa_crypto_free();
mohammad160387a7eeb2018-11-01 11:25:49 +0200349```
350
351#### Handling cipher operation contexts
352
Guy Wildc03c0fc2019-09-03 13:18:04 +0300353After 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 +0200354
Guy Wildc03c0fc2019-09-03 13:18:04 +0300355The call to `psa_cipher_abort()` frees any resources associated with the operation, except for the operation structure itself.
mohammad160387a7eeb2018-11-01 11:25:49 +0200356
Guy Wildc03c0fc2019-09-03 13:18:04 +0300357Mbed Crypto implicitly calls `psa_cipher_abort()` when:
358* A call to `psa_cipher_generate_iv()`, `psa_cipher_set_iv()` or `psa_cipher_update()` fails (returning any status other than `PSA_SUCCESS`).
359* A call to `psa_cipher_finish()` succeeds or fails.
mohammad160387a7eeb2018-11-01 11:25:49 +0200360
Guy Wildc03c0fc2019-09-03 13:18:04 +0300361After 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 +0200362
Guy Wildc03c0fc2019-09-03 13:18:04 +0300363You 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()`).
364
365Making 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 +0200366
367### Hashing a message
368
Jaeden Amero884738a2019-08-16 17:58:31 +0100369Mbed Crypto lets you compute and verify hashes using various hashing
370algorithms.
mohammad160387a7eeb2018-11-01 11:25:49 +0200371
Guy Wildc03c0fc2019-09-03 13:18:04 +0300372**Prerequisites to working with the hash APIs:**
373* Initialize the library with a successful call to `psa_crypto_init()`.
mohammad160387a7eeb2018-11-01 11:25:49 +0200374
Guy Wildc03c0fc2019-09-03 13:18:04 +0300375**To calculate a hash:**
mohammad160387a7eeb2018-11-01 11:25:49 +02003761. Allocate an operation structure (`psa_hash_operation_t`) to pass to the hash functions.
Guy Wildc03c0fc2019-09-03 13:18:04 +03003771. Call `psa_hash_setup()` to initialize the operation structure and specify the hash algorithm.
Guy Wild802b19f2019-09-03 16:40:44 +03003781. 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 +03003791. 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 +0200380
Guy Wildc03c0fc2019-09-03 13:18:04 +0300381This example shows how to calculate the `SHA-256` hash of a message:
mohammad160387a7eeb2018-11-01 11:25:49 +0200382```c
Jaeden Amero884738a2019-08-16 17:58:31 +0100383 psa_status_t status;
mohammad160387a7eeb2018-11-01 11:25:49 +0200384 psa_algorithm_t alg = PSA_ALG_SHA_256;
Jaeden Amero884738a2019-08-16 17:58:31 +0100385 psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200386 unsigned char input[] = { 'a', 'b', 'c' };
387 unsigned char actual_hash[PSA_HASH_MAX_SIZE];
388 size_t actual_hash_len;
389
Jaeden Amero884738a2019-08-16 17:58:31 +0100390 printf("Hash a message...\t");
391 fflush(stdout);
392
393 /* Initialize PSA Crypto */
394 status = psa_crypto_init();
395 if (status != PSA_SUCCESS) {
396 printf("Failed to initialize PSA Crypto\n");
397 return;
398 }
399
mohammad160387a7eeb2018-11-01 11:25:49 +0200400 /* Compute hash of message */
Jaeden Amero884738a2019-08-16 17:58:31 +0100401 status = psa_hash_setup(&operation, alg);
402 if (status != PSA_SUCCESS) {
403 printf("Failed to begin hash operation\n");
404 return;
405 }
406 status = psa_hash_update(&operation, input, sizeof(input));
407 if (status != PSA_SUCCESS) {
408 printf("Failed to update hash operation\n");
409 return;
410 }
411 status = psa_hash_finish(&operation, actual_hash, sizeof(actual_hash),
412 &actual_hash_len);
413 if (status != PSA_SUCCESS) {
414 printf("Failed to finish hash operation\n");
415 return;
416 }
417
418 printf("Hashed a message\n");
mohammad160387a7eeb2018-11-01 11:25:49 +0200419
420 /* Clean up hash operation context */
421 psa_hash_abort(&operation);
Jaeden Amero884738a2019-08-16 17:58:31 +0100422
423 mbedtls_psa_crypto_free();
mohammad160387a7eeb2018-11-01 11:25:49 +0200424```
425
Guy Wildc03c0fc2019-09-03 13:18:04 +0300426This example shows how to verify the `SHA-256` hash of a message:
mohammad160387a7eeb2018-11-01 11:25:49 +0200427```c
Jaeden Amero884738a2019-08-16 17:58:31 +0100428 psa_status_t status;
mohammad160387a7eeb2018-11-01 11:25:49 +0200429 psa_algorithm_t alg = PSA_ALG_SHA_256;
Jaeden Amero884738a2019-08-16 17:58:31 +0100430 psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200431 unsigned char input[] = { 'a', 'b', 'c' };
432 unsigned char expected_hash[] = {
433 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde,
434 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
435 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad
436 };
437 size_t expected_hash_len = PSA_HASH_SIZE(alg);
438
Jaeden Amero884738a2019-08-16 17:58:31 +0100439 printf("Verify a hash...\t");
440 fflush(stdout);
441
442 /* Initialize PSA Crypto */
443 status = psa_crypto_init();
444 if (status != PSA_SUCCESS) {
445 printf("Failed to initialize PSA Crypto\n");
446 return;
447 }
448
mohammad160387a7eeb2018-11-01 11:25:49 +0200449 /* Verify message hash */
Jaeden Amero884738a2019-08-16 17:58:31 +0100450 status = psa_hash_setup(&operation, alg);
451 if (status != PSA_SUCCESS) {
452 printf("Failed to begin hash operation\n");
453 return;
454 }
455 status = psa_hash_update(&operation, input, sizeof(input));
456 if (status != PSA_SUCCESS) {
457 printf("Failed to update hash operation\n");
458 return;
459 }
460 status = psa_hash_verify(&operation, expected_hash, expected_hash_len);
461 if (status != PSA_SUCCESS) {
462 printf("Failed to verify hash\n");
463 return;
464 }
465
466 printf("Verified a hash\n");
467
468 /* Clean up hash operation context */
469 psa_hash_abort(&operation);
470
471 mbedtls_psa_crypto_free();
mohammad160387a7eeb2018-11-01 11:25:49 +0200472```
473
474The API provides the macro `PSA_HASH_SIZE`, which returns the expected hash length (in bytes) for the specified algorithm.
475
476#### Handling hash operation contexts
477
Guy Wildc03c0fc2019-09-03 13:18:04 +0300478After 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 +0200479
Guy Wildc03c0fc2019-09-03 13:18:04 +0300480Mbed Crypto implicitly calls `psa_hash_abort()` when:
4811. A call to `psa_hash_update()` fails (returning any status other than `PSA_SUCCESS`).
4821. A call to `psa_hash_finish()` succeeds or fails.
4831. A call to `psa_hash_verify()` succeeds or fails.
mohammad160387a7eeb2018-11-01 11:25:49 +0200484
Guy Wildc03c0fc2019-09-03 13:18:04 +0300485After 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 +0200486
Guy Wildc03c0fc2019-09-03 13:18:04 +0300487You 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 +0200488
Guy Wildc03c0fc2019-09-03 13:18:04 +0300489Making 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 +0200490
491### Generating a random value
492
Guy Wildc03c0fc2019-09-03 13:18:04 +0300493Mbed Crypto can generate random data.
mohammad160387a7eeb2018-11-01 11:25:49 +0200494
Guy Wild802b19f2019-09-03 16:40:44 +0300495**Prerequisites to generating random data:**
Jaeden Amero884738a2019-08-16 17:58:31 +0100496* Initialize the library with a successful call to `psa_crypto_init()`.
mohammad160387a7eeb2018-11-01 11:25:49 +0200497
Guy Wild802b19f2019-09-03 16:40:44 +0300498<span class="notes">**Note:** To generate a random key, use `psa_generate_key()` instead of `psa_generate_random()`.</span>
499
500This example shows how to generate ten bytes of random data by calling `psa_generate_random()`:
mohammad160387a7eeb2018-11-01 11:25:49 +0200501```C
502 psa_status_t status;
503 uint8_t random[10] = { 0 };
mohammad160387a7eeb2018-11-01 11:25:49 +0200504
Jaeden Amero884738a2019-08-16 17:58:31 +0100505 printf("Generate random...\t");
506 fflush(stdout);
507
508 /* Initialize PSA Crypto */
509 status = psa_crypto_init();
510 if (status != PSA_SUCCESS) {
511 printf("Failed to initialize PSA Crypto\n");
512 return;
513 }
514
515 status = psa_generate_random(random, sizeof(random));
516 if (status != PSA_SUCCESS) {
517 printf("Failed to generate a random value\n");
518 return;
519 }
520
521 printf("Generated random data\n");
522
523 /* Clean up */
mohammad160387a7eeb2018-11-01 11:25:49 +0200524 mbedtls_psa_crypto_free();
525```
526
527### Deriving a new key from an existing key
528
Jaeden Amero884738a2019-08-16 17:58:31 +0100529Mbed Crypto provides a key derivation API that lets you derive new keys from
530existing ones. The key derivation API has functions to take inputs, including
531other keys and data, and functions to generate outputs, such as new keys or
Guy Wildc03c0fc2019-09-03 13:18:04 +0300532other data.
mohammad160387a7eeb2018-11-01 11:25:49 +0200533
Guy Wildc03c0fc2019-09-03 13:18:04 +0300534You must first initialize and set up a key derivation context,
535provided 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.
536
537See the documentation for the particular algorithm (such as HKDF or the TLS1.2 PRF) for
538information about which inputs to pass when, and when you can obtain which outputs.
539
540**Prerequisites to working with the key derivation APIs:**
541* Initialize the library with a successful call to `psa_crypto_init()`.
Jaeden Amero884738a2019-08-16 17:58:31 +0100542* Use a key with the appropriate attributes set:
543 * Usage flags set for key derivation (`PSA_KEY_USAGE_DERIVE`)
544 * Key type set to `PSA_KEY_TYPE_DERIVE`.
545 * Algorithm set to a key derivation algorithm
546 (`PSA_ALG_HKDF(PSA_ALG_SHA_256)`).
mohammad160387a7eeb2018-11-01 11:25:49 +0200547
Guy Wildc03c0fc2019-09-03 13:18:04 +0300548**To derive a new AES-CTR 128-bit encryption key into a given key slot using HKDF
549with a given key, salt and information:**
550
5511. Set up the key derivation context using the `psa_key_derivation_setup()`
Jaeden Amero884738a2019-08-16 17:58:31 +0100552function, specifying the derivation algorithm `PSA_ALG_HKDF(PSA_ALG_SHA_256)`.
Guy Wildc03c0fc2019-09-03 13:18:04 +03005531. Provide an optional salt with `psa_key_derivation_input_bytes()`.
Guy Wild802b19f2019-09-03 16:40:44 +03005541. Provide `info` with `psa_key_derivation_input_bytes()`.
5551. Provide `secret` with `psa_key_derivation_input_key()`, referencing a key that
Jaeden Amero884738a2019-08-16 17:58:31 +0100556 can be used for key derivation.
5571. Set the key attributes desired for the new derived key. We'll set
Guy Wildc03c0fc2019-09-03 13:18:04 +0300558 the `PSA_KEY_USAGE_ENCRYPT` parameter and the `PSA_ALG_CTR` algorithm for this
Jaeden Amero884738a2019-08-16 17:58:31 +0100559 example.
5601. Derive the key by calling `psa_key_derivation_output_key()`.
5611. Clean up the key derivation context.
mohammad160387a7eeb2018-11-01 11:25:49 +0200562
Guy Wildc03c0fc2019-09-03 13:18:04 +0300563At this point, the derived key slot holds a new 128-bit AES-CTR encryption key
564derived from the key, salt and information provided:
mohammad160387a7eeb2018-11-01 11:25:49 +0200565```C
Jaeden Amero884738a2019-08-16 17:58:31 +0100566 psa_status_t status;
567 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
568 static const unsigned char key[] = {
mohammad160387a7eeb2018-11-01 11:25:49 +0200569 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
570 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
571 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
572 0x0b };
Jaeden Amero884738a2019-08-16 17:58:31 +0100573 static const unsigned char salt[] = {
574 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
575 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c };
576 static const unsigned char info[] = {
577 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
578 0xf7, 0xf8, 0xf9 };
mohammad160387a7eeb2018-11-01 11:25:49 +0200579 psa_algorithm_t alg = PSA_ALG_HKDF(PSA_ALG_SHA_256);
Jaeden Amero884738a2019-08-16 17:58:31 +0100580 psa_key_derivation_operation_t operation =
581 PSA_KEY_DERIVATION_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200582 size_t derived_bits = 128;
583 size_t capacity = PSA_BITS_TO_BYTES(derived_bits);
Jaeden Amero884738a2019-08-16 17:58:31 +0100584 psa_key_handle_t base_key;
585 psa_key_handle_t derived_key;
mohammad160387a7eeb2018-11-01 11:25:49 +0200586
Jaeden Amero884738a2019-08-16 17:58:31 +0100587 printf("Derive a key (HKDF)...\t");
588 fflush(stdout);
589
590 /* Initialize PSA Crypto */
mohammad160387a7eeb2018-11-01 11:25:49 +0200591 status = psa_crypto_init();
Jaeden Amero884738a2019-08-16 17:58:31 +0100592 if (status != PSA_SUCCESS) {
593 printf("Failed to initialize PSA Crypto\n");
594 return;
595 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200596
Jaeden Amero884738a2019-08-16 17:58:31 +0100597 /* Import a key for use in key derivation. If such a key has already been
598 * generated or imported, you can skip this part. */
599 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
600 psa_set_key_algorithm(&attributes, alg);
601 psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE);
602 status = psa_import_key(&attributes, key, sizeof(key), &base_key);
603 if (status != PSA_SUCCESS) {
604 printf("Failed to import a key\n");
605 return;
606 }
607 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200608
Jaeden Amero884738a2019-08-16 17:58:31 +0100609 /* Derive a key */
610 status = psa_key_derivation_setup(&operation, alg);
611 if (status != PSA_SUCCESS) {
612 printf("Failed to begin key derivation\n");
613 return;
614 }
615 status = psa_key_derivation_set_capacity(&operation, capacity);
616 if (status != PSA_SUCCESS) {
617 printf("Failed to set capacity\n");
618 return;
619 }
620 status = psa_key_derivation_input_bytes(&operation,
621 PSA_KEY_DERIVATION_INPUT_SALT,
622 salt, sizeof(salt));
623 if (status != PSA_SUCCESS) {
624 printf("Failed to input salt (extract)\n");
625 return;
626 }
627 status = psa_key_derivation_input_key(&operation,
628 PSA_KEY_DERIVATION_INPUT_SECRET,
629 base_key);
630 if (status != PSA_SUCCESS) {
631 printf("Failed to input key (extract)\n");
632 return;
633 }
634 status = psa_key_derivation_input_bytes(&operation,
635 PSA_KEY_DERIVATION_INPUT_INFO,
636 info, sizeof(info));
637 if (status != PSA_SUCCESS) {
638 printf("Failed to input info (expand)\n");
639 return;
640 }
641 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
642 psa_set_key_algorithm(&attributes, PSA_ALG_CTR);
643 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
644 psa_set_key_bits(&attributes, 128);
645 status = psa_key_derivation_output_key(&attributes, &operation,
646 &derived_key);
647 if (status != PSA_SUCCESS) {
648 printf("Failed to derive key\n");
649 return;
650 }
651 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200652
Jaeden Amero884738a2019-08-16 17:58:31 +0100653 printf("Derived key\n");
mohammad160387a7eeb2018-11-01 11:25:49 +0200654
Jaeden Amero884738a2019-08-16 17:58:31 +0100655 /* Clean up key derivation operation */
656 psa_key_derivation_abort(&operation);
mohammad160387a7eeb2018-11-01 11:25:49 +0200657
Jaeden Amero884738a2019-08-16 17:58:31 +0100658 /* Destroy the keys */
659 psa_destroy_key(derived_key);
660 psa_destroy_key(base_key);
mohammad160387a7eeb2018-11-01 11:25:49 +0200661
mohammad160387a7eeb2018-11-01 11:25:49 +0200662 mbedtls_psa_crypto_free();
663```
664
665### Authenticating and encrypting or decrypting a message
666
Guy Wildc03c0fc2019-09-03 13:18:04 +0300667Mbed 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 +0200668
Guy Wildc03c0fc2019-09-03 13:18:04 +0300669**Prerequisites to working with the AEAD cipher APIs:**
670* Initialize the library with a successful call to `psa_crypto_init()`.
671* 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 +0200672
Guy Wildc03c0fc2019-09-03 13:18:04 +0300673This example shows how to authenticate and encrypt a message:
mohammad160387a7eeb2018-11-01 11:25:49 +0200674```C
mohammad160387a7eeb2018-11-01 11:25:49 +0200675 psa_status_t status;
Jaeden Amero884738a2019-08-16 17:58:31 +0100676 static const uint8_t key[] = {
677 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
678 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF };
679 static const uint8_t nonce[] = {
680 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
681 0x08, 0x09, 0x0A, 0x0B };
682 static const uint8_t additional_data[] = {
683 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25,
684 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 };
685 static const uint8_t input_data[] = {
686 0xB9, 0x6B, 0x49, 0xE2, 0x1D, 0x62, 0x17, 0x41,
687 0x63, 0x28, 0x75, 0xDB, 0x7F, 0x6C, 0x92, 0x43,
688 0xD2, 0xD7, 0xC2 };
689 uint8_t *output_data = NULL;
mohammad160387a7eeb2018-11-01 11:25:49 +0200690 size_t output_size = 0;
691 size_t output_length = 0;
692 size_t tag_length = 16;
Jaeden Amero884738a2019-08-16 17:58:31 +0100693 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
694 psa_key_handle_t handle;
695
696 printf("Authenticate encrypt...\t");
697 fflush(stdout);
698
699 /* Initialize PSA Crypto */
700 status = psa_crypto_init();
701 if (status != PSA_SUCCESS) {
702 printf("Failed to initialize PSA Crypto\n");
703 return;
704 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200705
706 output_size = sizeof(input_data) + tag_length;
Jaeden Amero884738a2019-08-16 17:58:31 +0100707 output_data = (uint8_t *)malloc(output_size);
708 if (!output_data) {
709 printf("Out of memory\n");
710 return;
711 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200712
Jaeden Amero884738a2019-08-16 17:58:31 +0100713 /* Import a key */
714 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
715 psa_set_key_algorithm(&attributes, PSA_ALG_CCM);
716 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
717 psa_set_key_bits(&attributes, 128);
718 status = psa_import_key(&attributes, key, sizeof(key), &handle);
719 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200720
Jaeden Amero884738a2019-08-16 17:58:31 +0100721 /* Authenticate and encrypt */
722 status = psa_aead_encrypt(handle, PSA_ALG_CCM,
mohammad160387a7eeb2018-11-01 11:25:49 +0200723 nonce, sizeof(nonce),
724 additional_data, sizeof(additional_data),
725 input_data, sizeof(input_data),
726 output_data, output_size,
727 &output_length);
Jaeden Amero884738a2019-08-16 17:58:31 +0100728 if (status != PSA_SUCCESS) {
729 printf("Failed to authenticate and encrypt\n");
730 return;
731 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200732
Jaeden Amero884738a2019-08-16 17:58:31 +0100733 printf("Authenticated and encrypted\n");
734
735 /* Clean up */
736 free(output_data);
737
738 /* Destroy the key */
739 psa_destroy_key(handle);
740
mohammad160387a7eeb2018-11-01 11:25:49 +0200741 mbedtls_psa_crypto_free();
742```
743
Guy Wildc03c0fc2019-09-03 13:18:04 +0300744This example shows how to authenticate and decrypt a message:
mohammad160387a7eeb2018-11-01 11:25:49 +0200745
746```C
mohammad160387a7eeb2018-11-01 11:25:49 +0200747 psa_status_t status;
Jaeden Amero884738a2019-08-16 17:58:31 +0100748 static const uint8_t key[] = {
mohammad160387a7eeb2018-11-01 11:25:49 +0200749 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
Jaeden Amero884738a2019-08-16 17:58:31 +0100750 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF };
751 static const uint8_t nonce[] = {
752 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
753 0x08, 0x09, 0x0A, 0x0B };
754 static const uint8_t additional_data[] = {
755 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25,
756 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 };
757 static const uint8_t input_data[] = {
758 0x20, 0x30, 0xE0, 0x36, 0xED, 0x09, 0xA0, 0x45, 0xAF, 0x3C, 0xBA, 0xEE,
759 0x0F, 0xC8, 0x48, 0xAF, 0xCD, 0x89, 0x54, 0xF4, 0xF6, 0x3F, 0x28, 0x9A,
760 0xA1, 0xDD, 0xB2, 0xB8, 0x09, 0xCD, 0x7C, 0xE1, 0x46, 0xE9, 0x98 };
761 uint8_t *output_data = NULL;
mohammad160387a7eeb2018-11-01 11:25:49 +0200762 size_t output_size = 0;
763 size_t output_length = 0;
Jaeden Amero884738a2019-08-16 17:58:31 +0100764 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
765 psa_key_handle_t handle;
766
767 printf("Authenticate decrypt...\t");
768 fflush(stdout);
769
770 /* Initialize PSA Crypto */
771 status = psa_crypto_init();
772 if (status != PSA_SUCCESS) {
773 printf("Failed to initialize PSA Crypto\n");
774 return;
775 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200776
777 output_size = sizeof(input_data);
Jaeden Amero884738a2019-08-16 17:58:31 +0100778 output_data = (uint8_t *)malloc(output_size);
779 if (!output_data) {
780 printf("Out of memory\n");
781 return;
782 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200783
Jaeden Amero884738a2019-08-16 17:58:31 +0100784 /* Import a key */
785 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
786 psa_set_key_algorithm(&attributes, PSA_ALG_CCM);
787 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
788 psa_set_key_bits(&attributes, 128);
789 status = psa_import_key(&attributes, key, sizeof(key), &handle);
790 if (status != PSA_SUCCESS) {
791 printf("Failed to import a key\n");
792 return;
793 }
794 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200795
Jaeden Amero884738a2019-08-16 17:58:31 +0100796 /* Authenticate and decrypt */
797 status = psa_aead_decrypt(handle, PSA_ALG_CCM,
mohammad160387a7eeb2018-11-01 11:25:49 +0200798 nonce, sizeof(nonce),
799 additional_data, sizeof(additional_data),
800 input_data, sizeof(input_data),
801 output_data, output_size,
802 &output_length);
Jaeden Amero884738a2019-08-16 17:58:31 +0100803 if (status != PSA_SUCCESS) {
804 printf("Failed to authenticate and decrypt %ld\n", status);
805 return;
806 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200807
Jaeden Amero884738a2019-08-16 17:58:31 +0100808 printf("Authenticated and decrypted\n");
809
810 /* Clean up */
811 free(output_data);
812
813 /* Destroy the key */
814 psa_destroy_key(handle);
815
mohammad160387a7eeb2018-11-01 11:25:49 +0200816 mbedtls_psa_crypto_free();
817```
818
819### Generating and exporting keys
820
821Mbed Crypto provides a simple way to generate a key or key pair.
822
Guy Wildc03c0fc2019-09-03 13:18:04 +0300823**Prerequisites to using key generation and export APIs:**
824* Initialize the library with a successful call to `psa_crypto_init()`.
mohammad160387a7eeb2018-11-01 11:25:49 +0200825
Guy Wildc03c0fc2019-09-03 13:18:04 +0300826**To generate an ECDSA key:**
Jaeden Amero884738a2019-08-16 17:58:31 +01008271. Set the desired key attributes for key generation by calling
828 `psa_set_key_algorithm()` with the chosen ECDSA algorithm (such as
Guy Wildc03c0fc2019-09-03 13:18:04 +0300829 `PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)`). Do not set
Guy Wild802b19f2019-09-03 16:40:44 +0300830 `PSA_KEY_USAGE_EXPORT`; we only want to export the public key, not the key
Jaeden Amero884738a2019-08-16 17:58:31 +0100831 pair (or private key).
8321. Generate a key by calling `psa_generate_key()`.
Guy Wildc03c0fc2019-09-03 13:18:04 +03008331. Export the generated public key by calling `psa_export_public_key()`:
mohammad160387a7eeb2018-11-01 11:25:49 +0200834```C
Jaeden Amero884738a2019-08-16 17:58:31 +0100835 enum {
836 key_bits = 256,
837 };
838 psa_status_t status;
mohammad160387a7eeb2018-11-01 11:25:49 +0200839 size_t exported_length = 0;
Jaeden Amero884738a2019-08-16 17:58:31 +0100840 static uint8_t exported[PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits)];
841 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
842 psa_key_handle_t handle;
mohammad160387a7eeb2018-11-01 11:25:49 +0200843
Jaeden Amero884738a2019-08-16 17:58:31 +0100844 printf("Generate a key pair...\t");
845 fflush(stdout);
mohammad160387a7eeb2018-11-01 11:25:49 +0200846
Jaeden Amero884738a2019-08-16 17:58:31 +0100847 /* Initialize PSA Crypto */
848 status = psa_crypto_init();
849 if (status != PSA_SUCCESS) {
850 printf("Failed to initialize PSA Crypto\n");
851 return;
852 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200853
854 /* Generate a key */
Jaeden Amero884738a2019-08-16 17:58:31 +0100855 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN);
856 psa_set_key_algorithm(&attributes,
857 PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
858 psa_set_key_type(&attributes,
859 PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1));
860 psa_set_key_bits(&attributes, key_bits);
861 status = psa_generate_key(&attributes, &handle);
862 if (status != PSA_SUCCESS) {
863 printf("Failed to generate key\n");
864 return;
865 }
866 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200867
Jaeden Amero884738a2019-08-16 17:58:31 +0100868 status = psa_export_public_key(handle, exported, sizeof(exported),
869 &exported_length);
870 if (status != PSA_SUCCESS) {
871 printf("Failed to export public key %ld\n", status);
872 return;
873 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200874
Jaeden Amero884738a2019-08-16 17:58:31 +0100875 printf("Exported a public key\n");
876
877 /* Destroy the key */
878 psa_destroy_key(handle);
879
mohammad160387a7eeb2018-11-01 11:25:49 +0200880 mbedtls_psa_crypto_free();
881```
882
Guy Wild802b19f2019-09-03 16:40:44 +0300883### More about the Mbed Crypto API
mohammad160387a7eeb2018-11-01 11:25:49 +0200884
Guy Wildc03c0fc2019-09-03 13:18:04 +0300885For 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).