1a8e1175bSopenharmony_ci/** 2a8e1175bSopenharmony_ci * PSA API key derivation demonstration 3a8e1175bSopenharmony_ci * 4a8e1175bSopenharmony_ci * This program calculates a key ladder: a chain of secret material, each 5a8e1175bSopenharmony_ci * derived from the previous one in a deterministic way based on a label. 6a8e1175bSopenharmony_ci * Two keys are identical if and only if they are derived from the same key 7a8e1175bSopenharmony_ci * using the same label. 8a8e1175bSopenharmony_ci * 9a8e1175bSopenharmony_ci * The initial key is called the master key. The master key is normally 10a8e1175bSopenharmony_ci * randomly generated, but it could itself be derived from another key. 11a8e1175bSopenharmony_ci * 12a8e1175bSopenharmony_ci * This program derives a series of keys called intermediate keys. 13a8e1175bSopenharmony_ci * The first intermediate key is derived from the master key using the 14a8e1175bSopenharmony_ci * first label passed on the command line. Each subsequent intermediate 15a8e1175bSopenharmony_ci * key is derived from the previous one using the next label passed 16a8e1175bSopenharmony_ci * on the command line. 17a8e1175bSopenharmony_ci * 18a8e1175bSopenharmony_ci * This program has four modes of operation: 19a8e1175bSopenharmony_ci * 20a8e1175bSopenharmony_ci * - "generate": generate a random master key. 21a8e1175bSopenharmony_ci * - "wrap": derive a wrapping key from the last intermediate key, 22a8e1175bSopenharmony_ci * and use that key to encrypt-and-authenticate some data. 23a8e1175bSopenharmony_ci * - "unwrap": derive a wrapping key from the last intermediate key, 24a8e1175bSopenharmony_ci * and use that key to decrypt-and-authenticate some 25a8e1175bSopenharmony_ci * ciphertext created by wrap mode. 26a8e1175bSopenharmony_ci * - "save": save the last intermediate key so that it can be reused as 27a8e1175bSopenharmony_ci * the master key in another run of the program. 28a8e1175bSopenharmony_ci * 29a8e1175bSopenharmony_ci * See the usage() output for the command line usage. See the file 30a8e1175bSopenharmony_ci * `key_ladder_demo.sh` for an example run. 31a8e1175bSopenharmony_ci */ 32a8e1175bSopenharmony_ci 33a8e1175bSopenharmony_ci/* 34a8e1175bSopenharmony_ci * Copyright The Mbed TLS Contributors 35a8e1175bSopenharmony_ci * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 36a8e1175bSopenharmony_ci */ 37a8e1175bSopenharmony_ci 38a8e1175bSopenharmony_ci/* First include Mbed TLS headers to get the Mbed TLS configuration and 39a8e1175bSopenharmony_ci * platform definitions that we'll use in this program. Also include 40a8e1175bSopenharmony_ci * standard C headers for functions we'll use here. */ 41a8e1175bSopenharmony_ci#include "mbedtls/build_info.h" 42a8e1175bSopenharmony_ci 43a8e1175bSopenharmony_ci#include <stdlib.h> 44a8e1175bSopenharmony_ci#include <stdio.h> 45a8e1175bSopenharmony_ci#include <string.h> 46a8e1175bSopenharmony_ci 47a8e1175bSopenharmony_ci#include "mbedtls/platform.h" // for mbedtls_setbuf 48a8e1175bSopenharmony_ci#include "mbedtls/platform_util.h" // for mbedtls_platform_zeroize 49a8e1175bSopenharmony_ci 50a8e1175bSopenharmony_ci#include <psa/crypto.h> 51a8e1175bSopenharmony_ci 52a8e1175bSopenharmony_ci/* If the build options we need are not enabled, compile a placeholder. */ 53a8e1175bSopenharmony_ci#if !defined(PSA_WANT_ALG_SHA_256) || !defined(MBEDTLS_MD_C) || \ 54a8e1175bSopenharmony_ci !defined(MBEDTLS_AES_C) || !defined(MBEDTLS_CCM_C) || \ 55a8e1175bSopenharmony_ci !defined(MBEDTLS_PSA_CRYPTO_C) || !defined(MBEDTLS_FS_IO) || \ 56a8e1175bSopenharmony_ci defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER) 57a8e1175bSopenharmony_ciint main(void) 58a8e1175bSopenharmony_ci{ 59a8e1175bSopenharmony_ci printf("PSA_WANT_ALG_SHA_256 and/or MBEDTLS_MD_C and/or " 60a8e1175bSopenharmony_ci "MBEDTLS_AES_C and/or MBEDTLS_CCM_C and/or " 61a8e1175bSopenharmony_ci "MBEDTLS_PSA_CRYPTO_C and/or MBEDTLS_FS_IO " 62a8e1175bSopenharmony_ci "not defined and/or MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER " 63a8e1175bSopenharmony_ci "defined.\n"); 64a8e1175bSopenharmony_ci return 0; 65a8e1175bSopenharmony_ci} 66a8e1175bSopenharmony_ci#else 67a8e1175bSopenharmony_ci 68a8e1175bSopenharmony_ci/* The real program starts here. */ 69a8e1175bSopenharmony_ci 70a8e1175bSopenharmony_ci/* Run a system function and bail out if it fails. */ 71a8e1175bSopenharmony_ci#define SYS_CHECK(expr) \ 72a8e1175bSopenharmony_ci do \ 73a8e1175bSopenharmony_ci { \ 74a8e1175bSopenharmony_ci if (!(expr)) \ 75a8e1175bSopenharmony_ci { \ 76a8e1175bSopenharmony_ci perror( #expr); \ 77a8e1175bSopenharmony_ci status = DEMO_ERROR; \ 78a8e1175bSopenharmony_ci goto exit; \ 79a8e1175bSopenharmony_ci } \ 80a8e1175bSopenharmony_ci } \ 81a8e1175bSopenharmony_ci while (0) 82a8e1175bSopenharmony_ci 83a8e1175bSopenharmony_ci/* Run a PSA function and bail out if it fails. */ 84a8e1175bSopenharmony_ci#define PSA_CHECK(expr) \ 85a8e1175bSopenharmony_ci do \ 86a8e1175bSopenharmony_ci { \ 87a8e1175bSopenharmony_ci status = (expr); \ 88a8e1175bSopenharmony_ci if (status != PSA_SUCCESS) \ 89a8e1175bSopenharmony_ci { \ 90a8e1175bSopenharmony_ci printf("Error %d at line %d: %s\n", \ 91a8e1175bSopenharmony_ci (int) status, \ 92a8e1175bSopenharmony_ci __LINE__, \ 93a8e1175bSopenharmony_ci #expr); \ 94a8e1175bSopenharmony_ci goto exit; \ 95a8e1175bSopenharmony_ci } \ 96a8e1175bSopenharmony_ci } \ 97a8e1175bSopenharmony_ci while (0) 98a8e1175bSopenharmony_ci 99a8e1175bSopenharmony_ci/* To report operational errors in this program, use an error code that is 100a8e1175bSopenharmony_ci * different from every PSA error code. */ 101a8e1175bSopenharmony_ci#define DEMO_ERROR 120 102a8e1175bSopenharmony_ci 103a8e1175bSopenharmony_ci/* The maximum supported key ladder depth. */ 104a8e1175bSopenharmony_ci#define MAX_LADDER_DEPTH 10 105a8e1175bSopenharmony_ci 106a8e1175bSopenharmony_ci/* Salt to use when deriving an intermediate key. */ 107a8e1175bSopenharmony_ci#define DERIVE_KEY_SALT ((uint8_t *) "key_ladder_demo.derive") 108a8e1175bSopenharmony_ci#define DERIVE_KEY_SALT_LENGTH (strlen((const char *) DERIVE_KEY_SALT)) 109a8e1175bSopenharmony_ci 110a8e1175bSopenharmony_ci/* Salt to use when deriving a wrapping key. */ 111a8e1175bSopenharmony_ci#define WRAPPING_KEY_SALT ((uint8_t *) "key_ladder_demo.wrap") 112a8e1175bSopenharmony_ci#define WRAPPING_KEY_SALT_LENGTH (strlen((const char *) WRAPPING_KEY_SALT)) 113a8e1175bSopenharmony_ci 114a8e1175bSopenharmony_ci/* Size of the key derivation keys (applies both to the master key and 115a8e1175bSopenharmony_ci * to intermediate keys). */ 116a8e1175bSopenharmony_ci#define KEY_SIZE_BYTES 40 117a8e1175bSopenharmony_ci 118a8e1175bSopenharmony_ci/* Algorithm for key derivation. */ 119a8e1175bSopenharmony_ci#define KDF_ALG PSA_ALG_HKDF(PSA_ALG_SHA_256) 120a8e1175bSopenharmony_ci 121a8e1175bSopenharmony_ci/* Type and size of the key used to wrap data. */ 122a8e1175bSopenharmony_ci#define WRAPPING_KEY_TYPE PSA_KEY_TYPE_AES 123a8e1175bSopenharmony_ci#define WRAPPING_KEY_BITS 128 124a8e1175bSopenharmony_ci 125a8e1175bSopenharmony_ci/* Cipher mode used to wrap data. */ 126a8e1175bSopenharmony_ci#define WRAPPING_ALG PSA_ALG_CCM 127a8e1175bSopenharmony_ci 128a8e1175bSopenharmony_ci/* Nonce size used to wrap data. */ 129a8e1175bSopenharmony_ci#define WRAPPING_IV_SIZE 13 130a8e1175bSopenharmony_ci 131a8e1175bSopenharmony_ci/* Header used in files containing wrapped data. We'll save this header 132a8e1175bSopenharmony_ci * directly without worrying about data representation issues such as 133a8e1175bSopenharmony_ci * integer sizes and endianness, because the data is meant to be read 134a8e1175bSopenharmony_ci * back by the same program on the same machine. */ 135a8e1175bSopenharmony_ci#define WRAPPED_DATA_MAGIC "key_ladder_demo" // including trailing null byte 136a8e1175bSopenharmony_ci#define WRAPPED_DATA_MAGIC_LENGTH (sizeof(WRAPPED_DATA_MAGIC)) 137a8e1175bSopenharmony_citypedef struct { 138a8e1175bSopenharmony_ci char magic[WRAPPED_DATA_MAGIC_LENGTH]; 139a8e1175bSopenharmony_ci size_t ad_size; /* Size of the additional data, which is this header. */ 140a8e1175bSopenharmony_ci size_t payload_size; /* Size of the encrypted data. */ 141a8e1175bSopenharmony_ci /* Store the IV inside the additional data. It's convenient. */ 142a8e1175bSopenharmony_ci uint8_t iv[WRAPPING_IV_SIZE]; 143a8e1175bSopenharmony_ci} wrapped_data_header_t; 144a8e1175bSopenharmony_ci 145a8e1175bSopenharmony_ci/* The modes that this program can operate in (see usage). */ 146a8e1175bSopenharmony_cienum program_mode { 147a8e1175bSopenharmony_ci MODE_GENERATE, 148a8e1175bSopenharmony_ci MODE_SAVE, 149a8e1175bSopenharmony_ci MODE_UNWRAP, 150a8e1175bSopenharmony_ci MODE_WRAP 151a8e1175bSopenharmony_ci}; 152a8e1175bSopenharmony_ci 153a8e1175bSopenharmony_ci/* Save a key to a file. In the real world, you may want to export a derived 154a8e1175bSopenharmony_ci * key sometimes, to share it with another party. */ 155a8e1175bSopenharmony_cistatic psa_status_t save_key(psa_key_id_t key, 156a8e1175bSopenharmony_ci const char *output_file_name) 157a8e1175bSopenharmony_ci{ 158a8e1175bSopenharmony_ci psa_status_t status = PSA_SUCCESS; 159a8e1175bSopenharmony_ci uint8_t key_data[KEY_SIZE_BYTES]; 160a8e1175bSopenharmony_ci size_t key_size; 161a8e1175bSopenharmony_ci FILE *key_file = NULL; 162a8e1175bSopenharmony_ci 163a8e1175bSopenharmony_ci PSA_CHECK(psa_export_key(key, 164a8e1175bSopenharmony_ci key_data, sizeof(key_data), 165a8e1175bSopenharmony_ci &key_size)); 166a8e1175bSopenharmony_ci SYS_CHECK((key_file = fopen(output_file_name, "wb")) != NULL); 167a8e1175bSopenharmony_ci /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ 168a8e1175bSopenharmony_ci mbedtls_setbuf(key_file, NULL); 169a8e1175bSopenharmony_ci SYS_CHECK(fwrite(key_data, 1, key_size, key_file) == key_size); 170a8e1175bSopenharmony_ci SYS_CHECK(fclose(key_file) == 0); 171a8e1175bSopenharmony_ci key_file = NULL; 172a8e1175bSopenharmony_ci 173a8e1175bSopenharmony_ciexit: 174a8e1175bSopenharmony_ci if (key_file != NULL) { 175a8e1175bSopenharmony_ci fclose(key_file); 176a8e1175bSopenharmony_ci } 177a8e1175bSopenharmony_ci return status; 178a8e1175bSopenharmony_ci} 179a8e1175bSopenharmony_ci 180a8e1175bSopenharmony_ci/* Generate a master key for use in this demo. 181a8e1175bSopenharmony_ci * 182a8e1175bSopenharmony_ci * Normally a master key would be non-exportable. For the purpose of this 183a8e1175bSopenharmony_ci * demo, we want to save it to a file, to avoid relying on the keystore 184a8e1175bSopenharmony_ci * capability of the PSA crypto library. */ 185a8e1175bSopenharmony_cistatic psa_status_t generate(const char *key_file_name) 186a8e1175bSopenharmony_ci{ 187a8e1175bSopenharmony_ci psa_status_t status = PSA_SUCCESS; 188a8e1175bSopenharmony_ci psa_key_id_t key = 0; 189a8e1175bSopenharmony_ci psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 190a8e1175bSopenharmony_ci 191a8e1175bSopenharmony_ci psa_set_key_usage_flags(&attributes, 192a8e1175bSopenharmony_ci PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT); 193a8e1175bSopenharmony_ci psa_set_key_algorithm(&attributes, KDF_ALG); 194a8e1175bSopenharmony_ci psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE); 195a8e1175bSopenharmony_ci psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(KEY_SIZE_BYTES)); 196a8e1175bSopenharmony_ci 197a8e1175bSopenharmony_ci PSA_CHECK(psa_generate_key(&attributes, &key)); 198a8e1175bSopenharmony_ci 199a8e1175bSopenharmony_ci PSA_CHECK(save_key(key, key_file_name)); 200a8e1175bSopenharmony_ci 201a8e1175bSopenharmony_ciexit: 202a8e1175bSopenharmony_ci (void) psa_destroy_key(key); 203a8e1175bSopenharmony_ci return status; 204a8e1175bSopenharmony_ci} 205a8e1175bSopenharmony_ci 206a8e1175bSopenharmony_ci/* Load the master key from a file. 207a8e1175bSopenharmony_ci * 208a8e1175bSopenharmony_ci * In the real world, this master key would be stored in an internal memory 209a8e1175bSopenharmony_ci * and the storage would be managed by the keystore capability of the PSA 210a8e1175bSopenharmony_ci * crypto library. */ 211a8e1175bSopenharmony_cistatic psa_status_t import_key_from_file(psa_key_usage_t usage, 212a8e1175bSopenharmony_ci psa_algorithm_t alg, 213a8e1175bSopenharmony_ci const char *key_file_name, 214a8e1175bSopenharmony_ci psa_key_id_t *master_key) 215a8e1175bSopenharmony_ci{ 216a8e1175bSopenharmony_ci psa_status_t status = PSA_SUCCESS; 217a8e1175bSopenharmony_ci psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 218a8e1175bSopenharmony_ci uint8_t key_data[KEY_SIZE_BYTES]; 219a8e1175bSopenharmony_ci size_t key_size; 220a8e1175bSopenharmony_ci FILE *key_file = NULL; 221a8e1175bSopenharmony_ci unsigned char extra_byte; 222a8e1175bSopenharmony_ci 223a8e1175bSopenharmony_ci SYS_CHECK((key_file = fopen(key_file_name, "rb")) != NULL); 224a8e1175bSopenharmony_ci /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ 225a8e1175bSopenharmony_ci mbedtls_setbuf(key_file, NULL); 226a8e1175bSopenharmony_ci SYS_CHECK((key_size = fread(key_data, 1, sizeof(key_data), 227a8e1175bSopenharmony_ci key_file)) != 0); 228a8e1175bSopenharmony_ci if (fread(&extra_byte, 1, 1, key_file) != 0) { 229a8e1175bSopenharmony_ci printf("Key file too large (max: %u).\n", 230a8e1175bSopenharmony_ci (unsigned) sizeof(key_data)); 231a8e1175bSopenharmony_ci status = DEMO_ERROR; 232a8e1175bSopenharmony_ci goto exit; 233a8e1175bSopenharmony_ci } 234a8e1175bSopenharmony_ci SYS_CHECK(fclose(key_file) == 0); 235a8e1175bSopenharmony_ci key_file = NULL; 236a8e1175bSopenharmony_ci 237a8e1175bSopenharmony_ci psa_set_key_usage_flags(&attributes, usage); 238a8e1175bSopenharmony_ci psa_set_key_algorithm(&attributes, alg); 239a8e1175bSopenharmony_ci psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE); 240a8e1175bSopenharmony_ci PSA_CHECK(psa_import_key(&attributes, key_data, key_size, master_key)); 241a8e1175bSopenharmony_ciexit: 242a8e1175bSopenharmony_ci if (key_file != NULL) { 243a8e1175bSopenharmony_ci fclose(key_file); 244a8e1175bSopenharmony_ci } 245a8e1175bSopenharmony_ci mbedtls_platform_zeroize(key_data, sizeof(key_data)); 246a8e1175bSopenharmony_ci if (status != PSA_SUCCESS) { 247a8e1175bSopenharmony_ci /* If the key creation hasn't happened yet or has failed, 248a8e1175bSopenharmony_ci * *master_key is null. psa_destroy_key( 0 ) is 249a8e1175bSopenharmony_ci * guaranteed to do nothing and return PSA_SUCCESS. */ 250a8e1175bSopenharmony_ci (void) psa_destroy_key(*master_key); 251a8e1175bSopenharmony_ci *master_key = 0; 252a8e1175bSopenharmony_ci } 253a8e1175bSopenharmony_ci return status; 254a8e1175bSopenharmony_ci} 255a8e1175bSopenharmony_ci 256a8e1175bSopenharmony_ci/* Derive the intermediate keys, using the list of labels provided on 257a8e1175bSopenharmony_ci * the command line. On input, *key is the master key identifier. 258a8e1175bSopenharmony_ci * This function destroys the master key. On successful output, *key 259a8e1175bSopenharmony_ci * is the identifier of the final derived key. 260a8e1175bSopenharmony_ci */ 261a8e1175bSopenharmony_cistatic psa_status_t derive_key_ladder(const char *ladder[], 262a8e1175bSopenharmony_ci size_t ladder_depth, 263a8e1175bSopenharmony_ci psa_key_id_t *key) 264a8e1175bSopenharmony_ci{ 265a8e1175bSopenharmony_ci psa_status_t status = PSA_SUCCESS; 266a8e1175bSopenharmony_ci psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 267a8e1175bSopenharmony_ci psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; 268a8e1175bSopenharmony_ci size_t i; 269a8e1175bSopenharmony_ci 270a8e1175bSopenharmony_ci psa_set_key_usage_flags(&attributes, 271a8e1175bSopenharmony_ci PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT); 272a8e1175bSopenharmony_ci psa_set_key_algorithm(&attributes, KDF_ALG); 273a8e1175bSopenharmony_ci psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE); 274a8e1175bSopenharmony_ci psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(KEY_SIZE_BYTES)); 275a8e1175bSopenharmony_ci 276a8e1175bSopenharmony_ci /* For each label in turn, ... */ 277a8e1175bSopenharmony_ci for (i = 0; i < ladder_depth; i++) { 278a8e1175bSopenharmony_ci /* Start deriving material from the master key (if i=0) or from 279a8e1175bSopenharmony_ci * the current intermediate key (if i>0). */ 280a8e1175bSopenharmony_ci PSA_CHECK(psa_key_derivation_setup(&operation, KDF_ALG)); 281a8e1175bSopenharmony_ci PSA_CHECK(psa_key_derivation_input_bytes( 282a8e1175bSopenharmony_ci &operation, PSA_KEY_DERIVATION_INPUT_SALT, 283a8e1175bSopenharmony_ci DERIVE_KEY_SALT, DERIVE_KEY_SALT_LENGTH)); 284a8e1175bSopenharmony_ci PSA_CHECK(psa_key_derivation_input_key( 285a8e1175bSopenharmony_ci &operation, PSA_KEY_DERIVATION_INPUT_SECRET, 286a8e1175bSopenharmony_ci *key)); 287a8e1175bSopenharmony_ci PSA_CHECK(psa_key_derivation_input_bytes( 288a8e1175bSopenharmony_ci &operation, PSA_KEY_DERIVATION_INPUT_INFO, 289a8e1175bSopenharmony_ci (uint8_t *) ladder[i], strlen(ladder[i]))); 290a8e1175bSopenharmony_ci /* When the parent key is not the master key, destroy it, 291a8e1175bSopenharmony_ci * since it is no longer needed. */ 292a8e1175bSopenharmony_ci PSA_CHECK(psa_destroy_key(*key)); 293a8e1175bSopenharmony_ci *key = 0; 294a8e1175bSopenharmony_ci /* Derive the next intermediate key from the parent key. */ 295a8e1175bSopenharmony_ci PSA_CHECK(psa_key_derivation_output_key(&attributes, &operation, 296a8e1175bSopenharmony_ci key)); 297a8e1175bSopenharmony_ci PSA_CHECK(psa_key_derivation_abort(&operation)); 298a8e1175bSopenharmony_ci } 299a8e1175bSopenharmony_ci 300a8e1175bSopenharmony_ciexit: 301a8e1175bSopenharmony_ci psa_key_derivation_abort(&operation); 302a8e1175bSopenharmony_ci if (status != PSA_SUCCESS) { 303a8e1175bSopenharmony_ci psa_destroy_key(*key); 304a8e1175bSopenharmony_ci *key = 0; 305a8e1175bSopenharmony_ci } 306a8e1175bSopenharmony_ci return status; 307a8e1175bSopenharmony_ci} 308a8e1175bSopenharmony_ci 309a8e1175bSopenharmony_ci/* Derive a wrapping key from the last intermediate key. */ 310a8e1175bSopenharmony_cistatic psa_status_t derive_wrapping_key(psa_key_usage_t usage, 311a8e1175bSopenharmony_ci psa_key_id_t derived_key, 312a8e1175bSopenharmony_ci psa_key_id_t *wrapping_key) 313a8e1175bSopenharmony_ci{ 314a8e1175bSopenharmony_ci psa_status_t status = PSA_SUCCESS; 315a8e1175bSopenharmony_ci psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 316a8e1175bSopenharmony_ci psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; 317a8e1175bSopenharmony_ci 318a8e1175bSopenharmony_ci *wrapping_key = 0; 319a8e1175bSopenharmony_ci 320a8e1175bSopenharmony_ci /* Set up a key derivation operation from the key derived from 321a8e1175bSopenharmony_ci * the master key. */ 322a8e1175bSopenharmony_ci PSA_CHECK(psa_key_derivation_setup(&operation, KDF_ALG)); 323a8e1175bSopenharmony_ci PSA_CHECK(psa_key_derivation_input_bytes( 324a8e1175bSopenharmony_ci &operation, PSA_KEY_DERIVATION_INPUT_SALT, 325a8e1175bSopenharmony_ci WRAPPING_KEY_SALT, WRAPPING_KEY_SALT_LENGTH)); 326a8e1175bSopenharmony_ci PSA_CHECK(psa_key_derivation_input_key( 327a8e1175bSopenharmony_ci &operation, PSA_KEY_DERIVATION_INPUT_SECRET, 328a8e1175bSopenharmony_ci derived_key)); 329a8e1175bSopenharmony_ci PSA_CHECK(psa_key_derivation_input_bytes( 330a8e1175bSopenharmony_ci &operation, PSA_KEY_DERIVATION_INPUT_INFO, 331a8e1175bSopenharmony_ci NULL, 0)); 332a8e1175bSopenharmony_ci 333a8e1175bSopenharmony_ci /* Create the wrapping key. */ 334a8e1175bSopenharmony_ci psa_set_key_usage_flags(&attributes, usage); 335a8e1175bSopenharmony_ci psa_set_key_algorithm(&attributes, WRAPPING_ALG); 336a8e1175bSopenharmony_ci psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); 337a8e1175bSopenharmony_ci psa_set_key_bits(&attributes, WRAPPING_KEY_BITS); 338a8e1175bSopenharmony_ci PSA_CHECK(psa_key_derivation_output_key(&attributes, &operation, 339a8e1175bSopenharmony_ci wrapping_key)); 340a8e1175bSopenharmony_ci 341a8e1175bSopenharmony_ciexit: 342a8e1175bSopenharmony_ci psa_key_derivation_abort(&operation); 343a8e1175bSopenharmony_ci return status; 344a8e1175bSopenharmony_ci} 345a8e1175bSopenharmony_ci 346a8e1175bSopenharmony_cistatic psa_status_t wrap_data(const char *input_file_name, 347a8e1175bSopenharmony_ci const char *output_file_name, 348a8e1175bSopenharmony_ci psa_key_id_t wrapping_key) 349a8e1175bSopenharmony_ci{ 350a8e1175bSopenharmony_ci psa_status_t status; 351a8e1175bSopenharmony_ci FILE *input_file = NULL; 352a8e1175bSopenharmony_ci FILE *output_file = NULL; 353a8e1175bSopenharmony_ci psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 354a8e1175bSopenharmony_ci psa_key_type_t key_type; 355a8e1175bSopenharmony_ci long input_position; 356a8e1175bSopenharmony_ci size_t input_size; 357a8e1175bSopenharmony_ci size_t buffer_size = 0; 358a8e1175bSopenharmony_ci unsigned char *buffer = NULL; 359a8e1175bSopenharmony_ci size_t ciphertext_size; 360a8e1175bSopenharmony_ci wrapped_data_header_t header; 361a8e1175bSopenharmony_ci 362a8e1175bSopenharmony_ci /* Find the size of the data to wrap. */ 363a8e1175bSopenharmony_ci SYS_CHECK((input_file = fopen(input_file_name, "rb")) != NULL); 364a8e1175bSopenharmony_ci /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ 365a8e1175bSopenharmony_ci mbedtls_setbuf(input_file, NULL); 366a8e1175bSopenharmony_ci SYS_CHECK(fseek(input_file, 0, SEEK_END) == 0); 367a8e1175bSopenharmony_ci SYS_CHECK((input_position = ftell(input_file)) != -1); 368a8e1175bSopenharmony_ci#if LONG_MAX > SIZE_MAX 369a8e1175bSopenharmony_ci if (input_position > SIZE_MAX) { 370a8e1175bSopenharmony_ci printf("Input file too large.\n"); 371a8e1175bSopenharmony_ci status = DEMO_ERROR; 372a8e1175bSopenharmony_ci goto exit; 373a8e1175bSopenharmony_ci } 374a8e1175bSopenharmony_ci#endif 375a8e1175bSopenharmony_ci input_size = input_position; 376a8e1175bSopenharmony_ci PSA_CHECK(psa_get_key_attributes(wrapping_key, &attributes)); 377a8e1175bSopenharmony_ci key_type = psa_get_key_type(&attributes); 378a8e1175bSopenharmony_ci buffer_size = 379a8e1175bSopenharmony_ci PSA_AEAD_ENCRYPT_OUTPUT_SIZE(key_type, WRAPPING_ALG, input_size); 380a8e1175bSopenharmony_ci /* Check for integer overflow. */ 381a8e1175bSopenharmony_ci if (buffer_size < input_size) { 382a8e1175bSopenharmony_ci printf("Input file too large.\n"); 383a8e1175bSopenharmony_ci status = DEMO_ERROR; 384a8e1175bSopenharmony_ci goto exit; 385a8e1175bSopenharmony_ci } 386a8e1175bSopenharmony_ci 387a8e1175bSopenharmony_ci /* Load the data to wrap. */ 388a8e1175bSopenharmony_ci SYS_CHECK(fseek(input_file, 0, SEEK_SET) == 0); 389a8e1175bSopenharmony_ci SYS_CHECK((buffer = calloc(1, buffer_size)) != NULL); 390a8e1175bSopenharmony_ci SYS_CHECK(fread(buffer, 1, input_size, input_file) == input_size); 391a8e1175bSopenharmony_ci SYS_CHECK(fclose(input_file) == 0); 392a8e1175bSopenharmony_ci input_file = NULL; 393a8e1175bSopenharmony_ci 394a8e1175bSopenharmony_ci /* Construct a header. */ 395a8e1175bSopenharmony_ci memcpy(&header.magic, WRAPPED_DATA_MAGIC, WRAPPED_DATA_MAGIC_LENGTH); 396a8e1175bSopenharmony_ci header.ad_size = sizeof(header); 397a8e1175bSopenharmony_ci header.payload_size = input_size; 398a8e1175bSopenharmony_ci 399a8e1175bSopenharmony_ci /* Wrap the data. */ 400a8e1175bSopenharmony_ci PSA_CHECK(psa_generate_random(header.iv, WRAPPING_IV_SIZE)); 401a8e1175bSopenharmony_ci PSA_CHECK(psa_aead_encrypt(wrapping_key, WRAPPING_ALG, 402a8e1175bSopenharmony_ci header.iv, WRAPPING_IV_SIZE, 403a8e1175bSopenharmony_ci (uint8_t *) &header, sizeof(header), 404a8e1175bSopenharmony_ci buffer, input_size, 405a8e1175bSopenharmony_ci buffer, buffer_size, 406a8e1175bSopenharmony_ci &ciphertext_size)); 407a8e1175bSopenharmony_ci 408a8e1175bSopenharmony_ci /* Write the output. */ 409a8e1175bSopenharmony_ci SYS_CHECK((output_file = fopen(output_file_name, "wb")) != NULL); 410a8e1175bSopenharmony_ci /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ 411a8e1175bSopenharmony_ci mbedtls_setbuf(output_file, NULL); 412a8e1175bSopenharmony_ci SYS_CHECK(fwrite(&header, 1, sizeof(header), 413a8e1175bSopenharmony_ci output_file) == sizeof(header)); 414a8e1175bSopenharmony_ci SYS_CHECK(fwrite(buffer, 1, ciphertext_size, 415a8e1175bSopenharmony_ci output_file) == ciphertext_size); 416a8e1175bSopenharmony_ci SYS_CHECK(fclose(output_file) == 0); 417a8e1175bSopenharmony_ci output_file = NULL; 418a8e1175bSopenharmony_ci 419a8e1175bSopenharmony_ciexit: 420a8e1175bSopenharmony_ci if (input_file != NULL) { 421a8e1175bSopenharmony_ci fclose(input_file); 422a8e1175bSopenharmony_ci } 423a8e1175bSopenharmony_ci if (output_file != NULL) { 424a8e1175bSopenharmony_ci fclose(output_file); 425a8e1175bSopenharmony_ci } 426a8e1175bSopenharmony_ci if (buffer != NULL) { 427a8e1175bSopenharmony_ci mbedtls_platform_zeroize(buffer, buffer_size); 428a8e1175bSopenharmony_ci } 429a8e1175bSopenharmony_ci free(buffer); 430a8e1175bSopenharmony_ci return status; 431a8e1175bSopenharmony_ci} 432a8e1175bSopenharmony_ci 433a8e1175bSopenharmony_cistatic psa_status_t unwrap_data(const char *input_file_name, 434a8e1175bSopenharmony_ci const char *output_file_name, 435a8e1175bSopenharmony_ci psa_key_id_t wrapping_key) 436a8e1175bSopenharmony_ci{ 437a8e1175bSopenharmony_ci psa_status_t status; 438a8e1175bSopenharmony_ci FILE *input_file = NULL; 439a8e1175bSopenharmony_ci FILE *output_file = NULL; 440a8e1175bSopenharmony_ci psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 441a8e1175bSopenharmony_ci psa_key_type_t key_type; 442a8e1175bSopenharmony_ci unsigned char *buffer = NULL; 443a8e1175bSopenharmony_ci size_t ciphertext_size = 0; 444a8e1175bSopenharmony_ci size_t plaintext_size; 445a8e1175bSopenharmony_ci wrapped_data_header_t header; 446a8e1175bSopenharmony_ci unsigned char extra_byte; 447a8e1175bSopenharmony_ci 448a8e1175bSopenharmony_ci /* Load and validate the header. */ 449a8e1175bSopenharmony_ci SYS_CHECK((input_file = fopen(input_file_name, "rb")) != NULL); 450a8e1175bSopenharmony_ci /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ 451a8e1175bSopenharmony_ci mbedtls_setbuf(input_file, NULL); 452a8e1175bSopenharmony_ci SYS_CHECK(fread(&header, 1, sizeof(header), 453a8e1175bSopenharmony_ci input_file) == sizeof(header)); 454a8e1175bSopenharmony_ci if (memcmp(&header.magic, WRAPPED_DATA_MAGIC, 455a8e1175bSopenharmony_ci WRAPPED_DATA_MAGIC_LENGTH) != 0) { 456a8e1175bSopenharmony_ci printf("The input does not start with a valid magic header.\n"); 457a8e1175bSopenharmony_ci status = DEMO_ERROR; 458a8e1175bSopenharmony_ci goto exit; 459a8e1175bSopenharmony_ci } 460a8e1175bSopenharmony_ci if (header.ad_size != sizeof(header)) { 461a8e1175bSopenharmony_ci printf("The header size is not correct.\n"); 462a8e1175bSopenharmony_ci status = DEMO_ERROR; 463a8e1175bSopenharmony_ci goto exit; 464a8e1175bSopenharmony_ci } 465a8e1175bSopenharmony_ci PSA_CHECK(psa_get_key_attributes(wrapping_key, &attributes)); 466a8e1175bSopenharmony_ci key_type = psa_get_key_type(&attributes); 467a8e1175bSopenharmony_ci ciphertext_size = 468a8e1175bSopenharmony_ci PSA_AEAD_ENCRYPT_OUTPUT_SIZE(key_type, WRAPPING_ALG, header.payload_size); 469a8e1175bSopenharmony_ci /* Check for integer overflow. */ 470a8e1175bSopenharmony_ci if (ciphertext_size < header.payload_size) { 471a8e1175bSopenharmony_ci printf("Input file too large.\n"); 472a8e1175bSopenharmony_ci status = DEMO_ERROR; 473a8e1175bSopenharmony_ci goto exit; 474a8e1175bSopenharmony_ci } 475a8e1175bSopenharmony_ci 476a8e1175bSopenharmony_ci /* Load the payload data. */ 477a8e1175bSopenharmony_ci SYS_CHECK((buffer = calloc(1, ciphertext_size)) != NULL); 478a8e1175bSopenharmony_ci SYS_CHECK(fread(buffer, 1, ciphertext_size, 479a8e1175bSopenharmony_ci input_file) == ciphertext_size); 480a8e1175bSopenharmony_ci if (fread(&extra_byte, 1, 1, input_file) != 0) { 481a8e1175bSopenharmony_ci printf("Extra garbage after ciphertext\n"); 482a8e1175bSopenharmony_ci status = DEMO_ERROR; 483a8e1175bSopenharmony_ci goto exit; 484a8e1175bSopenharmony_ci } 485a8e1175bSopenharmony_ci SYS_CHECK(fclose(input_file) == 0); 486a8e1175bSopenharmony_ci input_file = NULL; 487a8e1175bSopenharmony_ci 488a8e1175bSopenharmony_ci /* Unwrap the data. */ 489a8e1175bSopenharmony_ci PSA_CHECK(psa_aead_decrypt(wrapping_key, WRAPPING_ALG, 490a8e1175bSopenharmony_ci header.iv, WRAPPING_IV_SIZE, 491a8e1175bSopenharmony_ci (uint8_t *) &header, sizeof(header), 492a8e1175bSopenharmony_ci buffer, ciphertext_size, 493a8e1175bSopenharmony_ci buffer, ciphertext_size, 494a8e1175bSopenharmony_ci &plaintext_size)); 495a8e1175bSopenharmony_ci if (plaintext_size != header.payload_size) { 496a8e1175bSopenharmony_ci printf("Incorrect payload size in the header.\n"); 497a8e1175bSopenharmony_ci status = DEMO_ERROR; 498a8e1175bSopenharmony_ci goto exit; 499a8e1175bSopenharmony_ci } 500a8e1175bSopenharmony_ci 501a8e1175bSopenharmony_ci /* Write the output. */ 502a8e1175bSopenharmony_ci SYS_CHECK((output_file = fopen(output_file_name, "wb")) != NULL); 503a8e1175bSopenharmony_ci /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ 504a8e1175bSopenharmony_ci mbedtls_setbuf(output_file, NULL); 505a8e1175bSopenharmony_ci SYS_CHECK(fwrite(buffer, 1, plaintext_size, 506a8e1175bSopenharmony_ci output_file) == plaintext_size); 507a8e1175bSopenharmony_ci SYS_CHECK(fclose(output_file) == 0); 508a8e1175bSopenharmony_ci output_file = NULL; 509a8e1175bSopenharmony_ci 510a8e1175bSopenharmony_ciexit: 511a8e1175bSopenharmony_ci if (input_file != NULL) { 512a8e1175bSopenharmony_ci fclose(input_file); 513a8e1175bSopenharmony_ci } 514a8e1175bSopenharmony_ci if (output_file != NULL) { 515a8e1175bSopenharmony_ci fclose(output_file); 516a8e1175bSopenharmony_ci } 517a8e1175bSopenharmony_ci if (buffer != NULL) { 518a8e1175bSopenharmony_ci mbedtls_platform_zeroize(buffer, ciphertext_size); 519a8e1175bSopenharmony_ci } 520a8e1175bSopenharmony_ci free(buffer); 521a8e1175bSopenharmony_ci return status; 522a8e1175bSopenharmony_ci} 523a8e1175bSopenharmony_ci 524a8e1175bSopenharmony_cistatic psa_status_t run(enum program_mode mode, 525a8e1175bSopenharmony_ci const char *key_file_name, 526a8e1175bSopenharmony_ci const char *ladder[], size_t ladder_depth, 527a8e1175bSopenharmony_ci const char *input_file_name, 528a8e1175bSopenharmony_ci const char *output_file_name) 529a8e1175bSopenharmony_ci{ 530a8e1175bSopenharmony_ci psa_status_t status = PSA_SUCCESS; 531a8e1175bSopenharmony_ci psa_key_id_t derivation_key = 0; 532a8e1175bSopenharmony_ci psa_key_id_t wrapping_key = 0; 533a8e1175bSopenharmony_ci 534a8e1175bSopenharmony_ci /* Initialize the PSA crypto library. */ 535a8e1175bSopenharmony_ci PSA_CHECK(psa_crypto_init()); 536a8e1175bSopenharmony_ci 537a8e1175bSopenharmony_ci /* Generate mode is unlike the others. Generate the master key and exit. */ 538a8e1175bSopenharmony_ci if (mode == MODE_GENERATE) { 539a8e1175bSopenharmony_ci return generate(key_file_name); 540a8e1175bSopenharmony_ci } 541a8e1175bSopenharmony_ci 542a8e1175bSopenharmony_ci /* Read the master key. */ 543a8e1175bSopenharmony_ci PSA_CHECK(import_key_from_file(PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT, 544a8e1175bSopenharmony_ci KDF_ALG, 545a8e1175bSopenharmony_ci key_file_name, 546a8e1175bSopenharmony_ci &derivation_key)); 547a8e1175bSopenharmony_ci 548a8e1175bSopenharmony_ci /* Calculate the derived key for this session. */ 549a8e1175bSopenharmony_ci PSA_CHECK(derive_key_ladder(ladder, ladder_depth, 550a8e1175bSopenharmony_ci &derivation_key)); 551a8e1175bSopenharmony_ci 552a8e1175bSopenharmony_ci switch (mode) { 553a8e1175bSopenharmony_ci case MODE_SAVE: 554a8e1175bSopenharmony_ci PSA_CHECK(save_key(derivation_key, output_file_name)); 555a8e1175bSopenharmony_ci break; 556a8e1175bSopenharmony_ci case MODE_UNWRAP: 557a8e1175bSopenharmony_ci PSA_CHECK(derive_wrapping_key(PSA_KEY_USAGE_DECRYPT, 558a8e1175bSopenharmony_ci derivation_key, 559a8e1175bSopenharmony_ci &wrapping_key)); 560a8e1175bSopenharmony_ci PSA_CHECK(unwrap_data(input_file_name, output_file_name, 561a8e1175bSopenharmony_ci wrapping_key)); 562a8e1175bSopenharmony_ci break; 563a8e1175bSopenharmony_ci case MODE_WRAP: 564a8e1175bSopenharmony_ci PSA_CHECK(derive_wrapping_key(PSA_KEY_USAGE_ENCRYPT, 565a8e1175bSopenharmony_ci derivation_key, 566a8e1175bSopenharmony_ci &wrapping_key)); 567a8e1175bSopenharmony_ci PSA_CHECK(wrap_data(input_file_name, output_file_name, 568a8e1175bSopenharmony_ci wrapping_key)); 569a8e1175bSopenharmony_ci break; 570a8e1175bSopenharmony_ci default: 571a8e1175bSopenharmony_ci /* Unreachable but some compilers don't realize it. */ 572a8e1175bSopenharmony_ci break; 573a8e1175bSopenharmony_ci } 574a8e1175bSopenharmony_ci 575a8e1175bSopenharmony_ciexit: 576a8e1175bSopenharmony_ci /* Destroy any remaining key. Deinitializing the crypto library would do 577a8e1175bSopenharmony_ci * this anyway since they are volatile keys, but explicitly destroying 578a8e1175bSopenharmony_ci * keys makes the code easier to reuse. */ 579a8e1175bSopenharmony_ci (void) psa_destroy_key(derivation_key); 580a8e1175bSopenharmony_ci (void) psa_destroy_key(wrapping_key); 581a8e1175bSopenharmony_ci /* Deinitialize the PSA crypto library. */ 582a8e1175bSopenharmony_ci mbedtls_psa_crypto_free(); 583a8e1175bSopenharmony_ci return status; 584a8e1175bSopenharmony_ci} 585a8e1175bSopenharmony_ci 586a8e1175bSopenharmony_cistatic void usage(void) 587a8e1175bSopenharmony_ci{ 588a8e1175bSopenharmony_ci printf("Usage: key_ladder_demo MODE [OPTION=VALUE]...\n"); 589a8e1175bSopenharmony_ci printf("Demonstrate the usage of a key derivation ladder.\n"); 590a8e1175bSopenharmony_ci printf("\n"); 591a8e1175bSopenharmony_ci printf("Modes:\n"); 592a8e1175bSopenharmony_ci printf(" generate Generate the master key\n"); 593a8e1175bSopenharmony_ci printf(" save Save the derived key\n"); 594a8e1175bSopenharmony_ci printf(" unwrap Unwrap (decrypt) input with the derived key\n"); 595a8e1175bSopenharmony_ci printf(" wrap Wrap (encrypt) input with the derived key\n"); 596a8e1175bSopenharmony_ci printf("\n"); 597a8e1175bSopenharmony_ci printf("Options:\n"); 598a8e1175bSopenharmony_ci printf(" input=FILENAME Input file (required for wrap/unwrap)\n"); 599a8e1175bSopenharmony_ci printf(" master=FILENAME File containing the master key (default: master.key)\n"); 600a8e1175bSopenharmony_ci printf(" output=FILENAME Output file (required for save/wrap/unwrap)\n"); 601a8e1175bSopenharmony_ci printf(" label=TEXT Label for the key derivation.\n"); 602a8e1175bSopenharmony_ci printf(" This may be repeated multiple times.\n"); 603a8e1175bSopenharmony_ci printf(" To get the same key, you must use the same master key\n"); 604a8e1175bSopenharmony_ci printf(" and the same sequence of labels.\n"); 605a8e1175bSopenharmony_ci} 606a8e1175bSopenharmony_ci 607a8e1175bSopenharmony_ciint main(int argc, char *argv[]) 608a8e1175bSopenharmony_ci{ 609a8e1175bSopenharmony_ci const char *key_file_name = "master.key"; 610a8e1175bSopenharmony_ci const char *input_file_name = NULL; 611a8e1175bSopenharmony_ci const char *output_file_name = NULL; 612a8e1175bSopenharmony_ci const char *ladder[MAX_LADDER_DEPTH]; 613a8e1175bSopenharmony_ci size_t ladder_depth = 0; 614a8e1175bSopenharmony_ci int i; 615a8e1175bSopenharmony_ci enum program_mode mode; 616a8e1175bSopenharmony_ci psa_status_t status; 617a8e1175bSopenharmony_ci 618a8e1175bSopenharmony_ci if (argc <= 1 || 619a8e1175bSopenharmony_ci strcmp(argv[1], "help") == 0 || 620a8e1175bSopenharmony_ci strcmp(argv[1], "-help") == 0 || 621a8e1175bSopenharmony_ci strcmp(argv[1], "--help") == 0) { 622a8e1175bSopenharmony_ci usage(); 623a8e1175bSopenharmony_ci return EXIT_SUCCESS; 624a8e1175bSopenharmony_ci } 625a8e1175bSopenharmony_ci 626a8e1175bSopenharmony_ci for (i = 2; i < argc; i++) { 627a8e1175bSopenharmony_ci char *q = strchr(argv[i], '='); 628a8e1175bSopenharmony_ci if (q == NULL) { 629a8e1175bSopenharmony_ci printf("Missing argument to option %s\n", argv[i]); 630a8e1175bSopenharmony_ci goto usage_failure; 631a8e1175bSopenharmony_ci } 632a8e1175bSopenharmony_ci *q = 0; 633a8e1175bSopenharmony_ci ++q; 634a8e1175bSopenharmony_ci if (strcmp(argv[i], "input") == 0) { 635a8e1175bSopenharmony_ci input_file_name = q; 636a8e1175bSopenharmony_ci } else if (strcmp(argv[i], "label") == 0) { 637a8e1175bSopenharmony_ci if (ladder_depth == MAX_LADDER_DEPTH) { 638a8e1175bSopenharmony_ci printf("Maximum ladder depth %u exceeded.\n", 639a8e1175bSopenharmony_ci (unsigned) MAX_LADDER_DEPTH); 640a8e1175bSopenharmony_ci return EXIT_FAILURE; 641a8e1175bSopenharmony_ci } 642a8e1175bSopenharmony_ci ladder[ladder_depth] = q; 643a8e1175bSopenharmony_ci ++ladder_depth; 644a8e1175bSopenharmony_ci } else if (strcmp(argv[i], "master") == 0) { 645a8e1175bSopenharmony_ci key_file_name = q; 646a8e1175bSopenharmony_ci } else if (strcmp(argv[i], "output") == 0) { 647a8e1175bSopenharmony_ci output_file_name = q; 648a8e1175bSopenharmony_ci } else { 649a8e1175bSopenharmony_ci printf("Unknown option: %s\n", argv[i]); 650a8e1175bSopenharmony_ci goto usage_failure; 651a8e1175bSopenharmony_ci } 652a8e1175bSopenharmony_ci } 653a8e1175bSopenharmony_ci 654a8e1175bSopenharmony_ci if (strcmp(argv[1], "generate") == 0) { 655a8e1175bSopenharmony_ci mode = MODE_GENERATE; 656a8e1175bSopenharmony_ci } else if (strcmp(argv[1], "save") == 0) { 657a8e1175bSopenharmony_ci mode = MODE_SAVE; 658a8e1175bSopenharmony_ci } else if (strcmp(argv[1], "unwrap") == 0) { 659a8e1175bSopenharmony_ci mode = MODE_UNWRAP; 660a8e1175bSopenharmony_ci } else if (strcmp(argv[1], "wrap") == 0) { 661a8e1175bSopenharmony_ci mode = MODE_WRAP; 662a8e1175bSopenharmony_ci } else { 663a8e1175bSopenharmony_ci printf("Unknown action: %s\n", argv[1]); 664a8e1175bSopenharmony_ci goto usage_failure; 665a8e1175bSopenharmony_ci } 666a8e1175bSopenharmony_ci 667a8e1175bSopenharmony_ci if (input_file_name == NULL && 668a8e1175bSopenharmony_ci (mode == MODE_WRAP || mode == MODE_UNWRAP)) { 669a8e1175bSopenharmony_ci printf("Required argument missing: input\n"); 670a8e1175bSopenharmony_ci return DEMO_ERROR; 671a8e1175bSopenharmony_ci } 672a8e1175bSopenharmony_ci if (output_file_name == NULL && 673a8e1175bSopenharmony_ci (mode == MODE_SAVE || mode == MODE_WRAP || mode == MODE_UNWRAP)) { 674a8e1175bSopenharmony_ci printf("Required argument missing: output\n"); 675a8e1175bSopenharmony_ci return DEMO_ERROR; 676a8e1175bSopenharmony_ci } 677a8e1175bSopenharmony_ci 678a8e1175bSopenharmony_ci status = run(mode, key_file_name, 679a8e1175bSopenharmony_ci ladder, ladder_depth, 680a8e1175bSopenharmony_ci input_file_name, output_file_name); 681a8e1175bSopenharmony_ci return status == PSA_SUCCESS ? 682a8e1175bSopenharmony_ci EXIT_SUCCESS : 683a8e1175bSopenharmony_ci EXIT_FAILURE; 684a8e1175bSopenharmony_ci 685a8e1175bSopenharmony_ciusage_failure: 686a8e1175bSopenharmony_ci usage(); 687a8e1175bSopenharmony_ci return EXIT_FAILURE; 688a8e1175bSopenharmony_ci} 689a8e1175bSopenharmony_ci#endif /* PSA_WANT_ALG_SHA_256 && MBEDTLS_MD_C && 690a8e1175bSopenharmony_ci MBEDTLS_AES_C && MBEDTLS_CCM_C && 691a8e1175bSopenharmony_ci MBEDTLS_PSA_CRYPTO_C && MBEDTLS_FS_IO */ 692