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