aead_demo.c (9733B)
1 /** 2 * PSA API multi-part AEAD demonstration. 3 * 4 * This program AEAD-encrypts a message, using the algorithm and key size 5 * specified on the command line, using the multi-part API. 6 * 7 * It comes with a companion program cipher/cipher_aead_demo.c, which does the 8 * same operations with the legacy Cipher API. The goal is that comparing the 9 * two programs will help people migrating to the PSA Crypto API. 10 * 11 * When used with multi-part AEAD operations, the `mbedtls_cipher_context` 12 * serves a triple purpose (1) hold the key, (2) store the algorithm when no 13 * operation is active, and (3) save progress information for the current 14 * operation. With PSA those roles are held by disinct objects: (1) a 15 * psa_key_id_t to hold the key, a (2) psa_algorithm_t to represent the 16 * algorithm, and (3) a psa_operation_t for multi-part progress. 17 * 18 * On the other hand, with PSA, the algorithms encodes the desired tag length; 19 * with Cipher the desired tag length needs to be tracked separately. 20 * 21 * This program and its companion cipher/cipher_aead_demo.c illustrate this by 22 * doing the same sequence of multi-part AEAD computation with both APIs; 23 * looking at the two side by side should make the differences and 24 * similarities clear. 25 */ 26 27 /* 28 * Copyright The Mbed TLS Contributors 29 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 30 */ 31 32 /* First include Mbed TLS headers to get the Mbed TLS configuration and 33 * platform definitions that we'll use in this program. Also include 34 * standard C headers for functions we'll use here. */ 35 #include "mbedtls/build_info.h" 36 37 #include "psa/crypto.h" 38 39 #include <stdlib.h> 40 #include <stdio.h> 41 #include <string.h> 42 43 /* If the build options we need are not enabled, compile a placeholder. */ 44 #if !defined(MBEDTLS_PSA_CRYPTO_C) || \ 45 !defined(MBEDTLS_AES_C) || !defined(MBEDTLS_GCM_C) || \ 46 !defined(MBEDTLS_CHACHAPOLY_C) || \ 47 defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER) 48 int main(void) 49 { 50 printf("MBEDTLS_PSA_CRYPTO_C and/or " 51 "MBEDTLS_AES_C and/or MBEDTLS_GCM_C and/or " 52 "MBEDTLS_CHACHAPOLY_C not defined, and/or " 53 "MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER defined\r\n"); 54 return 0; 55 } 56 #else 57 58 /* The real program starts here. */ 59 60 const char usage[] = 61 "Usage: aead_demo [aes128-gcm|aes256-gcm|aes128-gcm_8|chachapoly]"; 62 63 /* Dummy data for encryption: IV/nonce, additional data, 2-part message */ 64 const unsigned char iv1[12] = { 0x00 }; 65 const unsigned char add_data1[] = { 0x01, 0x02 }; 66 const unsigned char msg1_part1[] = { 0x03, 0x04 }; 67 const unsigned char msg1_part2[] = { 0x05, 0x06, 0x07 }; 68 69 /* Dummy data (2nd message) */ 70 const unsigned char iv2[12] = { 0x10 }; 71 const unsigned char add_data2[] = { 0x11, 0x12 }; 72 const unsigned char msg2_part1[] = { 0x13, 0x14 }; 73 const unsigned char msg2_part2[] = { 0x15, 0x16, 0x17 }; 74 75 /* Maximum total size of the messages */ 76 #define MSG1_SIZE (sizeof(msg1_part1) + sizeof(msg1_part2)) 77 #define MSG2_SIZE (sizeof(msg2_part1) + sizeof(msg2_part2)) 78 #define MSG_MAX_SIZE (MSG1_SIZE > MSG2_SIZE ? MSG1_SIZE : MSG2_SIZE) 79 80 /* Dummy key material - never do this in production! 81 * 32-byte is enough to all the key size supported by this program. */ 82 const unsigned char key_bytes[32] = { 0x2a }; 83 84 /* Print the contents of a buffer in hex */ 85 static void print_buf(const char *title, uint8_t *buf, size_t len) 86 { 87 printf("%s:", title); 88 for (size_t i = 0; i < len; i++) { 89 printf(" %02x", buf[i]); 90 } 91 printf("\n"); 92 } 93 94 /* Run a PSA function and bail out if it fails. 95 * The symbolic name of the error code can be recovered using: 96 * programs/psa/psa_constant_name status <value> */ 97 #define PSA_CHECK(expr) \ 98 do \ 99 { \ 100 status = (expr); \ 101 if (status != PSA_SUCCESS) \ 102 { \ 103 printf("Error %d at line %d: %s\n", \ 104 (int) status, \ 105 __LINE__, \ 106 #expr); \ 107 goto exit; \ 108 } \ 109 } \ 110 while (0) 111 112 /* 113 * Prepare encryption material: 114 * - interpret command-line argument 115 * - set up key 116 * - outputs: key and algorithm, which together hold all the information 117 */ 118 static psa_status_t aead_prepare(const char *info, 119 psa_key_id_t *key, 120 psa_algorithm_t *alg) 121 { 122 psa_status_t status; 123 124 /* Convert arg to alg + key_bits + key_type */ 125 size_t key_bits; 126 psa_key_type_t key_type; 127 if (strcmp(info, "aes128-gcm") == 0) { 128 *alg = PSA_ALG_GCM; 129 key_bits = 128; 130 key_type = PSA_KEY_TYPE_AES; 131 } else if (strcmp(info, "aes256-gcm") == 0) { 132 *alg = PSA_ALG_GCM; 133 key_bits = 256; 134 key_type = PSA_KEY_TYPE_AES; 135 } else if (strcmp(info, "aes128-gcm_8") == 0) { 136 *alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, 8); 137 key_bits = 128; 138 key_type = PSA_KEY_TYPE_AES; 139 } else if (strcmp(info, "chachapoly") == 0) { 140 *alg = PSA_ALG_CHACHA20_POLY1305; 141 key_bits = 256; 142 key_type = PSA_KEY_TYPE_CHACHA20; 143 } else { 144 puts(usage); 145 return PSA_ERROR_INVALID_ARGUMENT; 146 } 147 148 /* Prepare key attributes */ 149 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 150 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); 151 psa_set_key_algorithm(&attributes, *alg); 152 psa_set_key_type(&attributes, key_type); 153 psa_set_key_bits(&attributes, key_bits); // optional 154 155 /* Import key */ 156 PSA_CHECK(psa_import_key(&attributes, key_bytes, key_bits / 8, key)); 157 158 exit: 159 return status; 160 } 161 162 /* 163 * Print out some information. 164 * 165 * All of this information was present in the command line argument, but his 166 * function demonstrates how each piece can be recovered from (key, alg). 167 */ 168 static void aead_info(psa_key_id_t key, psa_algorithm_t alg) 169 { 170 psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; 171 (void) psa_get_key_attributes(key, &attr); 172 psa_key_type_t key_type = psa_get_key_type(&attr); 173 size_t key_bits = psa_get_key_bits(&attr); 174 psa_algorithm_t base_alg = PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(alg); 175 size_t tag_len = PSA_AEAD_TAG_LENGTH(key_type, key_bits, alg); 176 177 const char *type_str = key_type == PSA_KEY_TYPE_AES ? "AES" 178 : key_type == PSA_KEY_TYPE_CHACHA20 ? "Chacha" 179 : "???"; 180 const char *base_str = base_alg == PSA_ALG_GCM ? "GCM" 181 : base_alg == PSA_ALG_CHACHA20_POLY1305 ? "ChachaPoly" 182 : "???"; 183 184 printf("%s, %u, %s, %u\n", 185 type_str, (unsigned) key_bits, base_str, (unsigned) tag_len); 186 } 187 188 /* 189 * Encrypt a 2-part message. 190 */ 191 static int aead_encrypt(psa_key_id_t key, psa_algorithm_t alg, 192 const unsigned char *iv, size_t iv_len, 193 const unsigned char *ad, size_t ad_len, 194 const unsigned char *part1, size_t part1_len, 195 const unsigned char *part2, size_t part2_len) 196 { 197 psa_status_t status; 198 size_t olen, olen_tag; 199 unsigned char out[PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE(MSG_MAX_SIZE)]; 200 unsigned char *p = out, *end = out + sizeof(out); 201 unsigned char tag[PSA_AEAD_TAG_MAX_SIZE]; 202 203 psa_aead_operation_t op = PSA_AEAD_OPERATION_INIT; 204 PSA_CHECK(psa_aead_encrypt_setup(&op, key, alg)); 205 206 PSA_CHECK(psa_aead_set_nonce(&op, iv, iv_len)); 207 PSA_CHECK(psa_aead_update_ad(&op, ad, ad_len)); 208 PSA_CHECK(psa_aead_update(&op, part1, part1_len, p, end - p, &olen)); 209 p += olen; 210 PSA_CHECK(psa_aead_update(&op, part2, part2_len, p, end - p, &olen)); 211 p += olen; 212 PSA_CHECK(psa_aead_finish(&op, p, end - p, &olen, 213 tag, sizeof(tag), &olen_tag)); 214 p += olen; 215 memcpy(p, tag, olen_tag); 216 p += olen_tag; 217 218 olen = p - out; 219 print_buf("out", out, olen); 220 221 exit: 222 psa_aead_abort(&op); // required on errors, harmless on success 223 return status; 224 } 225 226 /* 227 * AEAD demo: set up key/alg, print out info, encrypt messages. 228 */ 229 static psa_status_t aead_demo(const char *info) 230 { 231 psa_status_t status; 232 233 psa_key_id_t key; 234 psa_algorithm_t alg; 235 236 PSA_CHECK(aead_prepare(info, &key, &alg)); 237 238 aead_info(key, alg); 239 240 PSA_CHECK(aead_encrypt(key, alg, 241 iv1, sizeof(iv1), add_data1, sizeof(add_data1), 242 msg1_part1, sizeof(msg1_part1), 243 msg1_part2, sizeof(msg1_part2))); 244 PSA_CHECK(aead_encrypt(key, alg, 245 iv2, sizeof(iv2), add_data2, sizeof(add_data2), 246 msg2_part1, sizeof(msg2_part1), 247 msg2_part2, sizeof(msg2_part2))); 248 249 exit: 250 psa_destroy_key(key); 251 252 return status; 253 } 254 255 /* 256 * Main function 257 */ 258 int main(int argc, char **argv) 259 { 260 psa_status_t status = PSA_SUCCESS; 261 262 /* Check usage */ 263 if (argc != 2) { 264 puts(usage); 265 return EXIT_FAILURE; 266 } 267 268 /* Initialize the PSA crypto library. */ 269 PSA_CHECK(psa_crypto_init()); 270 271 /* Run the demo */ 272 PSA_CHECK(aead_demo(argv[1])); 273 274 /* Deinitialize the PSA crypto library. */ 275 mbedtls_psa_crypto_free(); 276 277 exit: 278 return status == PSA_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE; 279 } 280 281 #endif