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