blob: 4d380e0881d57f194651fefe64aab70af033c0b2 [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,
21security analyses, hardware and firmware architecture specifications, and an open source firmware reference implementation. PSA provides a recipe, based on industry best practice, that allows security to be consistently designed in, at both a hardware and firmware level. Part of the API provided by PSA is the cryptography interface, which provides access to a set of primitives.
22
23### Using Mbed Crypto
24
25* [Getting the Mbed Crypto library](#getting-the-mbed-crypto-library)
26* [Building the Mbed Crypto library](#building-the-mbed-crypto-library)
27* [Using the Mbed Crypto library](#using-the-mbed-crypto-library)
28* [Importing a key](#importing-a-key)
29* [Signing a message using RSA](#signing-a-message-using-RSA)
30* [Encrypting or decrypting using symmetric ciphers](#encrypting-or-decrypting-using-symmetric-ciphers)
31* [Hashing a message](#hashing-a-message)
32* [Deriving a new key from an existing key](#deriving-a-new-key-from-an-existing-key)
33* [Generating a random value](#generating-a-random-value)
34* [Authenticating and encrypting or decrypting a message](#authenticating-and-encrypting-or-decrypting-a-message)
35* [Generating and exporting keys](#generating-and-exporting-keys)
36* [More about the Mbed Crypto library](#more-about-the-mbed-crypto-library)
37
38### Getting the Mbed Crypto library
39
40Mbed Crypto releases are available in the [public Github repository]( https://github.com/ARMmbed/mbed-crypto).
41
42### Building the Mbed Crypto library
43
44You need the following tools to build the library with the provided makefiles:
45* GNU Make.
46* A C toolchain (compiler, linker, archiver).
47* Python 2 or Python 3 (either works) to generate the test code.
48* Perl to run the tests.
49
50If you have a C compiler such as GCC or Clang, just run `make` in the top-level directory to build the library, a set of unit tests and some sample programs.
51
52To select a different compiler, set the `CC` variable to name or path of the compiler and linker (default: `cc`) and set `AR` to a compatible archiver (default: `ar`), such as:
53```
54make CC=arm-linux-gnueabi-gcc AR=arm-linux-gnueabi-ar
55```
56The provided makefiles pass options to the compiler that assume a GCC-like command line syntax. To use a different compiler, you may need to pass different values for `CFLAGS`, `WARNINGS_CFLAGS` and `LDFLAGS`.
57
58To run the unit tests on the host machine, run `make test` from the top-level directory. If you are cross-compiling, copy the test executable from the `tests` directory to the target machine.
59
60### Using the Mbed Crypto library
61
62To use the Mbed Crypto APIs, call `psa_crypto_init()` before calling any other API. This initializes the library.
63
64### Importing a key
65
Jaeden Amero884738a2019-08-16 17:58:31 +010066To use a key for cryptography operations in Mbed Crypto, you need to first
67import it. Upon importing, you'll be given a handle to refer to the key for use
68with other function calls.
mohammad160387a7eeb2018-11-01 11:25:49 +020069
Jaeden Amero884738a2019-08-16 17:58:31 +010070Prerequisites for importing keys:
mohammad160387a7eeb2018-11-01 11:25:49 +020071* Initialize the library with a successful call to `psa_crypto_init`.
72
Jaeden Amero884738a2019-08-16 17:58:31 +010073Importing 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
115Mbed Crypto provides support for encrypting, decrypting, signing and verifying messages using public key signature algorithms (such as RSA or ECDSA).
116
Jaeden Amero884738a2019-08-16 17:58:31 +0100117Prerequisites for performing asymmetric signature operations:
mohammad160387a7eeb2018-11-01 11:25:49 +0200118* 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.
122 * Algorithm set to desired signature algorithm.
mohammad160387a7eeb2018-11-01 11:25:49 +0200123
Jaeden Amero884738a2019-08-16 17:58:31 +0100124To sign a given `hash` using RSA:
1251. Call `psa_asymmetric_sign()` and get the output buffer that contains the
126 signature:
mohammad160387a7eeb2018-11-01 11:25:49 +0200127```C
128 psa_status_t status;
Jaeden Amero884738a2019-08-16 17:58:31 +0100129 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
130 uint8_t key[] = RSA_KEY;
131 uint8_t hash[] = "INPUT_FOR_SIGN";
132 uint8_t signature[PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE] = {0};
mohammad160387a7eeb2018-11-01 11:25:49 +0200133 size_t signature_length;
Jaeden Amero884738a2019-08-16 17:58:31 +0100134 psa_key_handle_t handle;
mohammad160387a7eeb2018-11-01 11:25:49 +0200135
Jaeden Amero884738a2019-08-16 17:58:31 +0100136 printf("Sign a message...\t");
137 fflush(stdout);
138
139 /* Initialize PSA Crypto */
mohammad160387a7eeb2018-11-01 11:25:49 +0200140 status = psa_crypto_init();
Jaeden Amero884738a2019-08-16 17:58:31 +0100141 if (status != PSA_SUCCESS) {
142 printf("Failed to initialize PSA Crypto\n");
143 return;
144 }
145
146 /* Set key attributes */
147 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN);
148 psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_SIGN_RAW);
149 psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
150 psa_set_key_bits(&attributes, 1024);
mohammad160387a7eeb2018-11-01 11:25:49 +0200151
152 /* Import the key */
Jaeden Amero884738a2019-08-16 17:58:31 +0100153 status = psa_import_key(&attributes, key, sizeof(key), &handle);
154 if (status != PSA_SUCCESS) {
155 printf("Failed to import key\n");
156 return;
157 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200158
Jaeden Amero884738a2019-08-16 17:58:31 +0100159 /* Sign message using the key */
160 status = psa_asymmetric_sign(handle, PSA_ALG_RSA_PKCS1V15_SIGN_RAW,
161 hash, sizeof(hash),
mohammad160387a7eeb2018-11-01 11:25:49 +0200162 signature, sizeof(signature),
163 &signature_length);
Jaeden Amero884738a2019-08-16 17:58:31 +0100164 if (status != PSA_SUCCESS) {
165 printf("Failed to sign\n");
166 return;
167 }
168
169 printf("Signed a message\n");
170
171 /* Free the attributes */
172 psa_reset_key_attributes(&attributes);
173
mohammad160387a7eeb2018-11-01 11:25:49 +0200174 /* Destroy the key */
Jaeden Amero884738a2019-08-16 17:58:31 +0100175 psa_destroy_key(handle);
176
mohammad160387a7eeb2018-11-01 11:25:49 +0200177 mbedtls_psa_crypto_free();
178```
179
Jaeden Amero884738a2019-08-16 17:58:31 +0100180### Using symmetric ciphers
mohammad160387a7eeb2018-11-01 11:25:49 +0200181
182Mbed Crypto provides support for encrypting and decrypting messages using various symmetric cipher algorithms (both block and stream ciphers).
183
184Prerequisites to working with the symmetric cipher API:
185* Initialize the library with a successful call to `psa_crypto_init`.
186* Configure the key policy accordingly (`PSA_KEY_USAGE_ENCRYPT` to allow encryption or `PSA_KEY_USAGE_DECRYPT` to allow decryption).
187* Have a valid key in the key slot.
188
189Encrypting a message with a symmetric cipher:
1901. Allocate an operation (`psa_cipher_operation_t`) structure to pass to the cipher functions.
1911. 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 `psa_cipher_generate_iv`, unless you require a specific IV value.
1931. Call `psa_cipher_update` one or more times, passing either the whole or only a fragment of the message each time.
1941. Call `psa_cipher_finish` to end the operation and output the encrypted message.
195
Jaeden Amero884738a2019-08-16 17:58:31 +0100196Encrypting data using an AES key in cipher block chain (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
270Decrypting a message with a symmetric cipher:
2711. Allocate an operation (`psa_cipher_operation_t`) structure to pass to the cipher functions.
2721. 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.
2741. Call `psa_cipher_update` one or more times passing either the whole or only a fragment of the message each time.
2751. Call `psa_cipher_finish` to end the operation and output the decrypted message.
276
277Decrypting encrypted data using an AES key in CBC mode with no padding
278(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
353Once 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`.
354
355The call to `psa_cipher_abort` frees any resources associated with the operation (except for the operation structure itself). An implicit call to `psa_cipher_abort` occurs when any of these conditions occur:
356* A call to `psa_cipher_generate_iv`, `psa_cipher_set_iv` or `psa_cipher_update` has failed (returning any status other than `PSA_SUCCESS`).
357* Either a successful or failed call to `psa_cipher_finish`.
358
359Once `psa_cipher_abort` has been called (either implicitly by the implementation or explicitly by the user), the operation structure is invalidated and may not be reused for the same operation. However, the operation structure may be reused for a different operation by calling either `psa_cipher_encrypt_setup` or `psa_cipher_decrypt_setup` again.
360
361For an operation that has been initialized successfully (by a successful call to `psa_cipher_encrypt_setup` or `psa_cipher_decrypt_setup`) it is imperative that at some time `psa_cipher_abort` is called.
362
363Multiple sequential calls to `psa_cipher_abort` on an operation that has already been terminated (either implicitly or explicitly) are safe and have no effect.
364
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
370Prerequisites to working with the hash APIs:
371* Initialize the library with a successful call to `psa_crypto_init`.
372
373To calculate a hash:
3741. Allocate an operation structure (`psa_hash_operation_t`) to pass to the hash functions.
3751. Call `psa_hash_setup` to initialize the operation structure and specify the hash algorithm.
3761. Call `psa_hash_update` one or more times, passing either the whole or only a fragment of the message each time.
3771. Call `psa_hash_finish` to calculate the hash, or `psa_hash_verify` to compare the computed hash with an expected hash value.
378
379Calculate the `SHA-256` hash of a message:
380```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
424Verify the `SHA-256` hash of a message:
425```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
476Once the operation structure has been successfully initialized by a successful call to `psa_hash_setup`, it's possible to 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).
477
478An implicit call to `psa_hash_abort` occurs when any of these conditions occur:
4791. A call to `psa_hash_update` has failed (returning any status other than `PSA_SUCCESS`).
4801. Either a successful or failed call to `psa_hash_finish`.
4811. Either a successful or failed call to `psa_hash_verify`.
482
483Once `psa_hash_abort` has been called (either implicitly by the implementation or explicitly by the user), the operation structure is invalidated and may not be reused for the same operation. However, the operation structure may be reused for a different operation by calling `psa_hash_setup` again.
484
485For an operation that has been initialized successfully (by a successful call to `psa_hash_setup`) it is imperative that at some time `psa_hash_abort` is called.
486
487Multiple sequential calls to `psa_hash_abort` on an operation that has already been terminated (either implicitly or explicitly) is safe and has no effect.
488
489### Generating a random value
490
Jaeden Amero884738a2019-08-16 17:58:31 +0100491Mbed Crypto can generate random data. To generate a random key, use
492`psa_generate_key()` instead of `psa_generate_random()`
mohammad160387a7eeb2018-11-01 11:25:49 +0200493
494Prerequisites to random generation:
Jaeden Amero884738a2019-08-16 17:58:31 +0100495* Initialize the library with a successful call to `psa_crypto_init()`.
mohammad160387a7eeb2018-11-01 11:25:49 +0200496
497Generate a random, ten-byte piece of data:
4981. Generate random bytes by calling `psa_generate_random()`:
499```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
530other data. A key derivation context must first be initialized and set up,
531provided with a key and optionally other data, and then derived data can be
532read from it either to a buffer or directly sent to a key slot. Refer to the
533documentation for the particular algorithm (such as HKDF or the TLS1.2 PRF) for
534information on which inputs to pass when and when you can obtain which outputs.
mohammad160387a7eeb2018-11-01 11:25:49 +0200535
536Prerequisites to working with the key derivation APIs:
537* Initialize the library with a successful call to `psa_crypto_init`.
Jaeden Amero884738a2019-08-16 17:58:31 +0100538* Use a key with the appropriate attributes set:
539 * Usage flags set for key derivation (`PSA_KEY_USAGE_DERIVE`)
540 * Key type set to `PSA_KEY_TYPE_DERIVE`.
541 * Algorithm set to a key derivation algorithm
542 (`PSA_ALG_HKDF(PSA_ALG_SHA_256)`).
mohammad160387a7eeb2018-11-01 11:25:49 +0200543
Jaeden Amero884738a2019-08-16 17:58:31 +0100544Deriving a new AES-CTR 128-bit encryption key into a given key slot using HKDF
545with a given key, salt and info:
5461. Set up the key derivation context using the `psa_key_derivation_setup`
547function, specifying the derivation algorithm `PSA_ALG_HKDF(PSA_ALG_SHA_256)`.
5481. Provide an optional salt with `psa_key_derivation_input_bytes`.
5491. Provide info with `psa_key_derivation_input_bytes`.
5501. Provide secret with `psa_key_derivation_input_key`, referencing a key that
551 can be used for key derivation.
5521. Set the key attributes desired for the new derived key. We'll set
553 `PSA_KEY_USAGE_ENCRYPT` parameter and the algorithm `PSA_ALG_CTR` for this
554 example.
5551. Derive the key by calling `psa_key_derivation_output_key()`.
5561. Clean up the key derivation context.
mohammad160387a7eeb2018-11-01 11:25:49 +0200557
Jaeden Amero884738a2019-08-16 17:58:31 +0100558At this point the derived key slot holds a new 128-bit AES-CTR encryption key
559derived from the key, salt and info provided:
mohammad160387a7eeb2018-11-01 11:25:49 +0200560```C
Jaeden Amero884738a2019-08-16 17:58:31 +0100561 psa_status_t status;
562 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
563 static const unsigned char key[] = {
mohammad160387a7eeb2018-11-01 11:25:49 +0200564 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
565 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
566 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
567 0x0b };
Jaeden Amero884738a2019-08-16 17:58:31 +0100568 static const unsigned char salt[] = {
569 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
570 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c };
571 static const unsigned char info[] = {
572 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
573 0xf7, 0xf8, 0xf9 };
mohammad160387a7eeb2018-11-01 11:25:49 +0200574 psa_algorithm_t alg = PSA_ALG_HKDF(PSA_ALG_SHA_256);
Jaeden Amero884738a2019-08-16 17:58:31 +0100575 psa_key_derivation_operation_t operation =
576 PSA_KEY_DERIVATION_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200577 size_t derived_bits = 128;
578 size_t capacity = PSA_BITS_TO_BYTES(derived_bits);
Jaeden Amero884738a2019-08-16 17:58:31 +0100579 psa_key_handle_t base_key;
580 psa_key_handle_t derived_key;
mohammad160387a7eeb2018-11-01 11:25:49 +0200581
Jaeden Amero884738a2019-08-16 17:58:31 +0100582 printf("Derive a key (HKDF)...\t");
583 fflush(stdout);
584
585 /* Initialize PSA Crypto */
mohammad160387a7eeb2018-11-01 11:25:49 +0200586 status = psa_crypto_init();
Jaeden Amero884738a2019-08-16 17:58:31 +0100587 if (status != PSA_SUCCESS) {
588 printf("Failed to initialize PSA Crypto\n");
589 return;
590 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200591
Jaeden Amero884738a2019-08-16 17:58:31 +0100592 /* Import a key for use in key derivation. If such a key has already been
593 * generated or imported, you can skip this part. */
594 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
595 psa_set_key_algorithm(&attributes, alg);
596 psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE);
597 status = psa_import_key(&attributes, key, sizeof(key), &base_key);
598 if (status != PSA_SUCCESS) {
599 printf("Failed to import a key\n");
600 return;
601 }
602 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200603
Jaeden Amero884738a2019-08-16 17:58:31 +0100604 /* Derive a key */
605 status = psa_key_derivation_setup(&operation, alg);
606 if (status != PSA_SUCCESS) {
607 printf("Failed to begin key derivation\n");
608 return;
609 }
610 status = psa_key_derivation_set_capacity(&operation, capacity);
611 if (status != PSA_SUCCESS) {
612 printf("Failed to set capacity\n");
613 return;
614 }
615 status = psa_key_derivation_input_bytes(&operation,
616 PSA_KEY_DERIVATION_INPUT_SALT,
617 salt, sizeof(salt));
618 if (status != PSA_SUCCESS) {
619 printf("Failed to input salt (extract)\n");
620 return;
621 }
622 status = psa_key_derivation_input_key(&operation,
623 PSA_KEY_DERIVATION_INPUT_SECRET,
624 base_key);
625 if (status != PSA_SUCCESS) {
626 printf("Failed to input key (extract)\n");
627 return;
628 }
629 status = psa_key_derivation_input_bytes(&operation,
630 PSA_KEY_DERIVATION_INPUT_INFO,
631 info, sizeof(info));
632 if (status != PSA_SUCCESS) {
633 printf("Failed to input info (expand)\n");
634 return;
635 }
636 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
637 psa_set_key_algorithm(&attributes, PSA_ALG_CTR);
638 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
639 psa_set_key_bits(&attributes, 128);
640 status = psa_key_derivation_output_key(&attributes, &operation,
641 &derived_key);
642 if (status != PSA_SUCCESS) {
643 printf("Failed to derive key\n");
644 return;
645 }
646 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200647
Jaeden Amero884738a2019-08-16 17:58:31 +0100648 printf("Derived key\n");
mohammad160387a7eeb2018-11-01 11:25:49 +0200649
Jaeden Amero884738a2019-08-16 17:58:31 +0100650 /* Clean up key derivation operation */
651 psa_key_derivation_abort(&operation);
mohammad160387a7eeb2018-11-01 11:25:49 +0200652
Jaeden Amero884738a2019-08-16 17:58:31 +0100653 /* Destroy the keys */
654 psa_destroy_key(derived_key);
655 psa_destroy_key(base_key);
mohammad160387a7eeb2018-11-01 11:25:49 +0200656
mohammad160387a7eeb2018-11-01 11:25:49 +0200657 mbedtls_psa_crypto_free();
658```
659
660### Authenticating and encrypting or decrypting a message
661
662Mbed Crypto provides a simple way for authenticate and encrypt with associated data (AEAD) supporting `PSA_ALG_CCM` algorithm.
663
664Prerequisites to working with the AEAD ciphers APIs:
665* Initialize the library with a successful call to `psa_crypto_init`.
Jaeden Amero884738a2019-08-16 17:58:31 +0100666* The key attributes for the key used for derivation must have usage flags
667 `PSA_KEY_USAGE_ENCRYPT` or `PSA_KEY_USAGE_DECRYPT`.
mohammad160387a7eeb2018-11-01 11:25:49 +0200668
669To authenticate and encrypt a message:
670```C
mohammad160387a7eeb2018-11-01 11:25:49 +0200671 psa_status_t status;
Jaeden Amero884738a2019-08-16 17:58:31 +0100672 static const uint8_t key[] = {
673 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
674 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF };
675 static const uint8_t nonce[] = {
676 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
677 0x08, 0x09, 0x0A, 0x0B };
678 static const uint8_t additional_data[] = {
679 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25,
680 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 };
681 static const uint8_t input_data[] = {
682 0xB9, 0x6B, 0x49, 0xE2, 0x1D, 0x62, 0x17, 0x41,
683 0x63, 0x28, 0x75, 0xDB, 0x7F, 0x6C, 0x92, 0x43,
684 0xD2, 0xD7, 0xC2 };
685 uint8_t *output_data = NULL;
mohammad160387a7eeb2018-11-01 11:25:49 +0200686 size_t output_size = 0;
687 size_t output_length = 0;
688 size_t tag_length = 16;
Jaeden Amero884738a2019-08-16 17:58:31 +0100689 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
690 psa_key_handle_t handle;
691
692 printf("Authenticate encrypt...\t");
693 fflush(stdout);
694
695 /* Initialize PSA Crypto */
696 status = psa_crypto_init();
697 if (status != PSA_SUCCESS) {
698 printf("Failed to initialize PSA Crypto\n");
699 return;
700 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200701
702 output_size = sizeof(input_data) + tag_length;
Jaeden Amero884738a2019-08-16 17:58:31 +0100703 output_data = (uint8_t *)malloc(output_size);
704 if (!output_data) {
705 printf("Out of memory\n");
706 return;
707 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200708
Jaeden Amero884738a2019-08-16 17:58:31 +0100709 /* Import a key */
710 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
711 psa_set_key_algorithm(&attributes, PSA_ALG_CCM);
712 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
713 psa_set_key_bits(&attributes, 128);
714 status = psa_import_key(&attributes, key, sizeof(key), &handle);
715 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200716
Jaeden Amero884738a2019-08-16 17:58:31 +0100717 /* Authenticate and encrypt */
718 status = psa_aead_encrypt(handle, PSA_ALG_CCM,
mohammad160387a7eeb2018-11-01 11:25:49 +0200719 nonce, sizeof(nonce),
720 additional_data, sizeof(additional_data),
721 input_data, sizeof(input_data),
722 output_data, output_size,
723 &output_length);
Jaeden Amero884738a2019-08-16 17:58:31 +0100724 if (status != PSA_SUCCESS) {
725 printf("Failed to authenticate and encrypt\n");
726 return;
727 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200728
Jaeden Amero884738a2019-08-16 17:58:31 +0100729 printf("Authenticated and encrypted\n");
730
731 /* Clean up */
732 free(output_data);
733
734 /* Destroy the key */
735 psa_destroy_key(handle);
736
mohammad160387a7eeb2018-11-01 11:25:49 +0200737 mbedtls_psa_crypto_free();
738```
739
740To authenticate and decrypt a message:
741
742```C
mohammad160387a7eeb2018-11-01 11:25:49 +0200743 psa_status_t status;
Jaeden Amero884738a2019-08-16 17:58:31 +0100744 static const uint8_t key[] = {
mohammad160387a7eeb2018-11-01 11:25:49 +0200745 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
Jaeden Amero884738a2019-08-16 17:58:31 +0100746 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF };
747 static const uint8_t nonce[] = {
748 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
749 0x08, 0x09, 0x0A, 0x0B };
750 static const uint8_t additional_data[] = {
751 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25,
752 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 };
753 static const uint8_t input_data[] = {
754 0x20, 0x30, 0xE0, 0x36, 0xED, 0x09, 0xA0, 0x45, 0xAF, 0x3C, 0xBA, 0xEE,
755 0x0F, 0xC8, 0x48, 0xAF, 0xCD, 0x89, 0x54, 0xF4, 0xF6, 0x3F, 0x28, 0x9A,
756 0xA1, 0xDD, 0xB2, 0xB8, 0x09, 0xCD, 0x7C, 0xE1, 0x46, 0xE9, 0x98 };
757 uint8_t *output_data = NULL;
mohammad160387a7eeb2018-11-01 11:25:49 +0200758 size_t output_size = 0;
759 size_t output_length = 0;
Jaeden Amero884738a2019-08-16 17:58:31 +0100760 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
761 psa_key_handle_t handle;
762
763 printf("Authenticate decrypt...\t");
764 fflush(stdout);
765
766 /* Initialize PSA Crypto */
767 status = psa_crypto_init();
768 if (status != PSA_SUCCESS) {
769 printf("Failed to initialize PSA Crypto\n");
770 return;
771 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200772
773 output_size = sizeof(input_data);
Jaeden Amero884738a2019-08-16 17:58:31 +0100774 output_data = (uint8_t *)malloc(output_size);
775 if (!output_data) {
776 printf("Out of memory\n");
777 return;
778 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200779
Jaeden Amero884738a2019-08-16 17:58:31 +0100780 /* Import a key */
781 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
782 psa_set_key_algorithm(&attributes, PSA_ALG_CCM);
783 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
784 psa_set_key_bits(&attributes, 128);
785 status = psa_import_key(&attributes, key, sizeof(key), &handle);
786 if (status != PSA_SUCCESS) {
787 printf("Failed to import a key\n");
788 return;
789 }
790 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200791
Jaeden Amero884738a2019-08-16 17:58:31 +0100792 /* Authenticate and decrypt */
793 status = psa_aead_decrypt(handle, PSA_ALG_CCM,
mohammad160387a7eeb2018-11-01 11:25:49 +0200794 nonce, sizeof(nonce),
795 additional_data, sizeof(additional_data),
796 input_data, sizeof(input_data),
797 output_data, output_size,
798 &output_length);
Jaeden Amero884738a2019-08-16 17:58:31 +0100799 if (status != PSA_SUCCESS) {
800 printf("Failed to authenticate and decrypt %ld\n", status);
801 return;
802 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200803
Jaeden Amero884738a2019-08-16 17:58:31 +0100804 printf("Authenticated and decrypted\n");
805
806 /* Clean up */
807 free(output_data);
808
809 /* Destroy the key */
810 psa_destroy_key(handle);
811
mohammad160387a7eeb2018-11-01 11:25:49 +0200812 mbedtls_psa_crypto_free();
813```
814
815### Generating and exporting keys
816
817Mbed Crypto provides a simple way to generate a key or key pair.
818
819Prerequisites to using key generation and export APIs:
820* Initialize the library with a successful call to `psa_crypto_init`.
821
Jaeden Amero884738a2019-08-16 17:58:31 +0100822Generate an ECDSA key:
8231. Set the desired key attributes for key generation by calling
824 `psa_set_key_algorithm()` with the chosen ECDSA algorithm (such as
825 `PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)`). We don't set
826 `PSA_KEY_USAGE_EXPORT` as we only want to export the public key, not the key
827 pair (or private key).
8281. Generate a key by calling `psa_generate_key()`.
8291. Export the generated public key by calling `psa_export_public_key()`
830:
mohammad160387a7eeb2018-11-01 11:25:49 +0200831```C
Jaeden Amero884738a2019-08-16 17:58:31 +0100832 enum {
833 key_bits = 256,
834 };
835 psa_status_t status;
mohammad160387a7eeb2018-11-01 11:25:49 +0200836 size_t exported_length = 0;
Jaeden Amero884738a2019-08-16 17:58:31 +0100837 static uint8_t exported[PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits)];
838 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
839 psa_key_handle_t handle;
mohammad160387a7eeb2018-11-01 11:25:49 +0200840
Jaeden Amero884738a2019-08-16 17:58:31 +0100841 printf("Generate a key pair...\t");
842 fflush(stdout);
mohammad160387a7eeb2018-11-01 11:25:49 +0200843
Jaeden Amero884738a2019-08-16 17:58:31 +0100844 /* Initialize PSA Crypto */
845 status = psa_crypto_init();
846 if (status != PSA_SUCCESS) {
847 printf("Failed to initialize PSA Crypto\n");
848 return;
849 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200850
851 /* Generate a key */
Jaeden Amero884738a2019-08-16 17:58:31 +0100852 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN);
853 psa_set_key_algorithm(&attributes,
854 PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
855 psa_set_key_type(&attributes,
856 PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1));
857 psa_set_key_bits(&attributes, key_bits);
858 status = psa_generate_key(&attributes, &handle);
859 if (status != PSA_SUCCESS) {
860 printf("Failed to generate key\n");
861 return;
862 }
863 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200864
Jaeden Amero884738a2019-08-16 17:58:31 +0100865 status = psa_export_public_key(handle, exported, sizeof(exported),
866 &exported_length);
867 if (status != PSA_SUCCESS) {
868 printf("Failed to export public key %ld\n", status);
869 return;
870 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200871
Jaeden Amero884738a2019-08-16 17:58:31 +0100872 printf("Exported a public key\n");
873
874 /* Destroy the key */
875 psa_destroy_key(handle);
876
mohammad160387a7eeb2018-11-01 11:25:49 +0200877 mbedtls_psa_crypto_free();
878```
879
880### More about the Mbed Crypto library
881
882More information on [Mbed Crypto](https://github.com/ARMmbed/mbed-crypto/).
883
884More information on [PSA Crypto](https://github.com/ARMmbed/mbed-crypto/blob/development/docs/PSA_Crypto_API_Overview.pdf).