blob: 236c1a26c3676c1f84c32031dc5290adfe003d2f [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,
Guy Wild5b1347a2019-09-05 09:46:31 +0300130 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 Wild33d421d2019-09-04 09:16:14 +03001911. Initialize the operation structure to zero or to `PSA_CIPHER_OPERATION_INIT`.
1921. Call `psa_cipher_encrypt_setup()` to specify the algorithm and the key to be used.
Guy Wild94113db2019-09-04 09:56:51 +03001931. 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.
Guy Wild2a9e9f72019-09-04 13:45:54 +03001941. 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.
Guy Wildc03c0fc2019-09-03 13:18:04 +03001951. Call `psa_cipher_finish()` to end the operation and output the encrypted message.
mohammad160387a7eeb2018-11-01 11:25:49 +0200196
Guy Wild2a9e9f72019-09-04 13:45:54 +0300197This 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):
mohammad160387a7eeb2018-11-01 11:25:49 +0200198```c
Jaeden Amero884738a2019-08-16 17:58:31 +0100199 enum {
200 block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES),
201 };
202 psa_status_t status;
203 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200204 psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING;
Jaeden Amero884738a2019-08-16 17:58:31 +0100205 uint8_t plaintext[block_size] = SOME_PLAINTEXT;
206 uint8_t iv[block_size];
mohammad160387a7eeb2018-11-01 11:25:49 +0200207 size_t iv_len;
Jaeden Amero884738a2019-08-16 17:58:31 +0100208 uint8_t key[] = AES_KEY;
209 uint8_t output[block_size];
mohammad160387a7eeb2018-11-01 11:25:49 +0200210 size_t output_len;
Jaeden Amero884738a2019-08-16 17:58:31 +0100211 psa_key_handle_t handle;
212 psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200213
Jaeden Amero884738a2019-08-16 17:58:31 +0100214 printf("Encrypt with cipher...\t");
215 fflush(stdout);
mohammad160387a7eeb2018-11-01 11:25:49 +0200216
Jaeden Amero884738a2019-08-16 17:58:31 +0100217 /* Initialize PSA Crypto */
218 status = psa_crypto_init();
219 if (status != PSA_SUCCESS)
220 {
221 printf("Failed to initialize PSA Crypto\n");
222 return;
223 }
224
225 /* Import a key */
226 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
227 psa_set_key_algorithm(&attributes, alg);
228 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
229 psa_set_key_bits(&attributes, 128);
230 status = psa_import_key(&attributes, key, sizeof(key), &handle);
231 if (status != PSA_SUCCESS) {
232 printf("Failed to import a key\n");
233 return;
234 }
235 psa_reset_key_attributes(&attributes);
236
237 /* Encrypt the plaintext */
238 status = psa_cipher_encrypt_setup(&operation, handle, alg);
239 if (status != PSA_SUCCESS) {
240 printf("Failed to begin cipher operation\n");
241 return;
242 }
243 status = psa_cipher_generate_iv(&operation, iv, sizeof(iv), &iv_len);
244 if (status != PSA_SUCCESS) {
245 printf("Failed to generate IV\n");
246 return;
247 }
248 status = psa_cipher_update(&operation, plaintext, sizeof(plaintext),
249 output, sizeof(output), &output_len);
250 if (status != PSA_SUCCESS) {
251 printf("Failed to update cipher operation\n");
252 return;
253 }
254 status = psa_cipher_finish(&operation, output + output_len,
255 sizeof(output) - output_len, &output_len);
256 if (status != PSA_SUCCESS) {
257 printf("Failed to finish cipher operation\n");
258 return;
259 }
260 printf("Encrypted plaintext\n");
261
mohammad160387a7eeb2018-11-01 11:25:49 +0200262 /* Clean up cipher operation context */
263 psa_cipher_abort(&operation);
Jaeden Amero884738a2019-08-16 17:58:31 +0100264
265 /* Destroy the key */
266 psa_destroy_key(handle);
267
268 mbedtls_psa_crypto_free();
mohammad160387a7eeb2018-11-01 11:25:49 +0200269```
270
Guy Wildc03c0fc2019-09-03 13:18:04 +0300271**To decrypt a message with a symmetric cipher:**
mohammad160387a7eeb2018-11-01 11:25:49 +02002721. Allocate an operation (`psa_cipher_operation_t`) structure to pass to the cipher functions.
Guy Wild2a9e9f72019-09-04 13:45:54 +03002731. Initialize the operation structure to zero or to `PSA_CIPHER_OPERATION_INIT`.
2741. Call `psa_cipher_decrypt_setup()` to specify the algorithm and the key to be used.
Guy Wildc03c0fc2019-09-03 13:18:04 +03002751. Call `psa_cipher_set_iv()` with the IV for the decryption.
Guy Wild2a9e9f72019-09-04 13:45:54 +03002761. 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.
Guy Wildc03c0fc2019-09-03 13:18:04 +03002771. Call `psa_cipher_finish()` to end the operation and output the decrypted message.
mohammad160387a7eeb2018-11-01 11:25:49 +0200278
Guy Wildc03c0fc2019-09-03 13:18:04 +0300279This example shows how to decrypt encrypted data using an AES key in CBC mode with no padding
mohammad160387a7eeb2018-11-01 11:25:49 +0200280(assuming all prerequisites have been fulfilled):
281```c
Jaeden Amero884738a2019-08-16 17:58:31 +0100282 enum {
283 block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES),
284 };
285 psa_status_t status;
286 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200287 psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING;
Jaeden Amero884738a2019-08-16 17:58:31 +0100288 psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
289 uint8_t ciphertext[block_size] = SOME_CIPHERTEXT;
290 uint8_t iv[block_size] = ENCRYPTED_WITH_IV;
291 uint8_t key[] = AES_KEY;
292 uint8_t output[block_size];
mohammad160387a7eeb2018-11-01 11:25:49 +0200293 size_t output_len;
Jaeden Amero884738a2019-08-16 17:58:31 +0100294 psa_key_handle_t handle;
mohammad160387a7eeb2018-11-01 11:25:49 +0200295
Jaeden Amero884738a2019-08-16 17:58:31 +0100296 printf("Decrypt with cipher...\t");
297 fflush(stdout);
mohammad160387a7eeb2018-11-01 11:25:49 +0200298
Jaeden Amero884738a2019-08-16 17:58:31 +0100299 /* Initialize PSA Crypto */
300 status = psa_crypto_init();
301 if (status != PSA_SUCCESS)
302 {
303 printf("Failed to initialize PSA Crypto\n");
304 return;
305 }
306
307 /* Import a key */
308 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
309 psa_set_key_algorithm(&attributes, alg);
310 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
311 psa_set_key_bits(&attributes, 128);
312 status = psa_import_key(&attributes, key, sizeof(key), &handle);
313 if (status != PSA_SUCCESS) {
314 printf("Failed to import a key\n");
315 return;
316 }
317 psa_reset_key_attributes(&attributes);
318
319 /* Decrypt the ciphertext */
320 status = psa_cipher_decrypt_setup(&operation, handle, alg);
321 if (status != PSA_SUCCESS) {
322 printf("Failed to begin cipher operation\n");
323 return;
324 }
325 status = psa_cipher_set_iv(&operation, iv, sizeof(iv));
326 if (status != PSA_SUCCESS) {
327 printf("Failed to set IV\n");
328 return;
329 }
330 status = psa_cipher_update(&operation, ciphertext, sizeof(ciphertext),
331 output, sizeof(output), &output_len);
332 if (status != PSA_SUCCESS) {
333 printf("Failed to update cipher operation\n");
334 return;
335 }
336 status = psa_cipher_finish(&operation, output + output_len,
337 sizeof(output) - output_len, &output_len);
338 if (status != PSA_SUCCESS) {
339 printf("Failed to finish cipher operation\n");
340 return;
341 }
342 printf("Decrypted ciphertext\n");
343
mohammad160387a7eeb2018-11-01 11:25:49 +0200344 /* Clean up cipher operation context */
345 psa_cipher_abort(&operation);
Jaeden Amero884738a2019-08-16 17:58:31 +0100346
347 /* Destroy the key */
348 psa_destroy_key(handle);
349
350 mbedtls_psa_crypto_free();
mohammad160387a7eeb2018-11-01 11:25:49 +0200351```
352
353#### Handling cipher operation contexts
354
Guy Wildc03c0fc2019-09-03 13:18:04 +0300355After 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 +0200356
Guy Wildc03c0fc2019-09-03 13:18:04 +0300357The call to `psa_cipher_abort()` frees any resources associated with the operation, except for the operation structure itself.
mohammad160387a7eeb2018-11-01 11:25:49 +0200358
Guy Wildc03c0fc2019-09-03 13:18:04 +0300359Mbed Crypto implicitly calls `psa_cipher_abort()` when:
360* A call to `psa_cipher_generate_iv()`, `psa_cipher_set_iv()` or `psa_cipher_update()` fails (returning any status other than `PSA_SUCCESS`).
361* A call to `psa_cipher_finish()` succeeds or fails.
mohammad160387a7eeb2018-11-01 11:25:49 +0200362
Guy Wildc03c0fc2019-09-03 13:18:04 +0300363After 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 +0200364
Guy Wildc03c0fc2019-09-03 13:18:04 +0300365You 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()`).
366
367Making 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 +0200368
369### Hashing a message
370
Jaeden Amero884738a2019-08-16 17:58:31 +0100371Mbed Crypto lets you compute and verify hashes using various hashing
372algorithms.
mohammad160387a7eeb2018-11-01 11:25:49 +0200373
Guy Wildc03c0fc2019-09-03 13:18:04 +0300374**Prerequisites to working with the hash APIs:**
375* Initialize the library with a successful call to `psa_crypto_init()`.
mohammad160387a7eeb2018-11-01 11:25:49 +0200376
Guy Wildc03c0fc2019-09-03 13:18:04 +0300377**To calculate a hash:**
mohammad160387a7eeb2018-11-01 11:25:49 +02003781. Allocate an operation structure (`psa_hash_operation_t`) to pass to the hash functions.
Guy Wildeefc5172019-09-04 09:16:53 +03003791. Initialize the operation structure to zero or to `PSA_HASH_OPERATION_INIT`.
3801. Call `psa_hash_setup()` to specify the hash algorithm.
Guy Wild2a9e9f72019-09-04 13:45:54 +03003811. 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.
Guy Wildc03c0fc2019-09-03 13:18:04 +03003821. 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 +0200383
Guy Wild2a9e9f72019-09-04 13:45:54 +0300384This example shows how to calculate the SHA-256 hash of a message:
mohammad160387a7eeb2018-11-01 11:25:49 +0200385```c
Jaeden Amero884738a2019-08-16 17:58:31 +0100386 psa_status_t status;
mohammad160387a7eeb2018-11-01 11:25:49 +0200387 psa_algorithm_t alg = PSA_ALG_SHA_256;
Jaeden Amero884738a2019-08-16 17:58:31 +0100388 psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200389 unsigned char input[] = { 'a', 'b', 'c' };
390 unsigned char actual_hash[PSA_HASH_MAX_SIZE];
391 size_t actual_hash_len;
392
Jaeden Amero884738a2019-08-16 17:58:31 +0100393 printf("Hash a message...\t");
394 fflush(stdout);
395
396 /* Initialize PSA Crypto */
397 status = psa_crypto_init();
398 if (status != PSA_SUCCESS) {
399 printf("Failed to initialize PSA Crypto\n");
400 return;
401 }
402
mohammad160387a7eeb2018-11-01 11:25:49 +0200403 /* Compute hash of message */
Jaeden Amero884738a2019-08-16 17:58:31 +0100404 status = psa_hash_setup(&operation, alg);
405 if (status != PSA_SUCCESS) {
406 printf("Failed to begin hash operation\n");
407 return;
408 }
409 status = psa_hash_update(&operation, input, sizeof(input));
410 if (status != PSA_SUCCESS) {
411 printf("Failed to update hash operation\n");
412 return;
413 }
414 status = psa_hash_finish(&operation, actual_hash, sizeof(actual_hash),
415 &actual_hash_len);
416 if (status != PSA_SUCCESS) {
417 printf("Failed to finish hash operation\n");
418 return;
419 }
420
421 printf("Hashed a message\n");
mohammad160387a7eeb2018-11-01 11:25:49 +0200422
423 /* Clean up hash operation context */
424 psa_hash_abort(&operation);
Jaeden Amero884738a2019-08-16 17:58:31 +0100425
426 mbedtls_psa_crypto_free();
mohammad160387a7eeb2018-11-01 11:25:49 +0200427```
428
Guy Wild2a9e9f72019-09-04 13:45:54 +0300429This example shows how to verify the SHA-256 hash of a message:
mohammad160387a7eeb2018-11-01 11:25:49 +0200430```c
Jaeden Amero884738a2019-08-16 17:58:31 +0100431 psa_status_t status;
mohammad160387a7eeb2018-11-01 11:25:49 +0200432 psa_algorithm_t alg = PSA_ALG_SHA_256;
Jaeden Amero884738a2019-08-16 17:58:31 +0100433 psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200434 unsigned char input[] = { 'a', 'b', 'c' };
435 unsigned char expected_hash[] = {
436 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde,
437 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
438 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad
439 };
440 size_t expected_hash_len = PSA_HASH_SIZE(alg);
441
Jaeden Amero884738a2019-08-16 17:58:31 +0100442 printf("Verify a hash...\t");
443 fflush(stdout);
444
445 /* Initialize PSA Crypto */
446 status = psa_crypto_init();
447 if (status != PSA_SUCCESS) {
448 printf("Failed to initialize PSA Crypto\n");
449 return;
450 }
451
mohammad160387a7eeb2018-11-01 11:25:49 +0200452 /* Verify message hash */
Jaeden Amero884738a2019-08-16 17:58:31 +0100453 status = psa_hash_setup(&operation, alg);
454 if (status != PSA_SUCCESS) {
455 printf("Failed to begin hash operation\n");
456 return;
457 }
458 status = psa_hash_update(&operation, input, sizeof(input));
459 if (status != PSA_SUCCESS) {
460 printf("Failed to update hash operation\n");
461 return;
462 }
463 status = psa_hash_verify(&operation, expected_hash, expected_hash_len);
464 if (status != PSA_SUCCESS) {
465 printf("Failed to verify hash\n");
466 return;
467 }
468
469 printf("Verified a hash\n");
470
471 /* Clean up hash operation context */
472 psa_hash_abort(&operation);
473
474 mbedtls_psa_crypto_free();
mohammad160387a7eeb2018-11-01 11:25:49 +0200475```
476
477The API provides the macro `PSA_HASH_SIZE`, which returns the expected hash length (in bytes) for the specified algorithm.
478
479#### Handling hash operation contexts
480
Guy Wild2a9e9f72019-09-04 13:45:54 +0300481After 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.
mohammad160387a7eeb2018-11-01 11:25:49 +0200482
Guy Wildc03c0fc2019-09-03 13:18:04 +0300483Mbed Crypto implicitly calls `psa_hash_abort()` when:
4841. A call to `psa_hash_update()` fails (returning any status other than `PSA_SUCCESS`).
4851. A call to `psa_hash_finish()` succeeds or fails.
4861. A call to `psa_hash_verify()` succeeds or fails.
mohammad160387a7eeb2018-11-01 11:25:49 +0200487
Guy Wildc03c0fc2019-09-03 13:18:04 +0300488After 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 +0200489
Guy Wildc03c0fc2019-09-03 13:18:04 +0300490You 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 +0200491
Guy Wildc03c0fc2019-09-03 13:18:04 +0300492Making 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 +0200493
494### Generating a random value
495
Guy Wildc03c0fc2019-09-03 13:18:04 +0300496Mbed Crypto can generate random data.
mohammad160387a7eeb2018-11-01 11:25:49 +0200497
Guy Wild802b19f2019-09-03 16:40:44 +0300498**Prerequisites to generating random data:**
Jaeden Amero884738a2019-08-16 17:58:31 +0100499* Initialize the library with a successful call to `psa_crypto_init()`.
mohammad160387a7eeb2018-11-01 11:25:49 +0200500
Guy Wild802b19f2019-09-03 16:40:44 +0300501<span class="notes">**Note:** To generate a random key, use `psa_generate_key()` instead of `psa_generate_random()`.</span>
502
503This example shows how to generate ten bytes of random data by calling `psa_generate_random()`:
mohammad160387a7eeb2018-11-01 11:25:49 +0200504```C
505 psa_status_t status;
506 uint8_t random[10] = { 0 };
mohammad160387a7eeb2018-11-01 11:25:49 +0200507
Jaeden Amero884738a2019-08-16 17:58:31 +0100508 printf("Generate random...\t");
509 fflush(stdout);
510
511 /* Initialize PSA Crypto */
512 status = psa_crypto_init();
513 if (status != PSA_SUCCESS) {
514 printf("Failed to initialize PSA Crypto\n");
515 return;
516 }
517
518 status = psa_generate_random(random, sizeof(random));
519 if (status != PSA_SUCCESS) {
520 printf("Failed to generate a random value\n");
521 return;
522 }
523
524 printf("Generated random data\n");
525
526 /* Clean up */
mohammad160387a7eeb2018-11-01 11:25:49 +0200527 mbedtls_psa_crypto_free();
528```
529
530### Deriving a new key from an existing key
531
Jaeden Amero884738a2019-08-16 17:58:31 +0100532Mbed Crypto provides a key derivation API that lets you derive new keys from
533existing ones. The key derivation API has functions to take inputs, including
534other keys and data, and functions to generate outputs, such as new keys or
Guy Wildc03c0fc2019-09-03 13:18:04 +0300535other data.
mohammad160387a7eeb2018-11-01 11:25:49 +0200536
Guy Wildc03c0fc2019-09-03 13:18:04 +0300537You must first initialize and set up a key derivation context,
538provided 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.
539
540See the documentation for the particular algorithm (such as HKDF or the TLS1.2 PRF) for
541information about which inputs to pass when, and when you can obtain which outputs.
542
543**Prerequisites to working with the key derivation APIs:**
544* Initialize the library with a successful call to `psa_crypto_init()`.
Jaeden Amero884738a2019-08-16 17:58:31 +0100545* Use a key with the appropriate attributes set:
546 * Usage flags set for key derivation (`PSA_KEY_USAGE_DERIVE`)
547 * Key type set to `PSA_KEY_TYPE_DERIVE`.
548 * Algorithm set to a key derivation algorithm
Guy Wild2a9e9f72019-09-04 13:45:54 +0300549 (for example, `PSA_ALG_HKDF(PSA_ALG_SHA_256)`).
mohammad160387a7eeb2018-11-01 11:25:49 +0200550
Guy Wildc03c0fc2019-09-03 13:18:04 +0300551**To derive a new AES-CTR 128-bit encryption key into a given key slot using HKDF
Guy Wild2a9e9f72019-09-04 13:45:54 +0300552with a given key, salt and info:**
Guy Wildc03c0fc2019-09-03 13:18:04 +0300553
5541. Set up the key derivation context using the `psa_key_derivation_setup()`
Jaeden Amero884738a2019-08-16 17:58:31 +0100555function, specifying the derivation algorithm `PSA_ALG_HKDF(PSA_ALG_SHA_256)`.
Guy Wild29008112019-09-05 11:38:14 +03005561. Provide an optional salt with `psa_key_derivation_input_bytes()`.
5571. Provide info with `psa_key_derivation_input_bytes()`.
5581. Provide a secret with `psa_key_derivation_input_key()`, referencing a key that
Jaeden Amero884738a2019-08-16 17:58:31 +0100559 can be used for key derivation.
5601. Set the key attributes desired for the new derived key. We'll set
Guy Wild0058ab62019-09-04 09:17:54 +0300561 the `PSA_KEY_USAGE_ENCRYPT` usage flag and the `PSA_ALG_CTR` algorithm for this
Jaeden Amero884738a2019-08-16 17:58:31 +0100562 example.
5631. Derive the key by calling `psa_key_derivation_output_key()`.
5641. Clean up the key derivation context.
mohammad160387a7eeb2018-11-01 11:25:49 +0200565
Guy Wildc03c0fc2019-09-03 13:18:04 +0300566At this point, the derived key slot holds a new 128-bit AES-CTR encryption key
Guy Wildce560772019-09-05 11:35:16 +0300567derived from the key, salt and info provided:
mohammad160387a7eeb2018-11-01 11:25:49 +0200568```C
Jaeden Amero884738a2019-08-16 17:58:31 +0100569 psa_status_t status;
570 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
571 static const unsigned char key[] = {
mohammad160387a7eeb2018-11-01 11:25:49 +0200572 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
573 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
574 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
575 0x0b };
Jaeden Amero884738a2019-08-16 17:58:31 +0100576 static const unsigned char salt[] = {
577 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
578 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c };
579 static const unsigned char info[] = {
580 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
581 0xf7, 0xf8, 0xf9 };
mohammad160387a7eeb2018-11-01 11:25:49 +0200582 psa_algorithm_t alg = PSA_ALG_HKDF(PSA_ALG_SHA_256);
Jaeden Amero884738a2019-08-16 17:58:31 +0100583 psa_key_derivation_operation_t operation =
584 PSA_KEY_DERIVATION_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200585 size_t derived_bits = 128;
586 size_t capacity = PSA_BITS_TO_BYTES(derived_bits);
Jaeden Amero884738a2019-08-16 17:58:31 +0100587 psa_key_handle_t base_key;
588 psa_key_handle_t derived_key;
mohammad160387a7eeb2018-11-01 11:25:49 +0200589
Jaeden Amero884738a2019-08-16 17:58:31 +0100590 printf("Derive a key (HKDF)...\t");
591 fflush(stdout);
592
593 /* Initialize PSA Crypto */
mohammad160387a7eeb2018-11-01 11:25:49 +0200594 status = psa_crypto_init();
Jaeden Amero884738a2019-08-16 17:58:31 +0100595 if (status != PSA_SUCCESS) {
596 printf("Failed to initialize PSA Crypto\n");
597 return;
598 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200599
Jaeden Amero884738a2019-08-16 17:58:31 +0100600 /* Import a key for use in key derivation. If such a key has already been
601 * generated or imported, you can skip this part. */
602 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
603 psa_set_key_algorithm(&attributes, alg);
604 psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE);
605 status = psa_import_key(&attributes, key, sizeof(key), &base_key);
606 if (status != PSA_SUCCESS) {
607 printf("Failed to import a key\n");
608 return;
609 }
610 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200611
Jaeden Amero884738a2019-08-16 17:58:31 +0100612 /* Derive a key */
613 status = psa_key_derivation_setup(&operation, alg);
614 if (status != PSA_SUCCESS) {
615 printf("Failed to begin key derivation\n");
616 return;
617 }
618 status = psa_key_derivation_set_capacity(&operation, capacity);
619 if (status != PSA_SUCCESS) {
620 printf("Failed to set capacity\n");
621 return;
622 }
623 status = psa_key_derivation_input_bytes(&operation,
624 PSA_KEY_DERIVATION_INPUT_SALT,
625 salt, sizeof(salt));
626 if (status != PSA_SUCCESS) {
627 printf("Failed to input salt (extract)\n");
628 return;
629 }
630 status = psa_key_derivation_input_key(&operation,
631 PSA_KEY_DERIVATION_INPUT_SECRET,
632 base_key);
633 if (status != PSA_SUCCESS) {
634 printf("Failed to input key (extract)\n");
635 return;
636 }
637 status = psa_key_derivation_input_bytes(&operation,
638 PSA_KEY_DERIVATION_INPUT_INFO,
639 info, sizeof(info));
640 if (status != PSA_SUCCESS) {
641 printf("Failed to input info (expand)\n");
642 return;
643 }
644 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
645 psa_set_key_algorithm(&attributes, PSA_ALG_CTR);
646 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
647 psa_set_key_bits(&attributes, 128);
648 status = psa_key_derivation_output_key(&attributes, &operation,
649 &derived_key);
650 if (status != PSA_SUCCESS) {
651 printf("Failed to derive key\n");
652 return;
653 }
654 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200655
Jaeden Amero884738a2019-08-16 17:58:31 +0100656 printf("Derived key\n");
mohammad160387a7eeb2018-11-01 11:25:49 +0200657
Jaeden Amero884738a2019-08-16 17:58:31 +0100658 /* Clean up key derivation operation */
659 psa_key_derivation_abort(&operation);
mohammad160387a7eeb2018-11-01 11:25:49 +0200660
Jaeden Amero884738a2019-08-16 17:58:31 +0100661 /* Destroy the keys */
662 psa_destroy_key(derived_key);
663 psa_destroy_key(base_key);
mohammad160387a7eeb2018-11-01 11:25:49 +0200664
mohammad160387a7eeb2018-11-01 11:25:49 +0200665 mbedtls_psa_crypto_free();
666```
667
668### Authenticating and encrypting or decrypting a message
669
Guy Wildc03c0fc2019-09-03 13:18:04 +0300670Mbed 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 +0200671
Guy Wildc03c0fc2019-09-03 13:18:04 +0300672**Prerequisites to working with the AEAD cipher APIs:**
673* Initialize the library with a successful call to `psa_crypto_init()`.
674* 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 +0200675
Guy Wildc03c0fc2019-09-03 13:18:04 +0300676This example shows how to authenticate and encrypt a message:
mohammad160387a7eeb2018-11-01 11:25:49 +0200677```C
mohammad160387a7eeb2018-11-01 11:25:49 +0200678 psa_status_t status;
Jaeden Amero884738a2019-08-16 17:58:31 +0100679 static const uint8_t key[] = {
680 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
681 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF };
682 static const uint8_t nonce[] = {
683 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
684 0x08, 0x09, 0x0A, 0x0B };
685 static const uint8_t additional_data[] = {
686 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25,
687 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 };
688 static const uint8_t input_data[] = {
689 0xB9, 0x6B, 0x49, 0xE2, 0x1D, 0x62, 0x17, 0x41,
690 0x63, 0x28, 0x75, 0xDB, 0x7F, 0x6C, 0x92, 0x43,
691 0xD2, 0xD7, 0xC2 };
692 uint8_t *output_data = NULL;
mohammad160387a7eeb2018-11-01 11:25:49 +0200693 size_t output_size = 0;
694 size_t output_length = 0;
695 size_t tag_length = 16;
Jaeden Amero884738a2019-08-16 17:58:31 +0100696 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
697 psa_key_handle_t handle;
698
699 printf("Authenticate encrypt...\t");
700 fflush(stdout);
701
702 /* Initialize PSA Crypto */
703 status = psa_crypto_init();
704 if (status != PSA_SUCCESS) {
705 printf("Failed to initialize PSA Crypto\n");
706 return;
707 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200708
709 output_size = sizeof(input_data) + tag_length;
Jaeden Amero884738a2019-08-16 17:58:31 +0100710 output_data = (uint8_t *)malloc(output_size);
711 if (!output_data) {
712 printf("Out of memory\n");
713 return;
714 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200715
Jaeden Amero884738a2019-08-16 17:58:31 +0100716 /* Import a key */
717 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
718 psa_set_key_algorithm(&attributes, PSA_ALG_CCM);
719 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
720 psa_set_key_bits(&attributes, 128);
721 status = psa_import_key(&attributes, key, sizeof(key), &handle);
722 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200723
Jaeden Amero884738a2019-08-16 17:58:31 +0100724 /* Authenticate and encrypt */
725 status = psa_aead_encrypt(handle, PSA_ALG_CCM,
mohammad160387a7eeb2018-11-01 11:25:49 +0200726 nonce, sizeof(nonce),
727 additional_data, sizeof(additional_data),
728 input_data, sizeof(input_data),
729 output_data, output_size,
730 &output_length);
Jaeden Amero884738a2019-08-16 17:58:31 +0100731 if (status != PSA_SUCCESS) {
732 printf("Failed to authenticate and encrypt\n");
733 return;
734 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200735
Jaeden Amero884738a2019-08-16 17:58:31 +0100736 printf("Authenticated and encrypted\n");
737
738 /* Clean up */
739 free(output_data);
740
741 /* Destroy the key */
742 psa_destroy_key(handle);
743
mohammad160387a7eeb2018-11-01 11:25:49 +0200744 mbedtls_psa_crypto_free();
745```
746
Guy Wildc03c0fc2019-09-03 13:18:04 +0300747This example shows how to authenticate and decrypt a message:
mohammad160387a7eeb2018-11-01 11:25:49 +0200748
749```C
mohammad160387a7eeb2018-11-01 11:25:49 +0200750 psa_status_t status;
Jaeden Amero884738a2019-08-16 17:58:31 +0100751 static const uint8_t key[] = {
mohammad160387a7eeb2018-11-01 11:25:49 +0200752 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
Jaeden Amero884738a2019-08-16 17:58:31 +0100753 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF };
754 static const uint8_t nonce[] = {
755 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
756 0x08, 0x09, 0x0A, 0x0B };
757 static const uint8_t additional_data[] = {
758 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25,
759 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 };
760 static const uint8_t input_data[] = {
761 0x20, 0x30, 0xE0, 0x36, 0xED, 0x09, 0xA0, 0x45, 0xAF, 0x3C, 0xBA, 0xEE,
762 0x0F, 0xC8, 0x48, 0xAF, 0xCD, 0x89, 0x54, 0xF4, 0xF6, 0x3F, 0x28, 0x9A,
763 0xA1, 0xDD, 0xB2, 0xB8, 0x09, 0xCD, 0x7C, 0xE1, 0x46, 0xE9, 0x98 };
764 uint8_t *output_data = NULL;
mohammad160387a7eeb2018-11-01 11:25:49 +0200765 size_t output_size = 0;
766 size_t output_length = 0;
Jaeden Amero884738a2019-08-16 17:58:31 +0100767 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
768 psa_key_handle_t handle;
769
770 printf("Authenticate decrypt...\t");
771 fflush(stdout);
772
773 /* Initialize PSA Crypto */
774 status = psa_crypto_init();
775 if (status != PSA_SUCCESS) {
776 printf("Failed to initialize PSA Crypto\n");
777 return;
778 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200779
780 output_size = sizeof(input_data);
Jaeden Amero884738a2019-08-16 17:58:31 +0100781 output_data = (uint8_t *)malloc(output_size);
782 if (!output_data) {
783 printf("Out of memory\n");
784 return;
785 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200786
Jaeden Amero884738a2019-08-16 17:58:31 +0100787 /* Import a key */
788 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
789 psa_set_key_algorithm(&attributes, PSA_ALG_CCM);
790 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
791 psa_set_key_bits(&attributes, 128);
792 status = psa_import_key(&attributes, key, sizeof(key), &handle);
793 if (status != PSA_SUCCESS) {
794 printf("Failed to import a key\n");
795 return;
796 }
797 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200798
Jaeden Amero884738a2019-08-16 17:58:31 +0100799 /* Authenticate and decrypt */
800 status = psa_aead_decrypt(handle, PSA_ALG_CCM,
mohammad160387a7eeb2018-11-01 11:25:49 +0200801 nonce, sizeof(nonce),
802 additional_data, sizeof(additional_data),
803 input_data, sizeof(input_data),
804 output_data, output_size,
805 &output_length);
Jaeden Amero884738a2019-08-16 17:58:31 +0100806 if (status != PSA_SUCCESS) {
807 printf("Failed to authenticate and decrypt %ld\n", status);
808 return;
809 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200810
Jaeden Amero884738a2019-08-16 17:58:31 +0100811 printf("Authenticated and decrypted\n");
812
813 /* Clean up */
814 free(output_data);
815
816 /* Destroy the key */
817 psa_destroy_key(handle);
818
mohammad160387a7eeb2018-11-01 11:25:49 +0200819 mbedtls_psa_crypto_free();
820```
821
822### Generating and exporting keys
823
824Mbed Crypto provides a simple way to generate a key or key pair.
825
Guy Wildc03c0fc2019-09-03 13:18:04 +0300826**Prerequisites to using key generation and export APIs:**
827* Initialize the library with a successful call to `psa_crypto_init()`.
mohammad160387a7eeb2018-11-01 11:25:49 +0200828
Guy Wildc03c0fc2019-09-03 13:18:04 +0300829**To generate an ECDSA key:**
Jaeden Amero884738a2019-08-16 17:58:31 +01008301. Set the desired key attributes for key generation by calling
831 `psa_set_key_algorithm()` with the chosen ECDSA algorithm (such as
Guy Wild94113db2019-09-04 09:56:51 +0300832 `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`.
Jaeden Amero884738a2019-08-16 17:58:31 +01008331. Generate a key by calling `psa_generate_key()`.
Guy Wildc03c0fc2019-09-03 13:18:04 +03008341. Export the generated public key by calling `psa_export_public_key()`:
mohammad160387a7eeb2018-11-01 11:25:49 +0200835```C
Jaeden Amero884738a2019-08-16 17:58:31 +0100836 enum {
837 key_bits = 256,
838 };
839 psa_status_t status;
mohammad160387a7eeb2018-11-01 11:25:49 +0200840 size_t exported_length = 0;
Jaeden Amero884738a2019-08-16 17:58:31 +0100841 static uint8_t exported[PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits)];
842 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
843 psa_key_handle_t handle;
mohammad160387a7eeb2018-11-01 11:25:49 +0200844
Jaeden Amero884738a2019-08-16 17:58:31 +0100845 printf("Generate a key pair...\t");
846 fflush(stdout);
mohammad160387a7eeb2018-11-01 11:25:49 +0200847
Jaeden Amero884738a2019-08-16 17:58:31 +0100848 /* Initialize PSA Crypto */
849 status = psa_crypto_init();
850 if (status != PSA_SUCCESS) {
851 printf("Failed to initialize PSA Crypto\n");
852 return;
853 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200854
855 /* Generate a key */
Jaeden Amero884738a2019-08-16 17:58:31 +0100856 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN);
857 psa_set_key_algorithm(&attributes,
858 PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
859 psa_set_key_type(&attributes,
860 PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1));
861 psa_set_key_bits(&attributes, key_bits);
862 status = psa_generate_key(&attributes, &handle);
863 if (status != PSA_SUCCESS) {
864 printf("Failed to generate key\n");
865 return;
866 }
867 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200868
Jaeden Amero884738a2019-08-16 17:58:31 +0100869 status = psa_export_public_key(handle, exported, sizeof(exported),
870 &exported_length);
871 if (status != PSA_SUCCESS) {
872 printf("Failed to export public key %ld\n", status);
873 return;
874 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200875
Jaeden Amero884738a2019-08-16 17:58:31 +0100876 printf("Exported a public key\n");
877
878 /* Destroy the key */
879 psa_destroy_key(handle);
880
mohammad160387a7eeb2018-11-01 11:25:49 +0200881 mbedtls_psa_crypto_free();
882```
883
Guy Wild2a9e9f72019-09-04 13:45:54 +0300884### More about the PSA Crypto API
mohammad160387a7eeb2018-11-01 11:25:49 +0200885
Guy Wild94113db2019-09-04 09:56:51 +0300886For more information about the PSA Crypto API, please see the [PSA Cryptography API Specification](https://armmbed.github.io/mbed-crypto/html/index.html).