mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 1 | ## Getting started with Mbed Crypto |
| 2 | |
| 3 | ### What is Mbed Crypto? |
| 4 | |
| 5 | Mbed 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 | |
| 14 | The 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 | |
| 16 | The Mbed Crypto library is distributed under the Apache License, version 2.0. |
| 17 | |
| 18 | #### Platform Security Architecture (PSA) |
| 19 | |
| 20 | Arm's Platform Security Architecture (PSA) is a holistic set of threat models, |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 21 | security 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. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 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 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 40 | Mbed Crypto releases are available in the [public GitHub repository](https://github.com/ARMmbed/mbed-crypto). |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 41 | |
| 42 | ### Building the Mbed Crypto library |
| 43 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 44 | **Prerequisites to building the library with the provided makefiles:** |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 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 | |
Guy Wild | 5033fdd | 2019-09-04 09:14:55 +0300 | [diff] [blame] | 50 | If 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. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 51 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 52 | To 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: |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 53 | ``` |
| 54 | make CC=arm-linux-gnueabi-gcc AR=arm-linux-gnueabi-ar |
| 55 | ``` |
| 56 | The 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 | |
| 58 | To 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 | |
| 62 | To 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 Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 66 | To use a key for cryptography operations in Mbed Crypto, you need to first |
Guy Wild | 5033fdd | 2019-09-04 09:14:55 +0300 | [diff] [blame] | 67 | import it. Importing the key creates a handle that refers to the key for use |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 68 | with other function calls. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 69 | |
Guy Wild | 802b19f | 2019-09-03 16:40:44 +0300 | [diff] [blame] | 70 | **Prerequisites to importing keys:** |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 71 | * Initialize the library with a successful call to `psa_crypto_init()`. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 72 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 73 | This example shows how to import a key: |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 74 | ```C |
Jaeden Amero | fbdf150 | 2019-11-08 09:59:16 +0000 | [diff] [blame] | 75 | void import_a_key(const uint8_t *key, size_t key_len) |
| 76 | { |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 77 | psa_status_t status; |
| 78 | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 79 | psa_key_handle_t handle; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 80 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 81 | 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); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 96 | |
| 97 | /* Import the key */ |
Jaeden Amero | fbdf150 | 2019-11-08 09:59:16 +0000 | [diff] [blame] | 98 | status = psa_import_key(&attributes, key, key_len, &handle); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 99 | if (status != PSA_SUCCESS) { |
| 100 | printf("Failed to import key\n"); |
| 101 | return; |
| 102 | } |
| 103 | printf("Imported a key\n"); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 104 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 105 | /* Free the attributes */ |
| 106 | psa_reset_key_attributes(&attributes); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 107 | |
| 108 | /* Destroy the key */ |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 109 | psa_destroy_key(handle); |
| 110 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 111 | mbedtls_psa_crypto_free(); |
Jaeden Amero | fbdf150 | 2019-11-08 09:59:16 +0000 | [diff] [blame] | 112 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 113 | ``` |
| 114 | |
| 115 | ### Signing a message using RSA |
| 116 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 117 | Mbed Crypto supports encrypting, decrypting, signing and verifying messages using public key signature algorithms, such as RSA or ECDSA. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 118 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 119 | **Prerequisites to performing asymmetric signature operations:** |
| 120 | * Initialize the library with a successful call to `psa_crypto_init()`. |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 121 | * Have a valid key with appropriate attributes set: |
Gilles Peskine | 89d8c5c | 2019-11-26 17:01:59 +0100 | [diff] [blame] | 122 | * Usage flag `PSA_KEY_USAGE_SIGN_HASH` to allow signing. |
| 123 | * Usage flag `PSA_KEY_USAGE_VERIFY_HASH` to allow signature verification. |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 124 | * Algorithm set to the desired signature algorithm. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 125 | |
Guy Wild | 5033fdd | 2019-09-04 09:14:55 +0300 | [diff] [blame] | 126 | This example shows how to sign a hash that has already been calculated: |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 127 | ```C |
Jaeden Amero | fbdf150 | 2019-11-08 09:59:16 +0000 | [diff] [blame] | 128 | void sign_a_message_using_rsa(const uint8_t *key, size_t key_len) |
| 129 | { |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 130 | psa_status_t status; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 131 | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
Guy Wild | 5033fdd | 2019-09-04 09:14:55 +0300 | [diff] [blame] | 132 | uint8_t hash[32] = {0x50, 0xd8, 0x58, 0xe0, 0x98, 0x5e, 0xcc, 0x7f, |
Guy Wild | 5b1347a | 2019-09-05 09:46:31 +0300 | [diff] [blame] | 133 | 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 Peskine | 89d8c5c | 2019-11-26 17:01:59 +0100 | [diff] [blame] | 136 | uint8_t signature[PSA_SIGNATURE_MAX_SIZE] = {0}; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 137 | size_t signature_length; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 138 | psa_key_handle_t handle; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 139 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 140 | printf("Sign a message...\t"); |
| 141 | fflush(stdout); |
| 142 | |
| 143 | /* Initialize PSA Crypto */ |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 144 | status = psa_crypto_init(); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 145 | if (status != PSA_SUCCESS) { |
| 146 | printf("Failed to initialize PSA Crypto\n"); |
| 147 | return; |
| 148 | } |
| 149 | |
| 150 | /* Set key attributes */ |
Gilles Peskine | 89d8c5c | 2019-11-26 17:01:59 +0100 | [diff] [blame] | 151 | psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 152 | 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); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 155 | |
| 156 | /* Import the key */ |
Jaeden Amero | fbdf150 | 2019-11-08 09:59:16 +0000 | [diff] [blame] | 157 | status = psa_import_key(&attributes, key, key_len, &handle); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 158 | if (status != PSA_SUCCESS) { |
| 159 | printf("Failed to import key\n"); |
| 160 | return; |
| 161 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 162 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 163 | /* Sign message using the key */ |
Gilles Peskine | 89d8c5c | 2019-11-26 17:01:59 +0100 | [diff] [blame] | 164 | status = psa_sign_hash(handle, PSA_ALG_RSA_PKCS1V15_SIGN_RAW, |
| 165 | hash, sizeof(hash), |
| 166 | signature, sizeof(signature), |
| 167 | &signature_length); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 168 | 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 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 178 | /* Destroy the key */ |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 179 | psa_destroy_key(handle); |
| 180 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 181 | mbedtls_psa_crypto_free(); |
Jaeden Amero | fbdf150 | 2019-11-08 09:59:16 +0000 | [diff] [blame] | 182 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 183 | ``` |
| 184 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 185 | ### Using symmetric ciphers |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 186 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 187 | Mbed Crypto supports encrypting and decrypting messages using various symmetric cipher algorithms (both block and stream ciphers). |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 188 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 189 | **Prerequisites to working with the symmetric cipher API:** |
| 190 | * Initialize the library with a successful call to `psa_crypto_init()`. |
Guy Wild | 5033fdd | 2019-09-04 09:14:55 +0300 | [diff] [blame] | 191 | * 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. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 192 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 193 | **To encrypt a message with a symmetric cipher:** |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 194 | 1. Allocate an operation (`psa_cipher_operation_t`) structure to pass to the cipher functions. |
Guy Wild | 33d421d | 2019-09-04 09:16:14 +0300 | [diff] [blame] | 195 | 1. Initialize the operation structure to zero or to `PSA_CIPHER_OPERATION_INIT`. |
| 196 | 1. Call `psa_cipher_encrypt_setup()` to specify the algorithm and the key to be used. |
Guy Wild | 94113db | 2019-09-04 09:56:51 +0300 | [diff] [blame] | 197 | 1. 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 Wild | 2a9e9f7 | 2019-09-04 13:45:54 +0300 | [diff] [blame] | 198 | 1. 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 Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 199 | 1. Call `psa_cipher_finish()` to end the operation and output the encrypted message. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 200 | |
Guy Wild | 2a9e9f7 | 2019-09-04 13:45:54 +0300 | [diff] [blame] | 201 | This 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): |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 202 | ```c |
Jaeden Amero | fbdf150 | 2019-11-08 09:59:16 +0000 | [diff] [blame] | 203 | void encrypt_with_symmetric_ciphers(const uint8_t *key, size_t key_len) |
| 204 | { |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 205 | 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; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 210 | psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 211 | uint8_t plaintext[block_size] = SOME_PLAINTEXT; |
| 212 | uint8_t iv[block_size]; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 213 | size_t iv_len; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 214 | uint8_t output[block_size]; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 215 | size_t output_len; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 216 | psa_key_handle_t handle; |
| 217 | psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 218 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 219 | printf("Encrypt with cipher...\t"); |
| 220 | fflush(stdout); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 221 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 222 | /* 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 Amero | fbdf150 | 2019-11-08 09:59:16 +0000 | [diff] [blame] | 235 | status = psa_import_key(&attributes, key, key_len, &handle); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 236 | 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 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 267 | /* Clean up cipher operation context */ |
| 268 | psa_cipher_abort(&operation); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 269 | |
| 270 | /* Destroy the key */ |
| 271 | psa_destroy_key(handle); |
| 272 | |
| 273 | mbedtls_psa_crypto_free(); |
Jaeden Amero | fbdf150 | 2019-11-08 09:59:16 +0000 | [diff] [blame] | 274 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 275 | ``` |
| 276 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 277 | **To decrypt a message with a symmetric cipher:** |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 278 | 1. Allocate an operation (`psa_cipher_operation_t`) structure to pass to the cipher functions. |
Guy Wild | 2a9e9f7 | 2019-09-04 13:45:54 +0300 | [diff] [blame] | 279 | 1. Initialize the operation structure to zero or to `PSA_CIPHER_OPERATION_INIT`. |
| 280 | 1. Call `psa_cipher_decrypt_setup()` to specify the algorithm and the key to be used. |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 281 | 1. Call `psa_cipher_set_iv()` with the IV for the decryption. |
Guy Wild | 2a9e9f7 | 2019-09-04 13:45:54 +0300 | [diff] [blame] | 282 | 1. 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 Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 283 | 1. Call `psa_cipher_finish()` to end the operation and output the decrypted message. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 284 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 285 | This example shows how to decrypt encrypted data using an AES key in CBC mode with no padding |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 286 | (assuming all prerequisites have been fulfilled): |
| 287 | ```c |
Jaeden Amero | fbdf150 | 2019-11-08 09:59:16 +0000 | [diff] [blame] | 288 | void decrypt_with_symmetric_ciphers(const uint8_t *key, size_t key_len) |
| 289 | { |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 290 | 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; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 295 | psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 296 | 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 Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 299 | uint8_t output[block_size]; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 300 | size_t output_len; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 301 | psa_key_handle_t handle; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 302 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 303 | printf("Decrypt with cipher...\t"); |
| 304 | fflush(stdout); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 305 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 306 | /* 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 Amero | fbdf150 | 2019-11-08 09:59:16 +0000 | [diff] [blame] | 319 | status = psa_import_key(&attributes, key, key_len, &handle); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 320 | 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 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 351 | /* Clean up cipher operation context */ |
| 352 | psa_cipher_abort(&operation); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 353 | |
| 354 | /* Destroy the key */ |
| 355 | psa_destroy_key(handle); |
| 356 | |
| 357 | mbedtls_psa_crypto_free(); |
Jaeden Amero | fbdf150 | 2019-11-08 09:59:16 +0000 | [diff] [blame] | 358 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 359 | ``` |
| 360 | |
| 361 | #### Handling cipher operation contexts |
| 362 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 363 | After 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()`. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 364 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 365 | The call to `psa_cipher_abort()` frees any resources associated with the operation, except for the operation structure itself. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 366 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 367 | Mbed 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. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 370 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 371 | After 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. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 372 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 373 | You 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 | |
| 375 | Making multiple sequential calls to `psa_cipher_abort()` on an operation that is terminated (either implicitly or explicitly) is safe and has no effect. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 376 | |
| 377 | ### Hashing a message |
| 378 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 379 | Mbed Crypto lets you compute and verify hashes using various hashing |
| 380 | algorithms. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 381 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 382 | **Prerequisites to working with the hash APIs:** |
| 383 | * Initialize the library with a successful call to `psa_crypto_init()`. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 384 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 385 | **To calculate a hash:** |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 386 | 1. Allocate an operation structure (`psa_hash_operation_t`) to pass to the hash functions. |
Guy Wild | eefc517 | 2019-09-04 09:16:53 +0300 | [diff] [blame] | 387 | 1. Initialize the operation structure to zero or to `PSA_HASH_OPERATION_INIT`. |
| 388 | 1. Call `psa_hash_setup()` to specify the hash algorithm. |
Guy Wild | 2a9e9f7 | 2019-09-04 13:45:54 +0300 | [diff] [blame] | 389 | 1. 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 Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 390 | 1. Call `psa_hash_finish()` to calculate the hash, or `psa_hash_verify()` to compare the computed hash with an expected hash value. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 391 | |
Guy Wild | 2a9e9f7 | 2019-09-04 13:45:54 +0300 | [diff] [blame] | 392 | This example shows how to calculate the SHA-256 hash of a message: |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 393 | ```c |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 394 | psa_status_t status; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 395 | psa_algorithm_t alg = PSA_ALG_SHA_256; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 396 | psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 397 | unsigned char input[] = { 'a', 'b', 'c' }; |
| 398 | unsigned char actual_hash[PSA_HASH_MAX_SIZE]; |
| 399 | size_t actual_hash_len; |
| 400 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 401 | 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 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 411 | /* Compute hash of message */ |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 412 | 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"); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 430 | |
| 431 | /* Clean up hash operation context */ |
| 432 | psa_hash_abort(&operation); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 433 | |
| 434 | mbedtls_psa_crypto_free(); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 435 | ``` |
| 436 | |
Guy Wild | 2a9e9f7 | 2019-09-04 13:45:54 +0300 | [diff] [blame] | 437 | This example shows how to verify the SHA-256 hash of a message: |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 438 | ```c |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 439 | psa_status_t status; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 440 | psa_algorithm_t alg = PSA_ALG_SHA_256; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 441 | psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 442 | 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 Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 450 | 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 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 460 | /* Verify message hash */ |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 461 | 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(); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 483 | ``` |
| 484 | |
| 485 | The 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 Wild | 2a9e9f7 | 2019-09-04 13:45:54 +0300 | [diff] [blame] | 489 | After 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. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 490 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 491 | Mbed Crypto implicitly calls `psa_hash_abort()` when: |
| 492 | 1. A call to `psa_hash_update()` fails (returning any status other than `PSA_SUCCESS`). |
| 493 | 1. A call to `psa_hash_finish()` succeeds or fails. |
| 494 | 1. A call to `psa_hash_verify()` succeeds or fails. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 495 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 496 | After 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. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 497 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 498 | You must call `psa_hash_abort()` at some point for any operation that is initialized successfully (by a successful call to `psa_hash_setup()`) . |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 499 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 500 | Making 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. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 501 | |
| 502 | ### Generating a random value |
| 503 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 504 | Mbed Crypto can generate random data. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 505 | |
Guy Wild | 802b19f | 2019-09-03 16:40:44 +0300 | [diff] [blame] | 506 | **Prerequisites to generating random data:** |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 507 | * Initialize the library with a successful call to `psa_crypto_init()`. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 508 | |
Guy Wild | 802b19f | 2019-09-03 16:40:44 +0300 | [diff] [blame] | 509 | <span class="notes">**Note:** To generate a random key, use `psa_generate_key()` instead of `psa_generate_random()`.</span> |
| 510 | |
| 511 | This example shows how to generate ten bytes of random data by calling `psa_generate_random()`: |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 512 | ```C |
| 513 | psa_status_t status; |
| 514 | uint8_t random[10] = { 0 }; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 515 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 516 | 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 */ |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 535 | mbedtls_psa_crypto_free(); |
| 536 | ``` |
| 537 | |
| 538 | ### Deriving a new key from an existing key |
| 539 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 540 | Mbed Crypto provides a key derivation API that lets you derive new keys from |
| 541 | existing ones. The key derivation API has functions to take inputs, including |
| 542 | other keys and data, and functions to generate outputs, such as new keys or |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 543 | other data. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 544 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 545 | You must first initialize and set up a key derivation context, |
| 546 | provided 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 | |
| 548 | See the documentation for the particular algorithm (such as HKDF or the TLS1.2 PRF) for |
| 549 | information 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 Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 553 | * 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 Wild | 2a9e9f7 | 2019-09-04 13:45:54 +0300 | [diff] [blame] | 557 | (for example, `PSA_ALG_HKDF(PSA_ALG_SHA_256)`). |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 558 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 559 | **To derive a new AES-CTR 128-bit encryption key into a given key slot using HKDF |
Guy Wild | 2a9e9f7 | 2019-09-04 13:45:54 +0300 | [diff] [blame] | 560 | with a given key, salt and info:** |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 561 | |
| 562 | 1. Set up the key derivation context using the `psa_key_derivation_setup()` |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 563 | function, specifying the derivation algorithm `PSA_ALG_HKDF(PSA_ALG_SHA_256)`. |
Guy Wild | 2900811 | 2019-09-05 11:38:14 +0300 | [diff] [blame] | 564 | 1. Provide an optional salt with `psa_key_derivation_input_bytes()`. |
| 565 | 1. Provide info with `psa_key_derivation_input_bytes()`. |
| 566 | 1. Provide a secret with `psa_key_derivation_input_key()`, referencing a key that |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 567 | can be used for key derivation. |
| 568 | 1. Set the key attributes desired for the new derived key. We'll set |
Guy Wild | 0058ab6 | 2019-09-04 09:17:54 +0300 | [diff] [blame] | 569 | the `PSA_KEY_USAGE_ENCRYPT` usage flag and the `PSA_ALG_CTR` algorithm for this |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 570 | example. |
| 571 | 1. Derive the key by calling `psa_key_derivation_output_key()`. |
| 572 | 1. Clean up the key derivation context. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 573 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 574 | At this point, the derived key slot holds a new 128-bit AES-CTR encryption key |
Guy Wild | ce56077 | 2019-09-05 11:35:16 +0300 | [diff] [blame] | 575 | derived from the key, salt and info provided: |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 576 | ```C |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 577 | psa_status_t status; |
| 578 | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
| 579 | static const unsigned char key[] = { |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 580 | 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 Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 584 | 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 }; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 590 | psa_algorithm_t alg = PSA_ALG_HKDF(PSA_ALG_SHA_256); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 591 | psa_key_derivation_operation_t operation = |
| 592 | PSA_KEY_DERIVATION_OPERATION_INIT; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 593 | size_t derived_bits = 128; |
| 594 | size_t capacity = PSA_BITS_TO_BYTES(derived_bits); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 595 | psa_key_handle_t base_key; |
| 596 | psa_key_handle_t derived_key; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 597 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 598 | printf("Derive a key (HKDF)...\t"); |
| 599 | fflush(stdout); |
| 600 | |
| 601 | /* Initialize PSA Crypto */ |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 602 | status = psa_crypto_init(); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 603 | if (status != PSA_SUCCESS) { |
| 604 | printf("Failed to initialize PSA Crypto\n"); |
| 605 | return; |
| 606 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 607 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 608 | /* 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); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 619 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 620 | /* 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); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 663 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 664 | printf("Derived key\n"); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 665 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 666 | /* Clean up key derivation operation */ |
| 667 | psa_key_derivation_abort(&operation); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 668 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 669 | /* Destroy the keys */ |
| 670 | psa_destroy_key(derived_key); |
| 671 | psa_destroy_key(base_key); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 672 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 673 | mbedtls_psa_crypto_free(); |
| 674 | ``` |
| 675 | |
| 676 | ### Authenticating and encrypting or decrypting a message |
| 677 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 678 | Mbed Crypto provides a simple way to authenticate and encrypt with associated data (AEAD), supporting the `PSA_ALG_CCM` algorithm. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 679 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 680 | **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. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 683 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 684 | This example shows how to authenticate and encrypt a message: |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 685 | ```C |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 686 | psa_status_t status; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 687 | 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; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 701 | size_t output_size = 0; |
| 702 | size_t output_length = 0; |
| 703 | size_t tag_length = 16; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 704 | 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 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 716 | |
| 717 | output_size = sizeof(input_data) + tag_length; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 718 | output_data = (uint8_t *)malloc(output_size); |
| 719 | if (!output_data) { |
| 720 | printf("Out of memory\n"); |
| 721 | return; |
| 722 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 723 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 724 | /* 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); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 731 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 732 | /* Authenticate and encrypt */ |
| 733 | status = psa_aead_encrypt(handle, PSA_ALG_CCM, |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 734 | nonce, sizeof(nonce), |
| 735 | additional_data, sizeof(additional_data), |
| 736 | input_data, sizeof(input_data), |
| 737 | output_data, output_size, |
| 738 | &output_length); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 739 | if (status != PSA_SUCCESS) { |
| 740 | printf("Failed to authenticate and encrypt\n"); |
| 741 | return; |
| 742 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 743 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 744 | printf("Authenticated and encrypted\n"); |
| 745 | |
| 746 | /* Clean up */ |
| 747 | free(output_data); |
| 748 | |
| 749 | /* Destroy the key */ |
| 750 | psa_destroy_key(handle); |
| 751 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 752 | mbedtls_psa_crypto_free(); |
| 753 | ``` |
| 754 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 755 | This example shows how to authenticate and decrypt a message: |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 756 | |
| 757 | ```C |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 758 | psa_status_t status; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 759 | static const uint8_t key[] = { |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 760 | 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 761 | 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; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 773 | size_t output_size = 0; |
| 774 | size_t output_length = 0; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 775 | 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 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 787 | |
| 788 | output_size = sizeof(input_data); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 789 | output_data = (uint8_t *)malloc(output_size); |
| 790 | if (!output_data) { |
| 791 | printf("Out of memory\n"); |
| 792 | return; |
| 793 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 794 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 795 | /* 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); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 806 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 807 | /* Authenticate and decrypt */ |
| 808 | status = psa_aead_decrypt(handle, PSA_ALG_CCM, |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 809 | nonce, sizeof(nonce), |
| 810 | additional_data, sizeof(additional_data), |
| 811 | input_data, sizeof(input_data), |
| 812 | output_data, output_size, |
| 813 | &output_length); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 814 | if (status != PSA_SUCCESS) { |
| 815 | printf("Failed to authenticate and decrypt %ld\n", status); |
| 816 | return; |
| 817 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 818 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 819 | printf("Authenticated and decrypted\n"); |
| 820 | |
| 821 | /* Clean up */ |
| 822 | free(output_data); |
| 823 | |
| 824 | /* Destroy the key */ |
| 825 | psa_destroy_key(handle); |
| 826 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 827 | mbedtls_psa_crypto_free(); |
| 828 | ``` |
| 829 | |
| 830 | ### Generating and exporting keys |
| 831 | |
| 832 | Mbed Crypto provides a simple way to generate a key or key pair. |
| 833 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 834 | **Prerequisites to using key generation and export APIs:** |
| 835 | * Initialize the library with a successful call to `psa_crypto_init()`. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 836 | |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 837 | **To generate an ECDSA key:** |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 838 | 1. Set the desired key attributes for key generation by calling |
| 839 | `psa_set_key_algorithm()` with the chosen ECDSA algorithm (such as |
Guy Wild | 94113db | 2019-09-04 09:56:51 +0300 | [diff] [blame] | 840 | `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 Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 841 | 1. Generate a key by calling `psa_generate_key()`. |
Guy Wild | c03c0fc | 2019-09-03 13:18:04 +0300 | [diff] [blame] | 842 | 1. Export the generated public key by calling `psa_export_public_key()`: |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 843 | ```C |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 844 | enum { |
| 845 | key_bits = 256, |
| 846 | }; |
| 847 | psa_status_t status; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 848 | size_t exported_length = 0; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 849 | 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; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 852 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 853 | printf("Generate a key pair...\t"); |
| 854 | fflush(stdout); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 855 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 856 | /* Initialize PSA Crypto */ |
| 857 | status = psa_crypto_init(); |
| 858 | if (status != PSA_SUCCESS) { |
| 859 | printf("Failed to initialize PSA Crypto\n"); |
| 860 | return; |
| 861 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 862 | |
| 863 | /* Generate a key */ |
Gilles Peskine | 89d8c5c | 2019-11-26 17:01:59 +0100 | [diff] [blame] | 864 | psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 865 | psa_set_key_algorithm(&attributes, |
| 866 | PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)); |
| 867 | psa_set_key_type(&attributes, |
Gilles Peskine | 228abc5 | 2019-12-03 17:24:19 +0100 | [diff] [blame] | 868 | PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP_R1)); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 869 | 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); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 876 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 877 | 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 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 883 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 884 | printf("Exported a public key\n"); |
| 885 | |
| 886 | /* Destroy the key */ |
| 887 | psa_destroy_key(handle); |
| 888 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 889 | mbedtls_psa_crypto_free(); |
| 890 | ``` |
| 891 | |
Guy Wild | 2a9e9f7 | 2019-09-04 13:45:54 +0300 | [diff] [blame] | 892 | ### More about the PSA Crypto API |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 893 | |
Guy Wild | 94113db | 2019-09-04 09:56:51 +0300 | [diff] [blame] | 894 | For more information about the PSA Crypto API, please see the [PSA Cryptography API Specification](https://armmbed.github.io/mbed-crypto/html/index.html). |