blob: f3c1341dde4043e55ab99221fc1a23bee7a27948 [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 Amerofbdf1502019-11-08 09:59:16 +000075void import_a_key(const uint8_t *key, size_t key_len)
76{
Jaeden Amero884738a2019-08-16 17:58:31 +010077 psa_status_t status;
78 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
Jaeden Amero884738a2019-08-16 17:58:31 +010079 psa_key_handle_t handle;
mohammad160387a7eeb2018-11-01 11:25:49 +020080
Jaeden Amero884738a2019-08-16 17:58:31 +010081 printf("Import an AES key...\t");
82 fflush(stdout);
83
84 /* Initialize PSA Crypto */
85 status = psa_crypto_init();
86 if (status != PSA_SUCCESS) {
87 printf("Failed to initialize PSA Crypto\n");
88 return;
89 }
90
91 /* Set key attributes */
92 psa_set_key_usage_flags(&attributes, 0);
93 psa_set_key_algorithm(&attributes, 0);
94 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
95 psa_set_key_bits(&attributes, 128);
mohammad160387a7eeb2018-11-01 11:25:49 +020096
97 /* Import the key */
Jaeden Amerofbdf1502019-11-08 09:59:16 +000098 status = psa_import_key(&attributes, key, key_len, &handle);
Jaeden Amero884738a2019-08-16 17:58:31 +010099 if (status != PSA_SUCCESS) {
100 printf("Failed to import key\n");
101 return;
102 }
103 printf("Imported a key\n");
mohammad160387a7eeb2018-11-01 11:25:49 +0200104
Jaeden Amero884738a2019-08-16 17:58:31 +0100105 /* Free the attributes */
106 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200107
108 /* Destroy the key */
Jaeden Amero884738a2019-08-16 17:58:31 +0100109 psa_destroy_key(handle);
110
mohammad160387a7eeb2018-11-01 11:25:49 +0200111 mbedtls_psa_crypto_free();
Jaeden Amerofbdf1502019-11-08 09:59:16 +0000112}
mohammad160387a7eeb2018-11-01 11:25:49 +0200113```
114
115### Signing a message using RSA
116
Guy Wildc03c0fc2019-09-03 13:18:04 +0300117Mbed Crypto supports encrypting, decrypting, signing and verifying messages using public key signature algorithms, such as RSA or ECDSA.
mohammad160387a7eeb2018-11-01 11:25:49 +0200118
Guy Wildc03c0fc2019-09-03 13:18:04 +0300119**Prerequisites to performing asymmetric signature operations:**
120* Initialize the library with a successful call to `psa_crypto_init()`.
Jaeden Amero884738a2019-08-16 17:58:31 +0100121* Have a valid key with appropriate attributes set:
Gilles Peskine89d8c5c2019-11-26 17:01:59 +0100122 * Usage flag `PSA_KEY_USAGE_SIGN_HASH` to allow signing.
123 * Usage flag `PSA_KEY_USAGE_VERIFY_HASH` to allow signature verification.
Guy Wildc03c0fc2019-09-03 13:18:04 +0300124 * Algorithm set to the desired signature algorithm.
mohammad160387a7eeb2018-11-01 11:25:49 +0200125
Guy Wild5033fdd2019-09-04 09:14:55 +0300126This example shows how to sign a hash that has already been calculated:
mohammad160387a7eeb2018-11-01 11:25:49 +0200127```C
Jaeden Amerofbdf1502019-11-08 09:59:16 +0000128void sign_a_message_using_rsa(const uint8_t *key, size_t key_len)
129{
mohammad160387a7eeb2018-11-01 11:25:49 +0200130 psa_status_t status;
Jaeden Amero884738a2019-08-16 17:58:31 +0100131 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
Guy Wild5033fdd2019-09-04 09:14:55 +0300132 uint8_t hash[32] = {0x50, 0xd8, 0x58, 0xe0, 0x98, 0x5e, 0xcc, 0x7f,
Guy Wild5b1347a2019-09-05 09:46:31 +0300133 0x60, 0x41, 0x8a, 0xaf, 0x0c, 0xc5, 0xab, 0x58,
134 0x7f, 0x42, 0xc2, 0x57, 0x0a, 0x88, 0x40, 0x95,
135 0xa9, 0xe8, 0xcc, 0xac, 0xd0, 0xf6, 0x54, 0x5c};
Gilles Peskine89d8c5c2019-11-26 17:01:59 +0100136 uint8_t signature[PSA_SIGNATURE_MAX_SIZE] = {0};
mohammad160387a7eeb2018-11-01 11:25:49 +0200137 size_t signature_length;
Jaeden Amero884738a2019-08-16 17:58:31 +0100138 psa_key_handle_t handle;
mohammad160387a7eeb2018-11-01 11:25:49 +0200139
Jaeden Amero884738a2019-08-16 17:58:31 +0100140 printf("Sign a message...\t");
141 fflush(stdout);
142
143 /* Initialize PSA Crypto */
mohammad160387a7eeb2018-11-01 11:25:49 +0200144 status = psa_crypto_init();
Jaeden Amero884738a2019-08-16 17:58:31 +0100145 if (status != PSA_SUCCESS) {
146 printf("Failed to initialize PSA Crypto\n");
147 return;
148 }
149
150 /* Set key attributes */
Gilles Peskine89d8c5c2019-11-26 17:01:59 +0100151 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
Jaeden Amero884738a2019-08-16 17:58:31 +0100152 psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_SIGN_RAW);
153 psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
154 psa_set_key_bits(&attributes, 1024);
mohammad160387a7eeb2018-11-01 11:25:49 +0200155
156 /* Import the key */
Jaeden Amerofbdf1502019-11-08 09:59:16 +0000157 status = psa_import_key(&attributes, key, key_len, &handle);
Jaeden Amero884738a2019-08-16 17:58:31 +0100158 if (status != PSA_SUCCESS) {
159 printf("Failed to import key\n");
160 return;
161 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200162
Jaeden Amero884738a2019-08-16 17:58:31 +0100163 /* Sign message using the key */
Gilles Peskine89d8c5c2019-11-26 17:01:59 +0100164 status = psa_sign_hash(handle, PSA_ALG_RSA_PKCS1V15_SIGN_RAW,
165 hash, sizeof(hash),
166 signature, sizeof(signature),
167 &signature_length);
Jaeden Amero884738a2019-08-16 17:58:31 +0100168 if (status != PSA_SUCCESS) {
169 printf("Failed to sign\n");
170 return;
171 }
172
173 printf("Signed a message\n");
174
175 /* Free the attributes */
176 psa_reset_key_attributes(&attributes);
177
mohammad160387a7eeb2018-11-01 11:25:49 +0200178 /* Destroy the key */
Jaeden Amero884738a2019-08-16 17:58:31 +0100179 psa_destroy_key(handle);
180
mohammad160387a7eeb2018-11-01 11:25:49 +0200181 mbedtls_psa_crypto_free();
Jaeden Amerofbdf1502019-11-08 09:59:16 +0000182}
mohammad160387a7eeb2018-11-01 11:25:49 +0200183```
184
Jaeden Amero884738a2019-08-16 17:58:31 +0100185### Using symmetric ciphers
mohammad160387a7eeb2018-11-01 11:25:49 +0200186
Guy Wildc03c0fc2019-09-03 13:18:04 +0300187Mbed Crypto supports encrypting and decrypting messages using various symmetric cipher algorithms (both block and stream ciphers).
mohammad160387a7eeb2018-11-01 11:25:49 +0200188
Guy Wildc03c0fc2019-09-03 13:18:04 +0300189**Prerequisites to working with the symmetric cipher API:**
190* Initialize the library with a successful call to `psa_crypto_init()`.
Guy Wild5033fdd2019-09-04 09:14:55 +0300191* 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 +0200192
Guy Wildc03c0fc2019-09-03 13:18:04 +0300193**To encrypt a message with a symmetric cipher:**
mohammad160387a7eeb2018-11-01 11:25:49 +02001941. Allocate an operation (`psa_cipher_operation_t`) structure to pass to the cipher functions.
Guy Wild33d421d2019-09-04 09:16:14 +03001951. Initialize the operation structure to zero or to `PSA_CIPHER_OPERATION_INIT`.
1961. Call `psa_cipher_encrypt_setup()` to specify the algorithm and the key to be used.
Guy Wild94113db2019-09-04 09:56:51 +03001971. 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 +03001981. 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 +03001991. Call `psa_cipher_finish()` to end the operation and output the encrypted message.
mohammad160387a7eeb2018-11-01 11:25:49 +0200200
Guy Wild2a9e9f72019-09-04 13:45:54 +0300201This 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 +0200202```c
Jaeden Amerofbdf1502019-11-08 09:59:16 +0000203void encrypt_with_symmetric_ciphers(const uint8_t *key, size_t key_len)
204{
Jaeden Amero884738a2019-08-16 17:58:31 +0100205 enum {
206 block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES),
207 };
208 psa_status_t status;
209 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200210 psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING;
Jaeden Amero884738a2019-08-16 17:58:31 +0100211 uint8_t plaintext[block_size] = SOME_PLAINTEXT;
212 uint8_t iv[block_size];
mohammad160387a7eeb2018-11-01 11:25:49 +0200213 size_t iv_len;
Jaeden Amero884738a2019-08-16 17:58:31 +0100214 uint8_t output[block_size];
mohammad160387a7eeb2018-11-01 11:25:49 +0200215 size_t output_len;
Jaeden Amero884738a2019-08-16 17:58:31 +0100216 psa_key_handle_t handle;
217 psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200218
Jaeden Amero884738a2019-08-16 17:58:31 +0100219 printf("Encrypt with cipher...\t");
220 fflush(stdout);
mohammad160387a7eeb2018-11-01 11:25:49 +0200221
Jaeden Amero884738a2019-08-16 17:58:31 +0100222 /* Initialize PSA Crypto */
223 status = psa_crypto_init();
224 if (status != PSA_SUCCESS)
225 {
226 printf("Failed to initialize PSA Crypto\n");
227 return;
228 }
229
230 /* Import a key */
231 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
232 psa_set_key_algorithm(&attributes, alg);
233 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
234 psa_set_key_bits(&attributes, 128);
Jaeden Amerofbdf1502019-11-08 09:59:16 +0000235 status = psa_import_key(&attributes, key, key_len, &handle);
Jaeden Amero884738a2019-08-16 17:58:31 +0100236 if (status != PSA_SUCCESS) {
237 printf("Failed to import a key\n");
238 return;
239 }
240 psa_reset_key_attributes(&attributes);
241
242 /* Encrypt the plaintext */
243 status = psa_cipher_encrypt_setup(&operation, handle, alg);
244 if (status != PSA_SUCCESS) {
245 printf("Failed to begin cipher operation\n");
246 return;
247 }
248 status = psa_cipher_generate_iv(&operation, iv, sizeof(iv), &iv_len);
249 if (status != PSA_SUCCESS) {
250 printf("Failed to generate IV\n");
251 return;
252 }
253 status = psa_cipher_update(&operation, plaintext, sizeof(plaintext),
254 output, sizeof(output), &output_len);
255 if (status != PSA_SUCCESS) {
256 printf("Failed to update cipher operation\n");
257 return;
258 }
259 status = psa_cipher_finish(&operation, output + output_len,
260 sizeof(output) - output_len, &output_len);
261 if (status != PSA_SUCCESS) {
262 printf("Failed to finish cipher operation\n");
263 return;
264 }
265 printf("Encrypted plaintext\n");
266
mohammad160387a7eeb2018-11-01 11:25:49 +0200267 /* Clean up cipher operation context */
268 psa_cipher_abort(&operation);
Jaeden Amero884738a2019-08-16 17:58:31 +0100269
270 /* Destroy the key */
271 psa_destroy_key(handle);
272
273 mbedtls_psa_crypto_free();
Jaeden Amerofbdf1502019-11-08 09:59:16 +0000274}
mohammad160387a7eeb2018-11-01 11:25:49 +0200275```
276
Guy Wildc03c0fc2019-09-03 13:18:04 +0300277**To decrypt a message with a symmetric cipher:**
mohammad160387a7eeb2018-11-01 11:25:49 +02002781. Allocate an operation (`psa_cipher_operation_t`) structure to pass to the cipher functions.
Guy Wild2a9e9f72019-09-04 13:45:54 +03002791. Initialize the operation structure to zero or to `PSA_CIPHER_OPERATION_INIT`.
2801. Call `psa_cipher_decrypt_setup()` to specify the algorithm and the key to be used.
Guy Wildc03c0fc2019-09-03 13:18:04 +03002811. Call `psa_cipher_set_iv()` with the IV for the decryption.
Guy Wild2a9e9f72019-09-04 13:45:54 +03002821. 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 +03002831. Call `psa_cipher_finish()` to end the operation and output the decrypted message.
mohammad160387a7eeb2018-11-01 11:25:49 +0200284
Guy Wildc03c0fc2019-09-03 13:18:04 +0300285This example shows how to decrypt encrypted data using an AES key in CBC mode with no padding
mohammad160387a7eeb2018-11-01 11:25:49 +0200286(assuming all prerequisites have been fulfilled):
287```c
Jaeden Amerofbdf1502019-11-08 09:59:16 +0000288void decrypt_with_symmetric_ciphers(const uint8_t *key, size_t key_len)
289{
Jaeden Amero884738a2019-08-16 17:58:31 +0100290 enum {
291 block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES),
292 };
293 psa_status_t status;
294 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200295 psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING;
Jaeden Amero884738a2019-08-16 17:58:31 +0100296 psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
297 uint8_t ciphertext[block_size] = SOME_CIPHERTEXT;
298 uint8_t iv[block_size] = ENCRYPTED_WITH_IV;
Jaeden Amero884738a2019-08-16 17:58:31 +0100299 uint8_t output[block_size];
mohammad160387a7eeb2018-11-01 11:25:49 +0200300 size_t output_len;
Jaeden Amero884738a2019-08-16 17:58:31 +0100301 psa_key_handle_t handle;
mohammad160387a7eeb2018-11-01 11:25:49 +0200302
Jaeden Amero884738a2019-08-16 17:58:31 +0100303 printf("Decrypt with cipher...\t");
304 fflush(stdout);
mohammad160387a7eeb2018-11-01 11:25:49 +0200305
Jaeden Amero884738a2019-08-16 17:58:31 +0100306 /* Initialize PSA Crypto */
307 status = psa_crypto_init();
308 if (status != PSA_SUCCESS)
309 {
310 printf("Failed to initialize PSA Crypto\n");
311 return;
312 }
313
314 /* Import a key */
315 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
316 psa_set_key_algorithm(&attributes, alg);
317 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
318 psa_set_key_bits(&attributes, 128);
Jaeden Amerofbdf1502019-11-08 09:59:16 +0000319 status = psa_import_key(&attributes, key, key_len, &handle);
Jaeden Amero884738a2019-08-16 17:58:31 +0100320 if (status != PSA_SUCCESS) {
321 printf("Failed to import a key\n");
322 return;
323 }
324 psa_reset_key_attributes(&attributes);
325
326 /* Decrypt the ciphertext */
327 status = psa_cipher_decrypt_setup(&operation, handle, alg);
328 if (status != PSA_SUCCESS) {
329 printf("Failed to begin cipher operation\n");
330 return;
331 }
332 status = psa_cipher_set_iv(&operation, iv, sizeof(iv));
333 if (status != PSA_SUCCESS) {
334 printf("Failed to set IV\n");
335 return;
336 }
337 status = psa_cipher_update(&operation, ciphertext, sizeof(ciphertext),
338 output, sizeof(output), &output_len);
339 if (status != PSA_SUCCESS) {
340 printf("Failed to update cipher operation\n");
341 return;
342 }
343 status = psa_cipher_finish(&operation, output + output_len,
344 sizeof(output) - output_len, &output_len);
345 if (status != PSA_SUCCESS) {
346 printf("Failed to finish cipher operation\n");
347 return;
348 }
349 printf("Decrypted ciphertext\n");
350
mohammad160387a7eeb2018-11-01 11:25:49 +0200351 /* Clean up cipher operation context */
352 psa_cipher_abort(&operation);
Jaeden Amero884738a2019-08-16 17:58:31 +0100353
354 /* Destroy the key */
355 psa_destroy_key(handle);
356
357 mbedtls_psa_crypto_free();
Jaeden Amerofbdf1502019-11-08 09:59:16 +0000358}
mohammad160387a7eeb2018-11-01 11:25:49 +0200359```
360
361#### Handling cipher operation contexts
362
Guy Wildc03c0fc2019-09-03 13:18:04 +0300363After 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 +0200364
Guy Wildc03c0fc2019-09-03 13:18:04 +0300365The call to `psa_cipher_abort()` frees any resources associated with the operation, except for the operation structure itself.
mohammad160387a7eeb2018-11-01 11:25:49 +0200366
Guy Wildc03c0fc2019-09-03 13:18:04 +0300367Mbed Crypto implicitly calls `psa_cipher_abort()` when:
368* A call to `psa_cipher_generate_iv()`, `psa_cipher_set_iv()` or `psa_cipher_update()` fails (returning any status other than `PSA_SUCCESS`).
369* A call to `psa_cipher_finish()` succeeds or fails.
mohammad160387a7eeb2018-11-01 11:25:49 +0200370
Guy Wildc03c0fc2019-09-03 13:18:04 +0300371After 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 +0200372
Guy Wildc03c0fc2019-09-03 13:18:04 +0300373You must call `psa_cipher_abort()` at some point for any operation that is initialized successfully (by a successful call to `psa_cipher_encrypt_setup()` or `psa_cipher_decrypt_setup()`).
374
375Making multiple sequential calls to `psa_cipher_abort()` on an operation that is terminated (either implicitly or explicitly) is safe and has no effect.
mohammad160387a7eeb2018-11-01 11:25:49 +0200376
377### Hashing a message
378
Jaeden Amero884738a2019-08-16 17:58:31 +0100379Mbed Crypto lets you compute and verify hashes using various hashing
380algorithms.
mohammad160387a7eeb2018-11-01 11:25:49 +0200381
Guy Wildc03c0fc2019-09-03 13:18:04 +0300382**Prerequisites to working with the hash APIs:**
383* Initialize the library with a successful call to `psa_crypto_init()`.
mohammad160387a7eeb2018-11-01 11:25:49 +0200384
Guy Wildc03c0fc2019-09-03 13:18:04 +0300385**To calculate a hash:**
mohammad160387a7eeb2018-11-01 11:25:49 +02003861. Allocate an operation structure (`psa_hash_operation_t`) to pass to the hash functions.
Guy Wildeefc5172019-09-04 09:16:53 +03003871. Initialize the operation structure to zero or to `PSA_HASH_OPERATION_INIT`.
3881. Call `psa_hash_setup()` to specify the hash algorithm.
Guy Wild2a9e9f72019-09-04 13:45:54 +03003891. 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 +03003901. 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 +0200391
Guy Wild2a9e9f72019-09-04 13:45:54 +0300392This example shows how to calculate the SHA-256 hash of a message:
mohammad160387a7eeb2018-11-01 11:25:49 +0200393```c
Jaeden Amero884738a2019-08-16 17:58:31 +0100394 psa_status_t status;
mohammad160387a7eeb2018-11-01 11:25:49 +0200395 psa_algorithm_t alg = PSA_ALG_SHA_256;
Jaeden Amero884738a2019-08-16 17:58:31 +0100396 psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200397 unsigned char input[] = { 'a', 'b', 'c' };
398 unsigned char actual_hash[PSA_HASH_MAX_SIZE];
399 size_t actual_hash_len;
400
Jaeden Amero884738a2019-08-16 17:58:31 +0100401 printf("Hash a message...\t");
402 fflush(stdout);
403
404 /* Initialize PSA Crypto */
405 status = psa_crypto_init();
406 if (status != PSA_SUCCESS) {
407 printf("Failed to initialize PSA Crypto\n");
408 return;
409 }
410
mohammad160387a7eeb2018-11-01 11:25:49 +0200411 /* Compute hash of message */
Jaeden Amero884738a2019-08-16 17:58:31 +0100412 status = psa_hash_setup(&operation, alg);
413 if (status != PSA_SUCCESS) {
414 printf("Failed to begin hash operation\n");
415 return;
416 }
417 status = psa_hash_update(&operation, input, sizeof(input));
418 if (status != PSA_SUCCESS) {
419 printf("Failed to update hash operation\n");
420 return;
421 }
422 status = psa_hash_finish(&operation, actual_hash, sizeof(actual_hash),
423 &actual_hash_len);
424 if (status != PSA_SUCCESS) {
425 printf("Failed to finish hash operation\n");
426 return;
427 }
428
429 printf("Hashed a message\n");
mohammad160387a7eeb2018-11-01 11:25:49 +0200430
431 /* Clean up hash operation context */
432 psa_hash_abort(&operation);
Jaeden Amero884738a2019-08-16 17:58:31 +0100433
434 mbedtls_psa_crypto_free();
mohammad160387a7eeb2018-11-01 11:25:49 +0200435```
436
Guy Wild2a9e9f72019-09-04 13:45:54 +0300437This example shows how to verify the SHA-256 hash of a message:
mohammad160387a7eeb2018-11-01 11:25:49 +0200438```c
Jaeden Amero884738a2019-08-16 17:58:31 +0100439 psa_status_t status;
mohammad160387a7eeb2018-11-01 11:25:49 +0200440 psa_algorithm_t alg = PSA_ALG_SHA_256;
Jaeden Amero884738a2019-08-16 17:58:31 +0100441 psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200442 unsigned char input[] = { 'a', 'b', 'c' };
443 unsigned char expected_hash[] = {
444 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde,
445 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
446 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad
447 };
448 size_t expected_hash_len = PSA_HASH_SIZE(alg);
449
Jaeden Amero884738a2019-08-16 17:58:31 +0100450 printf("Verify a hash...\t");
451 fflush(stdout);
452
453 /* Initialize PSA Crypto */
454 status = psa_crypto_init();
455 if (status != PSA_SUCCESS) {
456 printf("Failed to initialize PSA Crypto\n");
457 return;
458 }
459
mohammad160387a7eeb2018-11-01 11:25:49 +0200460 /* Verify message hash */
Jaeden Amero884738a2019-08-16 17:58:31 +0100461 status = psa_hash_setup(&operation, alg);
462 if (status != PSA_SUCCESS) {
463 printf("Failed to begin hash operation\n");
464 return;
465 }
466 status = psa_hash_update(&operation, input, sizeof(input));
467 if (status != PSA_SUCCESS) {
468 printf("Failed to update hash operation\n");
469 return;
470 }
471 status = psa_hash_verify(&operation, expected_hash, expected_hash_len);
472 if (status != PSA_SUCCESS) {
473 printf("Failed to verify hash\n");
474 return;
475 }
476
477 printf("Verified a hash\n");
478
479 /* Clean up hash operation context */
480 psa_hash_abort(&operation);
481
482 mbedtls_psa_crypto_free();
mohammad160387a7eeb2018-11-01 11:25:49 +0200483```
484
485The API provides the macro `PSA_HASH_SIZE`, which returns the expected hash length (in bytes) for the specified algorithm.
486
487#### Handling hash operation contexts
488
Guy Wild2a9e9f72019-09-04 13:45:54 +0300489After 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 +0200490
Guy Wildc03c0fc2019-09-03 13:18:04 +0300491Mbed Crypto implicitly calls `psa_hash_abort()` when:
4921. A call to `psa_hash_update()` fails (returning any status other than `PSA_SUCCESS`).
4931. A call to `psa_hash_finish()` succeeds or fails.
4941. A call to `psa_hash_verify()` succeeds or fails.
mohammad160387a7eeb2018-11-01 11:25:49 +0200495
Guy Wildc03c0fc2019-09-03 13:18:04 +0300496After 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 +0200497
Guy Wildc03c0fc2019-09-03 13:18:04 +0300498You 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 +0200499
Guy Wildc03c0fc2019-09-03 13:18:04 +0300500Making 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 +0200501
502### Generating a random value
503
Guy Wildc03c0fc2019-09-03 13:18:04 +0300504Mbed Crypto can generate random data.
mohammad160387a7eeb2018-11-01 11:25:49 +0200505
Guy Wild802b19f2019-09-03 16:40:44 +0300506**Prerequisites to generating random data:**
Jaeden Amero884738a2019-08-16 17:58:31 +0100507* Initialize the library with a successful call to `psa_crypto_init()`.
mohammad160387a7eeb2018-11-01 11:25:49 +0200508
Guy Wild802b19f2019-09-03 16:40:44 +0300509<span class="notes">**Note:** To generate a random key, use `psa_generate_key()` instead of `psa_generate_random()`.</span>
510
511This example shows how to generate ten bytes of random data by calling `psa_generate_random()`:
mohammad160387a7eeb2018-11-01 11:25:49 +0200512```C
513 psa_status_t status;
514 uint8_t random[10] = { 0 };
mohammad160387a7eeb2018-11-01 11:25:49 +0200515
Jaeden Amero884738a2019-08-16 17:58:31 +0100516 printf("Generate random...\t");
517 fflush(stdout);
518
519 /* Initialize PSA Crypto */
520 status = psa_crypto_init();
521 if (status != PSA_SUCCESS) {
522 printf("Failed to initialize PSA Crypto\n");
523 return;
524 }
525
526 status = psa_generate_random(random, sizeof(random));
527 if (status != PSA_SUCCESS) {
528 printf("Failed to generate a random value\n");
529 return;
530 }
531
532 printf("Generated random data\n");
533
534 /* Clean up */
mohammad160387a7eeb2018-11-01 11:25:49 +0200535 mbedtls_psa_crypto_free();
536```
537
538### Deriving a new key from an existing key
539
Jaeden Amero884738a2019-08-16 17:58:31 +0100540Mbed Crypto provides a key derivation API that lets you derive new keys from
541existing ones. The key derivation API has functions to take inputs, including
542other keys and data, and functions to generate outputs, such as new keys or
Guy Wildc03c0fc2019-09-03 13:18:04 +0300543other data.
mohammad160387a7eeb2018-11-01 11:25:49 +0200544
Guy Wildc03c0fc2019-09-03 13:18:04 +0300545You must first initialize and set up a key derivation context,
546provided with a key and, optionally, other data. Then, use the key derivation context to either read derived data to a buffer or send derived data directly to a key slot.
547
548See the documentation for the particular algorithm (such as HKDF or the TLS1.2 PRF) for
549information about which inputs to pass when, and when you can obtain which outputs.
550
551**Prerequisites to working with the key derivation APIs:**
552* Initialize the library with a successful call to `psa_crypto_init()`.
Jaeden Amero884738a2019-08-16 17:58:31 +0100553* Use a key with the appropriate attributes set:
554 * Usage flags set for key derivation (`PSA_KEY_USAGE_DERIVE`)
555 * Key type set to `PSA_KEY_TYPE_DERIVE`.
556 * Algorithm set to a key derivation algorithm
Guy Wild2a9e9f72019-09-04 13:45:54 +0300557 (for example, `PSA_ALG_HKDF(PSA_ALG_SHA_256)`).
mohammad160387a7eeb2018-11-01 11:25:49 +0200558
Guy Wildc03c0fc2019-09-03 13:18:04 +0300559**To derive a new AES-CTR 128-bit encryption key into a given key slot using HKDF
Guy Wild2a9e9f72019-09-04 13:45:54 +0300560with a given key, salt and info:**
Guy Wildc03c0fc2019-09-03 13:18:04 +0300561
5621. Set up the key derivation context using the `psa_key_derivation_setup()`
Jaeden Amero884738a2019-08-16 17:58:31 +0100563function, specifying the derivation algorithm `PSA_ALG_HKDF(PSA_ALG_SHA_256)`.
Guy Wild29008112019-09-05 11:38:14 +03005641. Provide an optional salt with `psa_key_derivation_input_bytes()`.
5651. Provide info with `psa_key_derivation_input_bytes()`.
5661. Provide a secret with `psa_key_derivation_input_key()`, referencing a key that
Jaeden Amero884738a2019-08-16 17:58:31 +0100567 can be used for key derivation.
5681. Set the key attributes desired for the new derived key. We'll set
Guy Wild0058ab62019-09-04 09:17:54 +0300569 the `PSA_KEY_USAGE_ENCRYPT` usage flag and the `PSA_ALG_CTR` algorithm for this
Jaeden Amero884738a2019-08-16 17:58:31 +0100570 example.
5711. Derive the key by calling `psa_key_derivation_output_key()`.
5721. Clean up the key derivation context.
mohammad160387a7eeb2018-11-01 11:25:49 +0200573
Guy Wildc03c0fc2019-09-03 13:18:04 +0300574At this point, the derived key slot holds a new 128-bit AES-CTR encryption key
Guy Wildce560772019-09-05 11:35:16 +0300575derived from the key, salt and info provided:
mohammad160387a7eeb2018-11-01 11:25:49 +0200576```C
Jaeden Amero884738a2019-08-16 17:58:31 +0100577 psa_status_t status;
578 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
579 static const unsigned char key[] = {
mohammad160387a7eeb2018-11-01 11:25:49 +0200580 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
581 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
582 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
583 0x0b };
Jaeden Amero884738a2019-08-16 17:58:31 +0100584 static const unsigned char salt[] = {
585 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
586 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c };
587 static const unsigned char info[] = {
588 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
589 0xf7, 0xf8, 0xf9 };
mohammad160387a7eeb2018-11-01 11:25:49 +0200590 psa_algorithm_t alg = PSA_ALG_HKDF(PSA_ALG_SHA_256);
Jaeden Amero884738a2019-08-16 17:58:31 +0100591 psa_key_derivation_operation_t operation =
592 PSA_KEY_DERIVATION_OPERATION_INIT;
mohammad160387a7eeb2018-11-01 11:25:49 +0200593 size_t derived_bits = 128;
594 size_t capacity = PSA_BITS_TO_BYTES(derived_bits);
Jaeden Amero884738a2019-08-16 17:58:31 +0100595 psa_key_handle_t base_key;
596 psa_key_handle_t derived_key;
mohammad160387a7eeb2018-11-01 11:25:49 +0200597
Jaeden Amero884738a2019-08-16 17:58:31 +0100598 printf("Derive a key (HKDF)...\t");
599 fflush(stdout);
600
601 /* Initialize PSA Crypto */
mohammad160387a7eeb2018-11-01 11:25:49 +0200602 status = psa_crypto_init();
Jaeden Amero884738a2019-08-16 17:58:31 +0100603 if (status != PSA_SUCCESS) {
604 printf("Failed to initialize PSA Crypto\n");
605 return;
606 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200607
Jaeden Amero884738a2019-08-16 17:58:31 +0100608 /* Import a key for use in key derivation. If such a key has already been
609 * generated or imported, you can skip this part. */
610 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
611 psa_set_key_algorithm(&attributes, alg);
612 psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE);
613 status = psa_import_key(&attributes, key, sizeof(key), &base_key);
614 if (status != PSA_SUCCESS) {
615 printf("Failed to import a key\n");
616 return;
617 }
618 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200619
Jaeden Amero884738a2019-08-16 17:58:31 +0100620 /* Derive a key */
621 status = psa_key_derivation_setup(&operation, alg);
622 if (status != PSA_SUCCESS) {
623 printf("Failed to begin key derivation\n");
624 return;
625 }
626 status = psa_key_derivation_set_capacity(&operation, capacity);
627 if (status != PSA_SUCCESS) {
628 printf("Failed to set capacity\n");
629 return;
630 }
631 status = psa_key_derivation_input_bytes(&operation,
632 PSA_KEY_DERIVATION_INPUT_SALT,
633 salt, sizeof(salt));
634 if (status != PSA_SUCCESS) {
635 printf("Failed to input salt (extract)\n");
636 return;
637 }
638 status = psa_key_derivation_input_key(&operation,
639 PSA_KEY_DERIVATION_INPUT_SECRET,
640 base_key);
641 if (status != PSA_SUCCESS) {
642 printf("Failed to input key (extract)\n");
643 return;
644 }
645 status = psa_key_derivation_input_bytes(&operation,
646 PSA_KEY_DERIVATION_INPUT_INFO,
647 info, sizeof(info));
648 if (status != PSA_SUCCESS) {
649 printf("Failed to input info (expand)\n");
650 return;
651 }
652 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
653 psa_set_key_algorithm(&attributes, PSA_ALG_CTR);
654 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
655 psa_set_key_bits(&attributes, 128);
656 status = psa_key_derivation_output_key(&attributes, &operation,
657 &derived_key);
658 if (status != PSA_SUCCESS) {
659 printf("Failed to derive key\n");
660 return;
661 }
662 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200663
Jaeden Amero884738a2019-08-16 17:58:31 +0100664 printf("Derived key\n");
mohammad160387a7eeb2018-11-01 11:25:49 +0200665
Jaeden Amero884738a2019-08-16 17:58:31 +0100666 /* Clean up key derivation operation */
667 psa_key_derivation_abort(&operation);
mohammad160387a7eeb2018-11-01 11:25:49 +0200668
Jaeden Amero884738a2019-08-16 17:58:31 +0100669 /* Destroy the keys */
670 psa_destroy_key(derived_key);
671 psa_destroy_key(base_key);
mohammad160387a7eeb2018-11-01 11:25:49 +0200672
mohammad160387a7eeb2018-11-01 11:25:49 +0200673 mbedtls_psa_crypto_free();
674```
675
676### Authenticating and encrypting or decrypting a message
677
Guy Wildc03c0fc2019-09-03 13:18:04 +0300678Mbed 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 +0200679
Guy Wildc03c0fc2019-09-03 13:18:04 +0300680**Prerequisites to working with the AEAD cipher APIs:**
681* Initialize the library with a successful call to `psa_crypto_init()`.
682* The key attributes for the key used for derivation must have the `PSA_KEY_USAGE_ENCRYPT` or `PSA_KEY_USAGE_DECRYPT` usage flags.
mohammad160387a7eeb2018-11-01 11:25:49 +0200683
Guy Wildc03c0fc2019-09-03 13:18:04 +0300684This example shows how to authenticate and encrypt a message:
mohammad160387a7eeb2018-11-01 11:25:49 +0200685```C
mohammad160387a7eeb2018-11-01 11:25:49 +0200686 psa_status_t status;
Jaeden Amero884738a2019-08-16 17:58:31 +0100687 static const uint8_t key[] = {
688 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
689 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF };
690 static const uint8_t nonce[] = {
691 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
692 0x08, 0x09, 0x0A, 0x0B };
693 static const uint8_t additional_data[] = {
694 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25,
695 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 };
696 static const uint8_t input_data[] = {
697 0xB9, 0x6B, 0x49, 0xE2, 0x1D, 0x62, 0x17, 0x41,
698 0x63, 0x28, 0x75, 0xDB, 0x7F, 0x6C, 0x92, 0x43,
699 0xD2, 0xD7, 0xC2 };
700 uint8_t *output_data = NULL;
mohammad160387a7eeb2018-11-01 11:25:49 +0200701 size_t output_size = 0;
702 size_t output_length = 0;
703 size_t tag_length = 16;
Jaeden Amero884738a2019-08-16 17:58:31 +0100704 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
705 psa_key_handle_t handle;
706
707 printf("Authenticate encrypt...\t");
708 fflush(stdout);
709
710 /* Initialize PSA Crypto */
711 status = psa_crypto_init();
712 if (status != PSA_SUCCESS) {
713 printf("Failed to initialize PSA Crypto\n");
714 return;
715 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200716
717 output_size = sizeof(input_data) + tag_length;
Jaeden Amero884738a2019-08-16 17:58:31 +0100718 output_data = (uint8_t *)malloc(output_size);
719 if (!output_data) {
720 printf("Out of memory\n");
721 return;
722 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200723
Jaeden Amero884738a2019-08-16 17:58:31 +0100724 /* Import a key */
725 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
726 psa_set_key_algorithm(&attributes, PSA_ALG_CCM);
727 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
728 psa_set_key_bits(&attributes, 128);
729 status = psa_import_key(&attributes, key, sizeof(key), &handle);
730 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200731
Jaeden Amero884738a2019-08-16 17:58:31 +0100732 /* Authenticate and encrypt */
733 status = psa_aead_encrypt(handle, PSA_ALG_CCM,
mohammad160387a7eeb2018-11-01 11:25:49 +0200734 nonce, sizeof(nonce),
735 additional_data, sizeof(additional_data),
736 input_data, sizeof(input_data),
737 output_data, output_size,
738 &output_length);
Jaeden Amero884738a2019-08-16 17:58:31 +0100739 if (status != PSA_SUCCESS) {
740 printf("Failed to authenticate and encrypt\n");
741 return;
742 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200743
Jaeden Amero884738a2019-08-16 17:58:31 +0100744 printf("Authenticated and encrypted\n");
745
746 /* Clean up */
747 free(output_data);
748
749 /* Destroy the key */
750 psa_destroy_key(handle);
751
mohammad160387a7eeb2018-11-01 11:25:49 +0200752 mbedtls_psa_crypto_free();
753```
754
Guy Wildc03c0fc2019-09-03 13:18:04 +0300755This example shows how to authenticate and decrypt a message:
mohammad160387a7eeb2018-11-01 11:25:49 +0200756
757```C
mohammad160387a7eeb2018-11-01 11:25:49 +0200758 psa_status_t status;
Jaeden Amero884738a2019-08-16 17:58:31 +0100759 static const uint8_t key[] = {
mohammad160387a7eeb2018-11-01 11:25:49 +0200760 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
Jaeden Amero884738a2019-08-16 17:58:31 +0100761 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF };
762 static const uint8_t nonce[] = {
763 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
764 0x08, 0x09, 0x0A, 0x0B };
765 static const uint8_t additional_data[] = {
766 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25,
767 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 };
768 static const uint8_t input_data[] = {
769 0x20, 0x30, 0xE0, 0x36, 0xED, 0x09, 0xA0, 0x45, 0xAF, 0x3C, 0xBA, 0xEE,
770 0x0F, 0xC8, 0x48, 0xAF, 0xCD, 0x89, 0x54, 0xF4, 0xF6, 0x3F, 0x28, 0x9A,
771 0xA1, 0xDD, 0xB2, 0xB8, 0x09, 0xCD, 0x7C, 0xE1, 0x46, 0xE9, 0x98 };
772 uint8_t *output_data = NULL;
mohammad160387a7eeb2018-11-01 11:25:49 +0200773 size_t output_size = 0;
774 size_t output_length = 0;
Jaeden Amero884738a2019-08-16 17:58:31 +0100775 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
776 psa_key_handle_t handle;
777
778 printf("Authenticate decrypt...\t");
779 fflush(stdout);
780
781 /* Initialize PSA Crypto */
782 status = psa_crypto_init();
783 if (status != PSA_SUCCESS) {
784 printf("Failed to initialize PSA Crypto\n");
785 return;
786 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200787
788 output_size = sizeof(input_data);
Jaeden Amero884738a2019-08-16 17:58:31 +0100789 output_data = (uint8_t *)malloc(output_size);
790 if (!output_data) {
791 printf("Out of memory\n");
792 return;
793 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200794
Jaeden Amero884738a2019-08-16 17:58:31 +0100795 /* Import a key */
796 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
797 psa_set_key_algorithm(&attributes, PSA_ALG_CCM);
798 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
799 psa_set_key_bits(&attributes, 128);
800 status = psa_import_key(&attributes, key, sizeof(key), &handle);
801 if (status != PSA_SUCCESS) {
802 printf("Failed to import a key\n");
803 return;
804 }
805 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200806
Jaeden Amero884738a2019-08-16 17:58:31 +0100807 /* Authenticate and decrypt */
808 status = psa_aead_decrypt(handle, PSA_ALG_CCM,
mohammad160387a7eeb2018-11-01 11:25:49 +0200809 nonce, sizeof(nonce),
810 additional_data, sizeof(additional_data),
811 input_data, sizeof(input_data),
812 output_data, output_size,
813 &output_length);
Jaeden Amero884738a2019-08-16 17:58:31 +0100814 if (status != PSA_SUCCESS) {
815 printf("Failed to authenticate and decrypt %ld\n", status);
816 return;
817 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200818
Jaeden Amero884738a2019-08-16 17:58:31 +0100819 printf("Authenticated and decrypted\n");
820
821 /* Clean up */
822 free(output_data);
823
824 /* Destroy the key */
825 psa_destroy_key(handle);
826
mohammad160387a7eeb2018-11-01 11:25:49 +0200827 mbedtls_psa_crypto_free();
828```
829
830### Generating and exporting keys
831
832Mbed Crypto provides a simple way to generate a key or key pair.
833
Guy Wildc03c0fc2019-09-03 13:18:04 +0300834**Prerequisites to using key generation and export APIs:**
835* Initialize the library with a successful call to `psa_crypto_init()`.
mohammad160387a7eeb2018-11-01 11:25:49 +0200836
Guy Wildc03c0fc2019-09-03 13:18:04 +0300837**To generate an ECDSA key:**
Jaeden Amero884738a2019-08-16 17:58:31 +01008381. Set the desired key attributes for key generation by calling
839 `psa_set_key_algorithm()` with the chosen ECDSA algorithm (such as
Guy Wild94113db2019-09-04 09:56:51 +0300840 `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 +01008411. Generate a key by calling `psa_generate_key()`.
Guy Wildc03c0fc2019-09-03 13:18:04 +03008421. Export the generated public key by calling `psa_export_public_key()`:
mohammad160387a7eeb2018-11-01 11:25:49 +0200843```C
Jaeden Amero884738a2019-08-16 17:58:31 +0100844 enum {
845 key_bits = 256,
846 };
847 psa_status_t status;
mohammad160387a7eeb2018-11-01 11:25:49 +0200848 size_t exported_length = 0;
Jaeden Amero884738a2019-08-16 17:58:31 +0100849 static uint8_t exported[PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits)];
850 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
851 psa_key_handle_t handle;
mohammad160387a7eeb2018-11-01 11:25:49 +0200852
Jaeden Amero884738a2019-08-16 17:58:31 +0100853 printf("Generate a key pair...\t");
854 fflush(stdout);
mohammad160387a7eeb2018-11-01 11:25:49 +0200855
Jaeden Amero884738a2019-08-16 17:58:31 +0100856 /* Initialize PSA Crypto */
857 status = psa_crypto_init();
858 if (status != PSA_SUCCESS) {
859 printf("Failed to initialize PSA Crypto\n");
860 return;
861 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200862
863 /* Generate a key */
Gilles Peskine89d8c5c2019-11-26 17:01:59 +0100864 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
Jaeden Amero884738a2019-08-16 17:58:31 +0100865 psa_set_key_algorithm(&attributes,
866 PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
867 psa_set_key_type(&attributes,
Gilles Peskine228abc52019-12-03 17:24:19 +0100868 PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP_R1));
Jaeden Amero884738a2019-08-16 17:58:31 +0100869 psa_set_key_bits(&attributes, key_bits);
870 status = psa_generate_key(&attributes, &handle);
871 if (status != PSA_SUCCESS) {
872 printf("Failed to generate key\n");
873 return;
874 }
875 psa_reset_key_attributes(&attributes);
mohammad160387a7eeb2018-11-01 11:25:49 +0200876
Jaeden Amero884738a2019-08-16 17:58:31 +0100877 status = psa_export_public_key(handle, exported, sizeof(exported),
878 &exported_length);
879 if (status != PSA_SUCCESS) {
880 printf("Failed to export public key %ld\n", status);
881 return;
882 }
mohammad160387a7eeb2018-11-01 11:25:49 +0200883
Jaeden Amero884738a2019-08-16 17:58:31 +0100884 printf("Exported a public key\n");
885
886 /* Destroy the key */
887 psa_destroy_key(handle);
888
mohammad160387a7eeb2018-11-01 11:25:49 +0200889 mbedtls_psa_crypto_free();
890```
891
Guy Wild2a9e9f72019-09-04 13:45:54 +0300892### More about the PSA Crypto API
mohammad160387a7eeb2018-11-01 11:25:49 +0200893
Guy Wild94113db2019-09-04 09:56:51 +0300894For more information about the PSA Crypto API, please see the [PSA Cryptography API Specification](https://armmbed.github.io/mbed-crypto/html/index.html).