blob: b300e3619c3389b8da1f2be455a9d1e9732e2fb6 [file] [log] [blame]
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +01001/**
2 * PSA API multi-part AEAD demonstration.
Manuel Pégourié-Gonnard0e725c32022-01-27 11:15:33 +01003 *
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +01004 * This program AEAD-encrypts a message, using the algorithm and key size
5 * specified on the command line, using the multi-part API.
6 *
Manuel Pégourié-Gonnard64754e12022-02-08 11:21:14 +01007 * 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.
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +010010 *
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 *
Manuel Pégourié-Gonnard64754e12022-02-08 11:21:14 +010021 * 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.
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +010025 */
26
27/*
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +010028 * Copyright The Mbed TLS Contributors
Dave Rodgman16799db2023-11-02 19:47:20 +000029 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +010030 */
31
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +010032/* 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. */
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +010035#include "mbedtls/build_info.h"
36
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +010037#include "psa/crypto.h"
38
Michael Schuster3a4c4312024-06-01 21:00:33 +020039#include <test/helpers.h>
40
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +010041#include <stdlib.h>
42#include <stdio.h>
43#include <string.h>
44
45/* If the build options we need are not enabled, compile a placeholder. */
Manuel Pégourié-Gonnard7d5ef172022-01-27 13:09:13 +010046#if !defined(MBEDTLS_PSA_CRYPTO_C) || \
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +010047 !defined(MBEDTLS_AES_C) || !defined(MBEDTLS_GCM_C) || \
Manuel Pégourié-Gonnard9efbf532022-01-17 11:57:44 +010048 !defined(MBEDTLS_CHACHAPOLY_C) || \
49 defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER)
Gilles Peskine449bd832023-01-11 14:50:10 +010050int main(void)
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +010051{
Gilles Peskine449bd832023-01-11 14:50:10 +010052 printf("MBEDTLS_PSA_CRYPTO_C and/or "
53 "MBEDTLS_AES_C and/or MBEDTLS_GCM_C and/or "
54 "MBEDTLS_CHACHAPOLY_C not defined, and/or "
55 "MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER defined\r\n");
56 return 0;
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +010057}
58#else
59
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +010060/* The real program starts here. */
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +010061
Manuel Pégourié-Gonnard64754e12022-02-08 11:21:14 +010062const char usage[] =
Gilles Peskine449bd832023-01-11 14:50:10 +010063 "Usage: aead_demo [aes128-gcm|aes256-gcm|aes128-gcm_8|chachapoly]";
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +010064
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +010065/* Dummy data for encryption: IV/nonce, additional data, 2-part message */
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +010066const unsigned char iv1[12] = { 0x00 };
Manuel Pégourié-Gonnardbeef9c22022-01-27 11:42:47 +010067const unsigned char add_data1[] = { 0x01, 0x02 };
68const unsigned char msg1_part1[] = { 0x03, 0x04 };
69const unsigned char msg1_part2[] = { 0x05, 0x06, 0x07 };
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +010070
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +010071/* Dummy data (2nd message) */
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +010072const unsigned char iv2[12] = { 0x10 };
Manuel Pégourié-Gonnardbeef9c22022-01-27 11:42:47 +010073const unsigned char add_data2[] = { 0x11, 0x12 };
74const unsigned char msg2_part1[] = { 0x13, 0x14 };
75const unsigned char msg2_part2[] = { 0x15, 0x16, 0x17 };
Manuel Pégourié-Gonnard3aae30c2022-01-27 11:56:24 +010076
Manuel Pégourié-Gonnard48bae022022-02-08 11:14:58 +010077/* Maximum total size of the messages */
Gilles Peskine449bd832023-01-11 14:50:10 +010078#define MSG1_SIZE (sizeof(msg1_part1) + sizeof(msg1_part2))
79#define MSG2_SIZE (sizeof(msg2_part1) + sizeof(msg2_part2))
80#define MSG_MAX_SIZE (MSG1_SIZE > MSG2_SIZE ? MSG1_SIZE : MSG2_SIZE)
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +010081
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +010082/* Dummy key material - never do this in production!
83 * 32-byte is enough to all the key size supported by this program. */
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +010084const unsigned char key_bytes[32] = { 0x2a };
85
Manuel Pégourié-Gonnard340808c2022-02-08 11:15:26 +010086/* Run a PSA function and bail out if it fails.
87 * The symbolic name of the error code can be recovered using:
Tom Cosgrove1797b052022-12-04 17:19:59 +000088 * programs/psa/psa_constant_name status <value> */
Gilles Peskine449bd832023-01-11 14:50:10 +010089#define PSA_CHECK(expr) \
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +010090 do \
91 { \
Gilles Peskine449bd832023-01-11 14:50:10 +010092 status = (expr); \
93 if (status != PSA_SUCCESS) \
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +010094 { \
Gilles Peskine449bd832023-01-11 14:50:10 +010095 printf("Error %d at line %d: %s\n", \
96 (int) status, \
97 __LINE__, \
98 #expr); \
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +010099 goto exit; \
100 } \
101 } \
Gilles Peskine449bd832023-01-11 14:50:10 +0100102 while (0)
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100103
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +0100104/*
105 * Prepare encryption material:
106 * - interpret command-line argument
107 * - set up key
108 * - outputs: key and algorithm, which together hold all the information
109 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100110static psa_status_t aead_prepare(const char *info,
111 psa_key_id_t *key,
112 psa_algorithm_t *alg)
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100113{
114 psa_status_t status;
115
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +0100116 /* Convert arg to alg + key_bits + key_type */
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100117 size_t key_bits;
118 psa_key_type_t key_type;
Gilles Peskine449bd832023-01-11 14:50:10 +0100119 if (strcmp(info, "aes128-gcm") == 0) {
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100120 *alg = PSA_ALG_GCM;
121 key_bits = 128;
122 key_type = PSA_KEY_TYPE_AES;
Gilles Peskine449bd832023-01-11 14:50:10 +0100123 } else if (strcmp(info, "aes256-gcm") == 0) {
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100124 *alg = PSA_ALG_GCM;
125 key_bits = 256;
126 key_type = PSA_KEY_TYPE_AES;
Gilles Peskine449bd832023-01-11 14:50:10 +0100127 } else if (strcmp(info, "aes128-gcm_8") == 0) {
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100128 *alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, 8);
129 key_bits = 128;
130 key_type = PSA_KEY_TYPE_AES;
Gilles Peskine449bd832023-01-11 14:50:10 +0100131 } else if (strcmp(info, "chachapoly") == 0) {
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100132 *alg = PSA_ALG_CHACHA20_POLY1305;
133 key_bits = 256;
134 key_type = PSA_KEY_TYPE_CHACHA20;
135 } else {
Gilles Peskine449bd832023-01-11 14:50:10 +0100136 puts(usage);
137 return PSA_ERROR_INVALID_ARGUMENT;
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100138 }
139
Andrzej Kurek5c65c572022-04-13 14:28:52 -0400140 /* Prepare key attributes */
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100141 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
Gilles Peskine449bd832023-01-11 14:50:10 +0100142 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
143 psa_set_key_algorithm(&attributes, *alg);
144 psa_set_key_type(&attributes, key_type);
145 psa_set_key_bits(&attributes, key_bits); // optional
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100146
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +0100147 /* Import key */
Gilles Peskine449bd832023-01-11 14:50:10 +0100148 PSA_CHECK(psa_import_key(&attributes, key_bytes, key_bits / 8, key));
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100149
150exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100151 return status;
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100152}
153
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +0100154/*
155 * Print out some information.
156 *
157 * All of this information was present in the command line argument, but his
158 * function demonstrates how each piece can be recovered from (key, alg).
159 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100160static void aead_info(psa_key_id_t key, psa_algorithm_t alg)
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100161{
162 psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
Gilles Peskine449bd832023-01-11 14:50:10 +0100163 (void) psa_get_key_attributes(key, &attr);
164 psa_key_type_t key_type = psa_get_key_type(&attr);
165 size_t key_bits = psa_get_key_bits(&attr);
166 psa_algorithm_t base_alg = PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(alg);
167 size_t tag_len = PSA_AEAD_TAG_LENGTH(key_type, key_bits, alg);
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100168
169 const char *type_str = key_type == PSA_KEY_TYPE_AES ? "AES"
170 : key_type == PSA_KEY_TYPE_CHACHA20 ? "Chacha"
171 : "???";
172 const char *base_str = base_alg == PSA_ALG_GCM ? "GCM"
173 : base_alg == PSA_ALG_CHACHA20_POLY1305 ? "ChachaPoly"
174 : "???";
175
Gilles Peskine449bd832023-01-11 14:50:10 +0100176 printf("%s, %u, %s, %u\n",
177 type_str, (unsigned) key_bits, base_str, (unsigned) tag_len);
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100178}
179
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +0100180/*
181 * Encrypt a 2-part message.
182 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100183static int aead_encrypt(psa_key_id_t key, psa_algorithm_t alg,
184 const unsigned char *iv, size_t iv_len,
185 const unsigned char *ad, size_t ad_len,
186 const unsigned char *part1, size_t part1_len,
187 const unsigned char *part2, size_t part2_len)
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100188{
189 psa_status_t status;
190 size_t olen, olen_tag;
Manuel Pégourié-Gonnardfd1d13c2022-01-28 12:52:35 +0100191 unsigned char out[PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE(MSG_MAX_SIZE)];
Gilles Peskine449bd832023-01-11 14:50:10 +0100192 unsigned char *p = out, *end = out + sizeof(out);
Manuel Pégourié-Gonnard3aae30c2022-01-27 11:56:24 +0100193 unsigned char tag[PSA_AEAD_TAG_MAX_SIZE];
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100194
195 psa_aead_operation_t op = PSA_AEAD_OPERATION_INIT;
Gilles Peskine449bd832023-01-11 14:50:10 +0100196 PSA_CHECK(psa_aead_encrypt_setup(&op, key, alg));
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100197
Gilles Peskine449bd832023-01-11 14:50:10 +0100198 PSA_CHECK(psa_aead_set_nonce(&op, iv, iv_len));
199 PSA_CHECK(psa_aead_update_ad(&op, ad, ad_len));
200 PSA_CHECK(psa_aead_update(&op, part1, part1_len, p, end - p, &olen));
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100201 p += olen;
Gilles Peskine449bd832023-01-11 14:50:10 +0100202 PSA_CHECK(psa_aead_update(&op, part2, part2_len, p, end - p, &olen));
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100203 p += olen;
Gilles Peskine449bd832023-01-11 14:50:10 +0100204 PSA_CHECK(psa_aead_finish(&op, p, end - p, &olen,
205 tag, sizeof(tag), &olen_tag));
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100206 p += olen;
Gilles Peskine449bd832023-01-11 14:50:10 +0100207 memcpy(p, tag, olen_tag);
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100208 p += olen_tag;
209
210 olen = p - out;
Michael Schuster3a4c4312024-06-01 21:00:33 +0200211 mbedtls_test_print_buf("out", out, olen);
Manuel Pégourié-Gonnard1a45c712022-01-27 12:17:20 +0100212
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100213exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100214 psa_aead_abort(&op); // required on errors, harmless on success
215 return status;
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100216}
217
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +0100218/*
219 * AEAD demo: set up key/alg, print out info, encrypt messages.
220 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100221static psa_status_t aead_demo(const char *info)
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100222{
223 psa_status_t status;
224
225 psa_key_id_t key;
226 psa_algorithm_t alg;
227
Gilles Peskine449bd832023-01-11 14:50:10 +0100228 PSA_CHECK(aead_prepare(info, &key, &alg));
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100229
Gilles Peskine449bd832023-01-11 14:50:10 +0100230 aead_info(key, alg);
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100231
Gilles Peskine449bd832023-01-11 14:50:10 +0100232 PSA_CHECK(aead_encrypt(key, alg,
233 iv1, sizeof(iv1), add_data1, sizeof(add_data1),
234 msg1_part1, sizeof(msg1_part1),
235 msg1_part2, sizeof(msg1_part2)));
236 PSA_CHECK(aead_encrypt(key, alg,
237 iv2, sizeof(iv2), add_data2, sizeof(add_data2),
238 msg2_part1, sizeof(msg2_part1),
239 msg2_part2, sizeof(msg2_part2)));
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100240
241exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100242 psa_destroy_key(key);
Manuel Pégourié-Gonnard1a45c712022-01-27 12:17:20 +0100243
Gilles Peskine449bd832023-01-11 14:50:10 +0100244 return status;
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100245}
246
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100247/*
248 * Main function
249 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100250int main(int argc, char **argv)
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100251{
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +0100252 psa_status_t status = PSA_SUCCESS;
253
254 /* Check usage */
Gilles Peskine449bd832023-01-11 14:50:10 +0100255 if (argc != 2) {
256 puts(usage);
257 return EXIT_FAILURE;
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100258 }
259
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +0100260 /* Initialize the PSA crypto library. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100261 PSA_CHECK(psa_crypto_init());
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100262
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +0100263 /* Run the demo */
Gilles Peskine449bd832023-01-11 14:50:10 +0100264 PSA_CHECK(aead_demo(argv[1]));
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +0100265
266 /* Deinitialize the PSA crypto library. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100267 mbedtls_psa_crypto_free();
Manuel Pégourié-Gonnard248b3852022-01-31 12:56:39 +0100268
269exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100270 return status == PSA_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE;
Manuel Pégourié-Gonnard398d4592022-01-07 12:26:32 +0100271}
272
273#endif