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, |
| 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 allows security to be consistently designed in, at both a hardware and firmware level. Part of the API provided by PSA is the cryptography interface, which provides access to a set of primitives. |
| 22 | |
| 23 | ### Using Mbed Crypto |
| 24 | |
| 25 | * [Getting the Mbed Crypto library](#getting-the-mbed-crypto-library) |
| 26 | * [Building the Mbed Crypto library](#building-the-mbed-crypto-library) |
| 27 | * [Using the Mbed Crypto library](#using-the-mbed-crypto-library) |
| 28 | * [Importing a key](#importing-a-key) |
| 29 | * [Signing a message using RSA](#signing-a-message-using-RSA) |
| 30 | * [Encrypting or decrypting using symmetric ciphers](#encrypting-or-decrypting-using-symmetric-ciphers) |
| 31 | * [Hashing a message](#hashing-a-message) |
| 32 | * [Deriving a new key from an existing key](#deriving-a-new-key-from-an-existing-key) |
| 33 | * [Generating a random value](#generating-a-random-value) |
| 34 | * [Authenticating and encrypting or decrypting a message](#authenticating-and-encrypting-or-decrypting-a-message) |
| 35 | * [Generating and exporting keys](#generating-and-exporting-keys) |
| 36 | * [More about the Mbed Crypto library](#more-about-the-mbed-crypto-library) |
| 37 | |
| 38 | ### Getting the Mbed Crypto library |
| 39 | |
| 40 | Mbed Crypto releases are available in the [public Github repository]( https://github.com/ARMmbed/mbed-crypto). |
| 41 | |
| 42 | ### Building the Mbed Crypto library |
| 43 | |
| 44 | You need the following tools to build the library with the provided makefiles: |
| 45 | * GNU Make. |
| 46 | * A C toolchain (compiler, linker, archiver). |
| 47 | * Python 2 or Python 3 (either works) to generate the test code. |
| 48 | * Perl to run the tests. |
| 49 | |
| 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. |
| 51 | |
| 52 | To select a different compiler, set the `CC` variable to name or path of the compiler and linker (default: `cc`) and set `AR` to a compatible archiver (default: `ar`), such as: |
| 53 | ``` |
| 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 |
| 67 | import it. Upon importing, you'll be given a handle to refer to the key for use |
| 68 | with other function calls. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 69 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 70 | Prerequisites for importing keys: |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 71 | * Initialize the library with a successful call to `psa_crypto_init`. |
| 72 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 73 | Importing a key: |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 74 | ```C |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 75 | psa_status_t status; |
| 76 | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
| 77 | uint8_t data[] = AES_KEY; |
| 78 | psa_key_handle_t handle; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 79 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 80 | printf("Import an AES key...\t"); |
| 81 | fflush(stdout); |
| 82 | |
| 83 | /* Initialize PSA Crypto */ |
| 84 | status = psa_crypto_init(); |
| 85 | if (status != PSA_SUCCESS) { |
| 86 | printf("Failed to initialize PSA Crypto\n"); |
| 87 | return; |
| 88 | } |
| 89 | |
| 90 | /* Set key attributes */ |
| 91 | psa_set_key_usage_flags(&attributes, 0); |
| 92 | psa_set_key_algorithm(&attributes, 0); |
| 93 | psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); |
| 94 | psa_set_key_bits(&attributes, 128); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 95 | |
| 96 | /* Import the key */ |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 97 | status = psa_import_key(&attributes, data, sizeof(data), &handle); |
| 98 | if (status != PSA_SUCCESS) { |
| 99 | printf("Failed to import key\n"); |
| 100 | return; |
| 101 | } |
| 102 | printf("Imported a key\n"); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 103 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 104 | /* Free the attributes */ |
| 105 | psa_reset_key_attributes(&attributes); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 106 | |
| 107 | /* Destroy the key */ |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 108 | psa_destroy_key(handle); |
| 109 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 110 | mbedtls_psa_crypto_free(); |
| 111 | ``` |
| 112 | |
| 113 | ### Signing a message using RSA |
| 114 | |
| 115 | Mbed Crypto provides support for encrypting, decrypting, signing and verifying messages using public key signature algorithms (such as RSA or ECDSA). |
| 116 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 117 | Prerequisites for performing asymmetric signature operations: |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 118 | * Initialize the library with a successful call to `psa_crypto_init`. |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 119 | * Have a valid key with appropriate attributes set: |
| 120 | * Usage flag `PSA_KEY_USAGE_SIGN` to allow signing. |
| 121 | * Usage flag `PSA_KEY_USAGE_VERIFY` to allow signature verification. |
| 122 | * Algorithm set to desired signature algorithm. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 123 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 124 | To sign a given `hash` using RSA: |
| 125 | 1. Call `psa_asymmetric_sign()` and get the output buffer that contains the |
| 126 | signature: |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 127 | ```C |
| 128 | psa_status_t status; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 129 | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
| 130 | uint8_t key[] = RSA_KEY; |
| 131 | uint8_t hash[] = "INPUT_FOR_SIGN"; |
| 132 | uint8_t signature[PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE] = {0}; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 133 | size_t signature_length; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 134 | psa_key_handle_t handle; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 135 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 136 | printf("Sign a message...\t"); |
| 137 | fflush(stdout); |
| 138 | |
| 139 | /* Initialize PSA Crypto */ |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 140 | status = psa_crypto_init(); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 141 | if (status != PSA_SUCCESS) { |
| 142 | printf("Failed to initialize PSA Crypto\n"); |
| 143 | return; |
| 144 | } |
| 145 | |
| 146 | /* Set key attributes */ |
| 147 | psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN); |
| 148 | psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_SIGN_RAW); |
| 149 | psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR); |
| 150 | psa_set_key_bits(&attributes, 1024); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 151 | |
| 152 | /* Import the key */ |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 153 | status = psa_import_key(&attributes, key, sizeof(key), &handle); |
| 154 | if (status != PSA_SUCCESS) { |
| 155 | printf("Failed to import key\n"); |
| 156 | return; |
| 157 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 158 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 159 | /* Sign message using the key */ |
| 160 | status = psa_asymmetric_sign(handle, PSA_ALG_RSA_PKCS1V15_SIGN_RAW, |
| 161 | hash, sizeof(hash), |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 162 | signature, sizeof(signature), |
| 163 | &signature_length); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 164 | if (status != PSA_SUCCESS) { |
| 165 | printf("Failed to sign\n"); |
| 166 | return; |
| 167 | } |
| 168 | |
| 169 | printf("Signed a message\n"); |
| 170 | |
| 171 | /* Free the attributes */ |
| 172 | psa_reset_key_attributes(&attributes); |
| 173 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 174 | /* Destroy the key */ |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 175 | psa_destroy_key(handle); |
| 176 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 177 | mbedtls_psa_crypto_free(); |
| 178 | ``` |
| 179 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 180 | ### Using symmetric ciphers |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 181 | |
| 182 | Mbed Crypto provides support for encrypting and decrypting messages using various symmetric cipher algorithms (both block and stream ciphers). |
| 183 | |
| 184 | Prerequisites to working with the symmetric cipher API: |
| 185 | * Initialize the library with a successful call to `psa_crypto_init`. |
| 186 | * Configure the key policy accordingly (`PSA_KEY_USAGE_ENCRYPT` to allow encryption or `PSA_KEY_USAGE_DECRYPT` to allow decryption). |
| 187 | * Have a valid key in the key slot. |
| 188 | |
| 189 | Encrypting a message with a symmetric cipher: |
| 190 | 1. Allocate an operation (`psa_cipher_operation_t`) structure to pass to the cipher functions. |
| 191 | 1. Call `psa_cipher_encrypt_setup` to initialize the operation structure and specify the algorithm and the key to be used. |
| 192 | 1. Call either `psa_cipher_generate_iv` or `psa_cipher_set_iv` to generate or set the initialization vector (IV). We recommended `psa_cipher_generate_iv`, unless you require a specific IV value. |
| 193 | 1. Call `psa_cipher_update` one or more times, passing either the whole or only a fragment of the message each time. |
| 194 | 1. Call `psa_cipher_finish` to end the operation and output the encrypted message. |
| 195 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 196 | Encrypting data using an AES key in cipher block chain (CBC) mode with no padding (assuming all prerequisites have been fulfilled): |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 197 | ```c |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 198 | enum { |
| 199 | block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES), |
| 200 | }; |
| 201 | psa_status_t status; |
| 202 | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 203 | psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 204 | uint8_t plaintext[block_size] = SOME_PLAINTEXT; |
| 205 | uint8_t iv[block_size]; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 206 | size_t iv_len; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 207 | uint8_t key[] = AES_KEY; |
| 208 | uint8_t output[block_size]; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 209 | size_t output_len; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 210 | psa_key_handle_t handle; |
| 211 | psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 212 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 213 | printf("Encrypt with cipher...\t"); |
| 214 | fflush(stdout); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 215 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 216 | /* Initialize PSA Crypto */ |
| 217 | status = psa_crypto_init(); |
| 218 | if (status != PSA_SUCCESS) |
| 219 | { |
| 220 | printf("Failed to initialize PSA Crypto\n"); |
| 221 | return; |
| 222 | } |
| 223 | |
| 224 | /* Import a key */ |
| 225 | psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); |
| 226 | psa_set_key_algorithm(&attributes, alg); |
| 227 | psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); |
| 228 | psa_set_key_bits(&attributes, 128); |
| 229 | status = psa_import_key(&attributes, key, sizeof(key), &handle); |
| 230 | if (status != PSA_SUCCESS) { |
| 231 | printf("Failed to import a key\n"); |
| 232 | return; |
| 233 | } |
| 234 | psa_reset_key_attributes(&attributes); |
| 235 | |
| 236 | /* Encrypt the plaintext */ |
| 237 | status = psa_cipher_encrypt_setup(&operation, handle, alg); |
| 238 | if (status != PSA_SUCCESS) { |
| 239 | printf("Failed to begin cipher operation\n"); |
| 240 | return; |
| 241 | } |
| 242 | status = psa_cipher_generate_iv(&operation, iv, sizeof(iv), &iv_len); |
| 243 | if (status != PSA_SUCCESS) { |
| 244 | printf("Failed to generate IV\n"); |
| 245 | return; |
| 246 | } |
| 247 | status = psa_cipher_update(&operation, plaintext, sizeof(plaintext), |
| 248 | output, sizeof(output), &output_len); |
| 249 | if (status != PSA_SUCCESS) { |
| 250 | printf("Failed to update cipher operation\n"); |
| 251 | return; |
| 252 | } |
| 253 | status = psa_cipher_finish(&operation, output + output_len, |
| 254 | sizeof(output) - output_len, &output_len); |
| 255 | if (status != PSA_SUCCESS) { |
| 256 | printf("Failed to finish cipher operation\n"); |
| 257 | return; |
| 258 | } |
| 259 | printf("Encrypted plaintext\n"); |
| 260 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 261 | /* Clean up cipher operation context */ |
| 262 | psa_cipher_abort(&operation); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 263 | |
| 264 | /* Destroy the key */ |
| 265 | psa_destroy_key(handle); |
| 266 | |
| 267 | mbedtls_psa_crypto_free(); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 268 | ``` |
| 269 | |
| 270 | Decrypting a message with a symmetric cipher: |
| 271 | 1. Allocate an operation (`psa_cipher_operation_t`) structure to pass to the cipher functions. |
| 272 | 1. Call `psa_cipher_decrypt_setup` to initialize the operation structure and to specify the algorithm and the key to be used. |
| 273 | 1. Call `psa_cipher_set_iv` with the IV for the decryption. |
| 274 | 1. Call `psa_cipher_update` one or more times passing either the whole or only a fragment of the message each time. |
| 275 | 1. Call `psa_cipher_finish` to end the operation and output the decrypted message. |
| 276 | |
| 277 | Decrypting encrypted data using an AES key in CBC mode with no padding |
| 278 | (assuming all prerequisites have been fulfilled): |
| 279 | ```c |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 280 | enum { |
| 281 | block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES), |
| 282 | }; |
| 283 | psa_status_t status; |
| 284 | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 285 | psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 286 | psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; |
| 287 | uint8_t ciphertext[block_size] = SOME_CIPHERTEXT; |
| 288 | uint8_t iv[block_size] = ENCRYPTED_WITH_IV; |
| 289 | uint8_t key[] = AES_KEY; |
| 290 | uint8_t output[block_size]; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 291 | size_t output_len; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 292 | psa_key_handle_t handle; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 293 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 294 | printf("Decrypt with cipher...\t"); |
| 295 | fflush(stdout); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 296 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 297 | /* Initialize PSA Crypto */ |
| 298 | status = psa_crypto_init(); |
| 299 | if (status != PSA_SUCCESS) |
| 300 | { |
| 301 | printf("Failed to initialize PSA Crypto\n"); |
| 302 | return; |
| 303 | } |
| 304 | |
| 305 | /* Import a key */ |
| 306 | psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT); |
| 307 | psa_set_key_algorithm(&attributes, alg); |
| 308 | psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); |
| 309 | psa_set_key_bits(&attributes, 128); |
| 310 | status = psa_import_key(&attributes, key, sizeof(key), &handle); |
| 311 | if (status != PSA_SUCCESS) { |
| 312 | printf("Failed to import a key\n"); |
| 313 | return; |
| 314 | } |
| 315 | psa_reset_key_attributes(&attributes); |
| 316 | |
| 317 | /* Decrypt the ciphertext */ |
| 318 | status = psa_cipher_decrypt_setup(&operation, handle, alg); |
| 319 | if (status != PSA_SUCCESS) { |
| 320 | printf("Failed to begin cipher operation\n"); |
| 321 | return; |
| 322 | } |
| 323 | status = psa_cipher_set_iv(&operation, iv, sizeof(iv)); |
| 324 | if (status != PSA_SUCCESS) { |
| 325 | printf("Failed to set IV\n"); |
| 326 | return; |
| 327 | } |
| 328 | status = psa_cipher_update(&operation, ciphertext, sizeof(ciphertext), |
| 329 | output, sizeof(output), &output_len); |
| 330 | if (status != PSA_SUCCESS) { |
| 331 | printf("Failed to update cipher operation\n"); |
| 332 | return; |
| 333 | } |
| 334 | status = psa_cipher_finish(&operation, output + output_len, |
| 335 | sizeof(output) - output_len, &output_len); |
| 336 | if (status != PSA_SUCCESS) { |
| 337 | printf("Failed to finish cipher operation\n"); |
| 338 | return; |
| 339 | } |
| 340 | printf("Decrypted ciphertext\n"); |
| 341 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 342 | /* Clean up cipher operation context */ |
| 343 | psa_cipher_abort(&operation); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 344 | |
| 345 | /* Destroy the key */ |
| 346 | psa_destroy_key(handle); |
| 347 | |
| 348 | mbedtls_psa_crypto_free(); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 349 | ``` |
| 350 | |
| 351 | #### Handling cipher operation contexts |
| 352 | |
| 353 | Once you've initialized the operation structure with a successful call to `psa_cipher_encrypt_setup` or `psa_cipher_decrypt_setup`, you can terminate the operation at any time by calling `psa_cipher_abort`. |
| 354 | |
| 355 | The call to `psa_cipher_abort` frees any resources associated with the operation (except for the operation structure itself). An implicit call to `psa_cipher_abort` occurs when any of these conditions occur: |
| 356 | * A call to `psa_cipher_generate_iv`, `psa_cipher_set_iv` or `psa_cipher_update` has failed (returning any status other than `PSA_SUCCESS`). |
| 357 | * Either a successful or failed call to `psa_cipher_finish`. |
| 358 | |
| 359 | Once `psa_cipher_abort` has been called (either implicitly by the implementation or explicitly by the user), the operation structure is invalidated and may not be reused for the same operation. However, the operation structure may be reused for a different operation by calling either `psa_cipher_encrypt_setup` or `psa_cipher_decrypt_setup` again. |
| 360 | |
| 361 | For an operation that has been initialized successfully (by a successful call to `psa_cipher_encrypt_setup` or `psa_cipher_decrypt_setup`) it is imperative that at some time `psa_cipher_abort` is called. |
| 362 | |
| 363 | Multiple sequential calls to `psa_cipher_abort` on an operation that has already been terminated (either implicitly or explicitly) are safe and have no effect. |
| 364 | |
| 365 | ### Hashing a message |
| 366 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 367 | Mbed Crypto lets you compute and verify hashes using various hashing |
| 368 | algorithms. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 369 | |
| 370 | Prerequisites to working with the hash APIs: |
| 371 | * Initialize the library with a successful call to `psa_crypto_init`. |
| 372 | |
| 373 | To calculate a hash: |
| 374 | 1. Allocate an operation structure (`psa_hash_operation_t`) to pass to the hash functions. |
| 375 | 1. Call `psa_hash_setup` to initialize the operation structure and specify the hash algorithm. |
| 376 | 1. Call `psa_hash_update` one or more times, passing either the whole or only a fragment of the message each time. |
| 377 | 1. Call `psa_hash_finish` to calculate the hash, or `psa_hash_verify` to compare the computed hash with an expected hash value. |
| 378 | |
| 379 | Calculate the `SHA-256` hash of a message: |
| 380 | ```c |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 381 | psa_status_t status; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 382 | psa_algorithm_t alg = PSA_ALG_SHA_256; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 383 | psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 384 | unsigned char input[] = { 'a', 'b', 'c' }; |
| 385 | unsigned char actual_hash[PSA_HASH_MAX_SIZE]; |
| 386 | size_t actual_hash_len; |
| 387 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 388 | printf("Hash a message...\t"); |
| 389 | fflush(stdout); |
| 390 | |
| 391 | /* Initialize PSA Crypto */ |
| 392 | status = psa_crypto_init(); |
| 393 | if (status != PSA_SUCCESS) { |
| 394 | printf("Failed to initialize PSA Crypto\n"); |
| 395 | return; |
| 396 | } |
| 397 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 398 | /* Compute hash of message */ |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 399 | status = psa_hash_setup(&operation, alg); |
| 400 | if (status != PSA_SUCCESS) { |
| 401 | printf("Failed to begin hash operation\n"); |
| 402 | return; |
| 403 | } |
| 404 | status = psa_hash_update(&operation, input, sizeof(input)); |
| 405 | if (status != PSA_SUCCESS) { |
| 406 | printf("Failed to update hash operation\n"); |
| 407 | return; |
| 408 | } |
| 409 | status = psa_hash_finish(&operation, actual_hash, sizeof(actual_hash), |
| 410 | &actual_hash_len); |
| 411 | if (status != PSA_SUCCESS) { |
| 412 | printf("Failed to finish hash operation\n"); |
| 413 | return; |
| 414 | } |
| 415 | |
| 416 | printf("Hashed a message\n"); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 417 | |
| 418 | /* Clean up hash operation context */ |
| 419 | psa_hash_abort(&operation); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 420 | |
| 421 | mbedtls_psa_crypto_free(); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 422 | ``` |
| 423 | |
| 424 | Verify the `SHA-256` hash of a message: |
| 425 | ```c |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 426 | psa_status_t status; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 427 | psa_algorithm_t alg = PSA_ALG_SHA_256; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 428 | psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 429 | unsigned char input[] = { 'a', 'b', 'c' }; |
| 430 | unsigned char expected_hash[] = { |
| 431 | 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, |
| 432 | 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, |
| 433 | 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad |
| 434 | }; |
| 435 | size_t expected_hash_len = PSA_HASH_SIZE(alg); |
| 436 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 437 | printf("Verify a hash...\t"); |
| 438 | fflush(stdout); |
| 439 | |
| 440 | /* Initialize PSA Crypto */ |
| 441 | status = psa_crypto_init(); |
| 442 | if (status != PSA_SUCCESS) { |
| 443 | printf("Failed to initialize PSA Crypto\n"); |
| 444 | return; |
| 445 | } |
| 446 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 447 | /* Verify message hash */ |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 448 | status = psa_hash_setup(&operation, alg); |
| 449 | if (status != PSA_SUCCESS) { |
| 450 | printf("Failed to begin hash operation\n"); |
| 451 | return; |
| 452 | } |
| 453 | status = psa_hash_update(&operation, input, sizeof(input)); |
| 454 | if (status != PSA_SUCCESS) { |
| 455 | printf("Failed to update hash operation\n"); |
| 456 | return; |
| 457 | } |
| 458 | status = psa_hash_verify(&operation, expected_hash, expected_hash_len); |
| 459 | if (status != PSA_SUCCESS) { |
| 460 | printf("Failed to verify hash\n"); |
| 461 | return; |
| 462 | } |
| 463 | |
| 464 | printf("Verified a hash\n"); |
| 465 | |
| 466 | /* Clean up hash operation context */ |
| 467 | psa_hash_abort(&operation); |
| 468 | |
| 469 | mbedtls_psa_crypto_free(); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 470 | ``` |
| 471 | |
| 472 | The API provides the macro `PSA_HASH_SIZE`, which returns the expected hash length (in bytes) for the specified algorithm. |
| 473 | |
| 474 | #### Handling hash operation contexts |
| 475 | |
| 476 | Once the operation structure has been successfully initialized by a successful call to `psa_hash_setup`, it's possible to terminate the operation at any time by calling `psa_hash_abort`. The call to `psa_hash_abort` frees any resources associated with the operation (except for the operation structure itself). |
| 477 | |
| 478 | An implicit call to `psa_hash_abort` occurs when any of these conditions occur: |
| 479 | 1. A call to `psa_hash_update` has failed (returning any status other than `PSA_SUCCESS`). |
| 480 | 1. Either a successful or failed call to `psa_hash_finish`. |
| 481 | 1. Either a successful or failed call to `psa_hash_verify`. |
| 482 | |
| 483 | Once `psa_hash_abort` has been called (either implicitly by the implementation or explicitly by the user), the operation structure is invalidated and may not be reused for the same operation. However, the operation structure may be reused for a different operation by calling `psa_hash_setup` again. |
| 484 | |
| 485 | For an operation that has been initialized successfully (by a successful call to `psa_hash_setup`) it is imperative that at some time `psa_hash_abort` is called. |
| 486 | |
| 487 | 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. |
| 488 | |
| 489 | ### Generating a random value |
| 490 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 491 | Mbed Crypto can generate random data. To generate a random key, use |
| 492 | `psa_generate_key()` instead of `psa_generate_random()` |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 493 | |
| 494 | Prerequisites to random generation: |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 495 | * Initialize the library with a successful call to `psa_crypto_init()`. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 496 | |
| 497 | Generate a random, ten-byte piece of data: |
| 498 | 1. Generate random bytes by calling `psa_generate_random()`: |
| 499 | ```C |
| 500 | psa_status_t status; |
| 501 | uint8_t random[10] = { 0 }; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 502 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 503 | printf("Generate random...\t"); |
| 504 | fflush(stdout); |
| 505 | |
| 506 | /* Initialize PSA Crypto */ |
| 507 | status = psa_crypto_init(); |
| 508 | if (status != PSA_SUCCESS) { |
| 509 | printf("Failed to initialize PSA Crypto\n"); |
| 510 | return; |
| 511 | } |
| 512 | |
| 513 | status = psa_generate_random(random, sizeof(random)); |
| 514 | if (status != PSA_SUCCESS) { |
| 515 | printf("Failed to generate a random value\n"); |
| 516 | return; |
| 517 | } |
| 518 | |
| 519 | printf("Generated random data\n"); |
| 520 | |
| 521 | /* Clean up */ |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 522 | mbedtls_psa_crypto_free(); |
| 523 | ``` |
| 524 | |
| 525 | ### Deriving a new key from an existing key |
| 526 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 527 | Mbed Crypto provides a key derivation API that lets you derive new keys from |
| 528 | existing ones. The key derivation API has functions to take inputs, including |
| 529 | other keys and data, and functions to generate outputs, such as new keys or |
| 530 | other data. A key derivation context must first be initialized and set up, |
| 531 | provided with a key and optionally other data, and then derived data can be |
| 532 | read from it either to a buffer or directly sent to a key slot. Refer to the |
| 533 | documentation for the particular algorithm (such as HKDF or the TLS1.2 PRF) for |
| 534 | information on which inputs to pass when and when you can obtain which outputs. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 535 | |
| 536 | Prerequisites to working with the key derivation APIs: |
| 537 | * Initialize the library with a successful call to `psa_crypto_init`. |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 538 | * Use a key with the appropriate attributes set: |
| 539 | * Usage flags set for key derivation (`PSA_KEY_USAGE_DERIVE`) |
| 540 | * Key type set to `PSA_KEY_TYPE_DERIVE`. |
| 541 | * Algorithm set to a key derivation algorithm |
| 542 | (`PSA_ALG_HKDF(PSA_ALG_SHA_256)`). |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 543 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 544 | Deriving a new AES-CTR 128-bit encryption key into a given key slot using HKDF |
| 545 | with a given key, salt and info: |
| 546 | 1. Set up the key derivation context using the `psa_key_derivation_setup` |
| 547 | function, specifying the derivation algorithm `PSA_ALG_HKDF(PSA_ALG_SHA_256)`. |
| 548 | 1. Provide an optional salt with `psa_key_derivation_input_bytes`. |
| 549 | 1. Provide info with `psa_key_derivation_input_bytes`. |
| 550 | 1. Provide secret with `psa_key_derivation_input_key`, referencing a key that |
| 551 | can be used for key derivation. |
| 552 | 1. Set the key attributes desired for the new derived key. We'll set |
| 553 | `PSA_KEY_USAGE_ENCRYPT` parameter and the algorithm `PSA_ALG_CTR` for this |
| 554 | example. |
| 555 | 1. Derive the key by calling `psa_key_derivation_output_key()`. |
| 556 | 1. Clean up the key derivation context. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 557 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 558 | At this point the derived key slot holds a new 128-bit AES-CTR encryption key |
| 559 | derived from the key, salt and info provided: |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 560 | ```C |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 561 | psa_status_t status; |
| 562 | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
| 563 | static const unsigned char key[] = { |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 564 | 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, |
| 565 | 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, |
| 566 | 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, |
| 567 | 0x0b }; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 568 | static const unsigned char salt[] = { |
| 569 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, |
| 570 | 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }; |
| 571 | static const unsigned char info[] = { |
| 572 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, |
| 573 | 0xf7, 0xf8, 0xf9 }; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 574 | psa_algorithm_t alg = PSA_ALG_HKDF(PSA_ALG_SHA_256); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 575 | psa_key_derivation_operation_t operation = |
| 576 | PSA_KEY_DERIVATION_OPERATION_INIT; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 577 | size_t derived_bits = 128; |
| 578 | size_t capacity = PSA_BITS_TO_BYTES(derived_bits); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 579 | psa_key_handle_t base_key; |
| 580 | psa_key_handle_t derived_key; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 581 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 582 | printf("Derive a key (HKDF)...\t"); |
| 583 | fflush(stdout); |
| 584 | |
| 585 | /* Initialize PSA Crypto */ |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 586 | status = psa_crypto_init(); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 587 | if (status != PSA_SUCCESS) { |
| 588 | printf("Failed to initialize PSA Crypto\n"); |
| 589 | return; |
| 590 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 591 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 592 | /* Import a key for use in key derivation. If such a key has already been |
| 593 | * generated or imported, you can skip this part. */ |
| 594 | psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); |
| 595 | psa_set_key_algorithm(&attributes, alg); |
| 596 | psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE); |
| 597 | status = psa_import_key(&attributes, key, sizeof(key), &base_key); |
| 598 | if (status != PSA_SUCCESS) { |
| 599 | printf("Failed to import a key\n"); |
| 600 | return; |
| 601 | } |
| 602 | psa_reset_key_attributes(&attributes); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 603 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 604 | /* Derive a key */ |
| 605 | status = psa_key_derivation_setup(&operation, alg); |
| 606 | if (status != PSA_SUCCESS) { |
| 607 | printf("Failed to begin key derivation\n"); |
| 608 | return; |
| 609 | } |
| 610 | status = psa_key_derivation_set_capacity(&operation, capacity); |
| 611 | if (status != PSA_SUCCESS) { |
| 612 | printf("Failed to set capacity\n"); |
| 613 | return; |
| 614 | } |
| 615 | status = psa_key_derivation_input_bytes(&operation, |
| 616 | PSA_KEY_DERIVATION_INPUT_SALT, |
| 617 | salt, sizeof(salt)); |
| 618 | if (status != PSA_SUCCESS) { |
| 619 | printf("Failed to input salt (extract)\n"); |
| 620 | return; |
| 621 | } |
| 622 | status = psa_key_derivation_input_key(&operation, |
| 623 | PSA_KEY_DERIVATION_INPUT_SECRET, |
| 624 | base_key); |
| 625 | if (status != PSA_SUCCESS) { |
| 626 | printf("Failed to input key (extract)\n"); |
| 627 | return; |
| 628 | } |
| 629 | status = psa_key_derivation_input_bytes(&operation, |
| 630 | PSA_KEY_DERIVATION_INPUT_INFO, |
| 631 | info, sizeof(info)); |
| 632 | if (status != PSA_SUCCESS) { |
| 633 | printf("Failed to input info (expand)\n"); |
| 634 | return; |
| 635 | } |
| 636 | psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); |
| 637 | psa_set_key_algorithm(&attributes, PSA_ALG_CTR); |
| 638 | psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); |
| 639 | psa_set_key_bits(&attributes, 128); |
| 640 | status = psa_key_derivation_output_key(&attributes, &operation, |
| 641 | &derived_key); |
| 642 | if (status != PSA_SUCCESS) { |
| 643 | printf("Failed to derive key\n"); |
| 644 | return; |
| 645 | } |
| 646 | psa_reset_key_attributes(&attributes); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 647 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 648 | printf("Derived key\n"); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 649 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 650 | /* Clean up key derivation operation */ |
| 651 | psa_key_derivation_abort(&operation); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 652 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 653 | /* Destroy the keys */ |
| 654 | psa_destroy_key(derived_key); |
| 655 | psa_destroy_key(base_key); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 656 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 657 | mbedtls_psa_crypto_free(); |
| 658 | ``` |
| 659 | |
| 660 | ### Authenticating and encrypting or decrypting a message |
| 661 | |
| 662 | Mbed Crypto provides a simple way for authenticate and encrypt with associated data (AEAD) supporting `PSA_ALG_CCM` algorithm. |
| 663 | |
| 664 | Prerequisites to working with the AEAD ciphers APIs: |
| 665 | * Initialize the library with a successful call to `psa_crypto_init`. |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 666 | * The key attributes for the key used for derivation must have usage flags |
| 667 | `PSA_KEY_USAGE_ENCRYPT` or `PSA_KEY_USAGE_DECRYPT`. |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 668 | |
| 669 | To authenticate and encrypt a message: |
| 670 | ```C |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 671 | psa_status_t status; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 672 | static const uint8_t key[] = { |
| 673 | 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, |
| 674 | 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF }; |
| 675 | static const uint8_t nonce[] = { |
| 676 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 677 | 0x08, 0x09, 0x0A, 0x0B }; |
| 678 | static const uint8_t additional_data[] = { |
| 679 | 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25, |
| 680 | 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 }; |
| 681 | static const uint8_t input_data[] = { |
| 682 | 0xB9, 0x6B, 0x49, 0xE2, 0x1D, 0x62, 0x17, 0x41, |
| 683 | 0x63, 0x28, 0x75, 0xDB, 0x7F, 0x6C, 0x92, 0x43, |
| 684 | 0xD2, 0xD7, 0xC2 }; |
| 685 | uint8_t *output_data = NULL; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 686 | size_t output_size = 0; |
| 687 | size_t output_length = 0; |
| 688 | size_t tag_length = 16; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 689 | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
| 690 | psa_key_handle_t handle; |
| 691 | |
| 692 | printf("Authenticate encrypt...\t"); |
| 693 | fflush(stdout); |
| 694 | |
| 695 | /* Initialize PSA Crypto */ |
| 696 | status = psa_crypto_init(); |
| 697 | if (status != PSA_SUCCESS) { |
| 698 | printf("Failed to initialize PSA Crypto\n"); |
| 699 | return; |
| 700 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 701 | |
| 702 | output_size = sizeof(input_data) + tag_length; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 703 | output_data = (uint8_t *)malloc(output_size); |
| 704 | if (!output_data) { |
| 705 | printf("Out of memory\n"); |
| 706 | return; |
| 707 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 708 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 709 | /* Import a key */ |
| 710 | psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); |
| 711 | psa_set_key_algorithm(&attributes, PSA_ALG_CCM); |
| 712 | psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); |
| 713 | psa_set_key_bits(&attributes, 128); |
| 714 | status = psa_import_key(&attributes, key, sizeof(key), &handle); |
| 715 | psa_reset_key_attributes(&attributes); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 716 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 717 | /* Authenticate and encrypt */ |
| 718 | status = psa_aead_encrypt(handle, PSA_ALG_CCM, |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 719 | nonce, sizeof(nonce), |
| 720 | additional_data, sizeof(additional_data), |
| 721 | input_data, sizeof(input_data), |
| 722 | output_data, output_size, |
| 723 | &output_length); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 724 | if (status != PSA_SUCCESS) { |
| 725 | printf("Failed to authenticate and encrypt\n"); |
| 726 | return; |
| 727 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 728 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 729 | printf("Authenticated and encrypted\n"); |
| 730 | |
| 731 | /* Clean up */ |
| 732 | free(output_data); |
| 733 | |
| 734 | /* Destroy the key */ |
| 735 | psa_destroy_key(handle); |
| 736 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 737 | mbedtls_psa_crypto_free(); |
| 738 | ``` |
| 739 | |
| 740 | To authenticate and decrypt a message: |
| 741 | |
| 742 | ```C |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 743 | psa_status_t status; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 744 | static const uint8_t key[] = { |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 745 | 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 746 | 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF }; |
| 747 | static const uint8_t nonce[] = { |
| 748 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 749 | 0x08, 0x09, 0x0A, 0x0B }; |
| 750 | static const uint8_t additional_data[] = { |
| 751 | 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25, |
| 752 | 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 }; |
| 753 | static const uint8_t input_data[] = { |
| 754 | 0x20, 0x30, 0xE0, 0x36, 0xED, 0x09, 0xA0, 0x45, 0xAF, 0x3C, 0xBA, 0xEE, |
| 755 | 0x0F, 0xC8, 0x48, 0xAF, 0xCD, 0x89, 0x54, 0xF4, 0xF6, 0x3F, 0x28, 0x9A, |
| 756 | 0xA1, 0xDD, 0xB2, 0xB8, 0x09, 0xCD, 0x7C, 0xE1, 0x46, 0xE9, 0x98 }; |
| 757 | uint8_t *output_data = NULL; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 758 | size_t output_size = 0; |
| 759 | size_t output_length = 0; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 760 | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
| 761 | psa_key_handle_t handle; |
| 762 | |
| 763 | printf("Authenticate decrypt...\t"); |
| 764 | fflush(stdout); |
| 765 | |
| 766 | /* Initialize PSA Crypto */ |
| 767 | status = psa_crypto_init(); |
| 768 | if (status != PSA_SUCCESS) { |
| 769 | printf("Failed to initialize PSA Crypto\n"); |
| 770 | return; |
| 771 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 772 | |
| 773 | output_size = sizeof(input_data); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 774 | output_data = (uint8_t *)malloc(output_size); |
| 775 | if (!output_data) { |
| 776 | printf("Out of memory\n"); |
| 777 | return; |
| 778 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 779 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 780 | /* Import a key */ |
| 781 | psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT); |
| 782 | psa_set_key_algorithm(&attributes, PSA_ALG_CCM); |
| 783 | psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); |
| 784 | psa_set_key_bits(&attributes, 128); |
| 785 | status = psa_import_key(&attributes, key, sizeof(key), &handle); |
| 786 | if (status != PSA_SUCCESS) { |
| 787 | printf("Failed to import a key\n"); |
| 788 | return; |
| 789 | } |
| 790 | psa_reset_key_attributes(&attributes); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 791 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 792 | /* Authenticate and decrypt */ |
| 793 | status = psa_aead_decrypt(handle, PSA_ALG_CCM, |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 794 | nonce, sizeof(nonce), |
| 795 | additional_data, sizeof(additional_data), |
| 796 | input_data, sizeof(input_data), |
| 797 | output_data, output_size, |
| 798 | &output_length); |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 799 | if (status != PSA_SUCCESS) { |
| 800 | printf("Failed to authenticate and decrypt %ld\n", status); |
| 801 | return; |
| 802 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 803 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 804 | printf("Authenticated and decrypted\n"); |
| 805 | |
| 806 | /* Clean up */ |
| 807 | free(output_data); |
| 808 | |
| 809 | /* Destroy the key */ |
| 810 | psa_destroy_key(handle); |
| 811 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 812 | mbedtls_psa_crypto_free(); |
| 813 | ``` |
| 814 | |
| 815 | ### Generating and exporting keys |
| 816 | |
| 817 | Mbed Crypto provides a simple way to generate a key or key pair. |
| 818 | |
| 819 | Prerequisites to using key generation and export APIs: |
| 820 | * Initialize the library with a successful call to `psa_crypto_init`. |
| 821 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 822 | Generate an ECDSA key: |
| 823 | 1. Set the desired key attributes for key generation by calling |
| 824 | `psa_set_key_algorithm()` with the chosen ECDSA algorithm (such as |
| 825 | `PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)`). We don't set |
| 826 | `PSA_KEY_USAGE_EXPORT` as we only want to export the public key, not the key |
| 827 | pair (or private key). |
| 828 | 1. Generate a key by calling `psa_generate_key()`. |
| 829 | 1. Export the generated public key by calling `psa_export_public_key()` |
| 830 | : |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 831 | ```C |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 832 | enum { |
| 833 | key_bits = 256, |
| 834 | }; |
| 835 | psa_status_t status; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 836 | size_t exported_length = 0; |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 837 | static uint8_t exported[PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits)]; |
| 838 | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
| 839 | psa_key_handle_t handle; |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 840 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 841 | printf("Generate a key pair...\t"); |
| 842 | fflush(stdout); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 843 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 844 | /* Initialize PSA Crypto */ |
| 845 | status = psa_crypto_init(); |
| 846 | if (status != PSA_SUCCESS) { |
| 847 | printf("Failed to initialize PSA Crypto\n"); |
| 848 | return; |
| 849 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 850 | |
| 851 | /* Generate a key */ |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 852 | psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN); |
| 853 | psa_set_key_algorithm(&attributes, |
| 854 | PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)); |
| 855 | psa_set_key_type(&attributes, |
| 856 | PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1)); |
| 857 | psa_set_key_bits(&attributes, key_bits); |
| 858 | status = psa_generate_key(&attributes, &handle); |
| 859 | if (status != PSA_SUCCESS) { |
| 860 | printf("Failed to generate key\n"); |
| 861 | return; |
| 862 | } |
| 863 | psa_reset_key_attributes(&attributes); |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 864 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 865 | status = psa_export_public_key(handle, exported, sizeof(exported), |
| 866 | &exported_length); |
| 867 | if (status != PSA_SUCCESS) { |
| 868 | printf("Failed to export public key %ld\n", status); |
| 869 | return; |
| 870 | } |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 871 | |
Jaeden Amero | 884738a | 2019-08-16 17:58:31 +0100 | [diff] [blame] | 872 | printf("Exported a public key\n"); |
| 873 | |
| 874 | /* Destroy the key */ |
| 875 | psa_destroy_key(handle); |
| 876 | |
mohammad1603 | 87a7eeb | 2018-11-01 11:25:49 +0200 | [diff] [blame] | 877 | mbedtls_psa_crypto_free(); |
| 878 | ``` |
| 879 | |
| 880 | ### More about the Mbed Crypto library |
| 881 | |
| 882 | More information on [Mbed Crypto](https://github.com/ARMmbed/mbed-crypto/). |
| 883 | |
| 884 | More information on [PSA Crypto](https://github.com/ARMmbed/mbed-crypto/blob/development/docs/PSA_Crypto_API_Overview.pdf). |