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 30 * 31 * Licensed under the Apache License, Version 2.0 (the "License"); you may 32 * not use this file except in compliance with the License. 33 * You may obtain a copy of the License at 34 * 35 * http://www.apache.org/licenses/LICENSE-2.0 36 * 37 * Unless required by applicable law or agreed to in writing, software 38 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 39 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 40 * See the License for the specific language governing permissions and 41 * limitations under the License. 42 */ 43 44/* First include Mbed TLS headers to get the Mbed TLS configuration and 45 * platform definitions that we'll use in this program. Also include 46 * standard C headers for functions we'll use here. */ 47#include "mbedtls/build_info.h" 48 49#include "psa/crypto.h" 50 51#include <stdlib.h> 52#include <stdio.h> 53#include <string.h> 54 55/* If the build options we need are not enabled, compile a placeholder. */ 56#if !defined(MBEDTLS_PSA_CRYPTO_C) || \ 57 !defined(MBEDTLS_AES_C) || !defined(MBEDTLS_GCM_C) || \ 58 !defined(MBEDTLS_CHACHAPOLY_C) || \ 59 defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER) 60int main(void) 61{ 62 printf("MBEDTLS_PSA_CRYPTO_C and/or " 63 "MBEDTLS_AES_C and/or MBEDTLS_GCM_C and/or " 64 "MBEDTLS_CHACHAPOLY_C not defined, and/or " 65 "MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER defined\r\n"); 66 return 0; 67} 68#else 69 70/* The real program starts here. */ 71 72const char usage[] = 73 "Usage: aead_demo [aes128-gcm|aes256-gcm|aes128-gcm_8|chachapoly]"; 74 75/* Dummy data for encryption: IV/nonce, additional data, 2-part message */ 76const unsigned char iv1[12] = { 0x00 }; 77const unsigned char add_data1[] = { 0x01, 0x02 }; 78const unsigned char msg1_part1[] = { 0x03, 0x04 }; 79const unsigned char msg1_part2[] = { 0x05, 0x06, 0x07 }; 80 81/* Dummy data (2nd message) */ 82const unsigned char iv2[12] = { 0x10 }; 83const unsigned char add_data2[] = { 0x11, 0x12 }; 84const unsigned char msg2_part1[] = { 0x13, 0x14 }; 85const unsigned char msg2_part2[] = { 0x15, 0x16, 0x17 }; 86 87/* Maximum total size of the messages */ 88#define MSG1_SIZE (sizeof(msg1_part1) + sizeof(msg1_part2)) 89#define MSG2_SIZE (sizeof(msg2_part1) + sizeof(msg2_part2)) 90#define MSG_MAX_SIZE (MSG1_SIZE > MSG2_SIZE ? MSG1_SIZE : MSG2_SIZE) 91 92/* Dummy key material - never do this in production! 93 * 32-byte is enough to all the key size supported by this program. */ 94const unsigned char key_bytes[32] = { 0x2a }; 95 96/* Print the contents of a buffer in hex */ 97void print_buf(const char *title, uint8_t *buf, size_t len) 98{ 99 printf("%s:", title); 100 for (size_t i = 0; i < len; i++) { 101 printf(" %02x", buf[i]); 102 } 103 printf("\n"); 104} 105 106/* Run a PSA function and bail out if it fails. 107 * The symbolic name of the error code can be recovered using: 108 * programs/psa/psa_constant_name status <value> */ 109#define PSA_CHECK(expr) \ 110 do \ 111 { \ 112 status = (expr); \ 113 if (status != PSA_SUCCESS) \ 114 { \ 115 printf("Error %d at line %d: %s\n", \ 116 (int) status, \ 117 __LINE__, \ 118 #expr); \ 119 goto exit; \ 120 } \ 121 } \ 122 while (0) 123 124/* 125 * Prepare encryption material: 126 * - interpret command-line argument 127 * - set up key 128 * - outputs: key and algorithm, which together hold all the information 129 */ 130static psa_status_t aead_prepare(const char *info, 131 psa_key_id_t *key, 132 psa_algorithm_t *alg) 133{ 134 psa_status_t status; 135 136 /* Convert arg to alg + key_bits + key_type */ 137 size_t key_bits; 138 psa_key_type_t key_type; 139 if (strcmp(info, "aes128-gcm") == 0) { 140 *alg = PSA_ALG_GCM; 141 key_bits = 128; 142 key_type = PSA_KEY_TYPE_AES; 143 } else if (strcmp(info, "aes256-gcm") == 0) { 144 *alg = PSA_ALG_GCM; 145 key_bits = 256; 146 key_type = PSA_KEY_TYPE_AES; 147 } else if (strcmp(info, "aes128-gcm_8") == 0) { 148 *alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, 8); 149 key_bits = 128; 150 key_type = PSA_KEY_TYPE_AES; 151 } else if (strcmp(info, "chachapoly") == 0) { 152 *alg = PSA_ALG_CHACHA20_POLY1305; 153 key_bits = 256; 154 key_type = PSA_KEY_TYPE_CHACHA20; 155 } else { 156 puts(usage); 157 return PSA_ERROR_INVALID_ARGUMENT; 158 } 159 160 /* Prepare key attributes */ 161 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 162 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); 163 psa_set_key_algorithm(&attributes, *alg); 164 psa_set_key_type(&attributes, key_type); 165 psa_set_key_bits(&attributes, key_bits); // optional 166 167 /* Import key */ 168 PSA_CHECK(psa_import_key(&attributes, key_bytes, key_bits / 8, key)); 169 170exit: 171 return status; 172} 173 174/* 175 * Print out some information. 176 * 177 * All of this information was present in the command line argument, but his 178 * function demonstrates how each piece can be recovered from (key, alg). 179 */ 180static void aead_info(psa_key_id_t key, psa_algorithm_t alg) 181{ 182 psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; 183 (void) psa_get_key_attributes(key, &attr); 184 psa_key_type_t key_type = psa_get_key_type(&attr); 185 size_t key_bits = psa_get_key_bits(&attr); 186 psa_algorithm_t base_alg = PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(alg); 187 size_t tag_len = PSA_AEAD_TAG_LENGTH(key_type, key_bits, alg); 188 189 const char *type_str = key_type == PSA_KEY_TYPE_AES ? "AES" 190 : key_type == PSA_KEY_TYPE_CHACHA20 ? "Chacha" 191 : "???"; 192 const char *base_str = base_alg == PSA_ALG_GCM ? "GCM" 193 : base_alg == PSA_ALG_CHACHA20_POLY1305 ? "ChachaPoly" 194 : "???"; 195 196 printf("%s, %u, %s, %u\n", 197 type_str, (unsigned) key_bits, base_str, (unsigned) tag_len); 198} 199 200/* 201 * Encrypt a 2-part message. 202 */ 203static int aead_encrypt(psa_key_id_t key, psa_algorithm_t alg, 204 const unsigned char *iv, size_t iv_len, 205 const unsigned char *ad, size_t ad_len, 206 const unsigned char *part1, size_t part1_len, 207 const unsigned char *part2, size_t part2_len) 208{ 209 psa_status_t status; 210 size_t olen, olen_tag; 211 unsigned char out[PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE(MSG_MAX_SIZE)]; 212 unsigned char *p = out, *end = out + sizeof(out); 213 unsigned char tag[PSA_AEAD_TAG_MAX_SIZE]; 214 215 psa_aead_operation_t op = PSA_AEAD_OPERATION_INIT; 216 PSA_CHECK(psa_aead_encrypt_setup(&op, key, alg)); 217 218 PSA_CHECK(psa_aead_set_nonce(&op, iv, iv_len)); 219 PSA_CHECK(psa_aead_update_ad(&op, ad, ad_len)); 220 PSA_CHECK(psa_aead_update(&op, part1, part1_len, p, end - p, &olen)); 221 p += olen; 222 PSA_CHECK(psa_aead_update(&op, part2, part2_len, p, end - p, &olen)); 223 p += olen; 224 PSA_CHECK(psa_aead_finish(&op, p, end - p, &olen, 225 tag, sizeof(tag), &olen_tag)); 226 p += olen; 227 memcpy(p, tag, olen_tag); 228 p += olen_tag; 229 230 olen = p - out; 231 print_buf("out", out, olen); 232 233exit: 234 psa_aead_abort(&op); // required on errors, harmless on success 235 return status; 236} 237 238/* 239 * AEAD demo: set up key/alg, print out info, encrypt messages. 240 */ 241static psa_status_t aead_demo(const char *info) 242{ 243 psa_status_t status; 244 245 psa_key_id_t key; 246 psa_algorithm_t alg; 247 248 PSA_CHECK(aead_prepare(info, &key, &alg)); 249 250 aead_info(key, alg); 251 252 PSA_CHECK(aead_encrypt(key, alg, 253 iv1, sizeof(iv1), add_data1, sizeof(add_data1), 254 msg1_part1, sizeof(msg1_part1), 255 msg1_part2, sizeof(msg1_part2))); 256 PSA_CHECK(aead_encrypt(key, alg, 257 iv2, sizeof(iv2), add_data2, sizeof(add_data2), 258 msg2_part1, sizeof(msg2_part1), 259 msg2_part2, sizeof(msg2_part2))); 260 261exit: 262 psa_destroy_key(key); 263 264 return status; 265} 266 267/* 268 * Main function 269 */ 270int main(int argc, char **argv) 271{ 272 psa_status_t status = PSA_SUCCESS; 273 274 /* Check usage */ 275 if (argc != 2) { 276 puts(usage); 277 return EXIT_FAILURE; 278 } 279 280 /* Initialize the PSA crypto library. */ 281 PSA_CHECK(psa_crypto_init()); 282 283 /* Run the demo */ 284 PSA_CHECK(aead_demo(argv[1])); 285 286 /* Deinitialize the PSA crypto library. */ 287 mbedtls_psa_crypto_free(); 288 289exit: 290 return status == PSA_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE; 291} 292 293#endif 294