1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include <stdio.h> 11e1051a39Sopenharmony_ci#include <stdlib.h> 12e1051a39Sopenharmony_ci#include <string.h> 13e1051a39Sopenharmony_ci#include <limits.h> 14e1051a39Sopenharmony_ci#include "apps.h" 15e1051a39Sopenharmony_ci#include "progs.h" 16e1051a39Sopenharmony_ci#include <openssl/bio.h> 17e1051a39Sopenharmony_ci#include <openssl/err.h> 18e1051a39Sopenharmony_ci#include <openssl/evp.h> 19e1051a39Sopenharmony_ci#include <openssl/objects.h> 20e1051a39Sopenharmony_ci#include <openssl/x509.h> 21e1051a39Sopenharmony_ci#include <openssl/rand.h> 22e1051a39Sopenharmony_ci#include <openssl/pem.h> 23e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_COMP 24e1051a39Sopenharmony_ci# include <openssl/comp.h> 25e1051a39Sopenharmony_ci#endif 26e1051a39Sopenharmony_ci#include <ctype.h> 27e1051a39Sopenharmony_ci 28e1051a39Sopenharmony_ci#undef SIZE 29e1051a39Sopenharmony_ci#undef BSIZE 30e1051a39Sopenharmony_ci#define SIZE (512) 31e1051a39Sopenharmony_ci#define BSIZE (8*1024) 32e1051a39Sopenharmony_ci 33e1051a39Sopenharmony_ci#define PBKDF2_ITER_DEFAULT 10000 34e1051a39Sopenharmony_ci#define STR(a) XSTR(a) 35e1051a39Sopenharmony_ci#define XSTR(a) #a 36e1051a39Sopenharmony_ci 37e1051a39Sopenharmony_cistatic int set_hex(const char *in, unsigned char *out, int size); 38e1051a39Sopenharmony_cistatic void show_ciphers(const OBJ_NAME *name, void *bio_); 39e1051a39Sopenharmony_ci 40e1051a39Sopenharmony_cistruct doall_enc_ciphers { 41e1051a39Sopenharmony_ci BIO *bio; 42e1051a39Sopenharmony_ci int n; 43e1051a39Sopenharmony_ci}; 44e1051a39Sopenharmony_ci 45e1051a39Sopenharmony_citypedef enum OPTION_choice { 46e1051a39Sopenharmony_ci OPT_COMMON, 47e1051a39Sopenharmony_ci OPT_LIST, 48e1051a39Sopenharmony_ci OPT_E, OPT_IN, OPT_OUT, OPT_PASS, OPT_ENGINE, OPT_D, OPT_P, OPT_V, 49e1051a39Sopenharmony_ci OPT_NOPAD, OPT_SALT, OPT_NOSALT, OPT_DEBUG, OPT_UPPER_P, OPT_UPPER_A, 50e1051a39Sopenharmony_ci OPT_A, OPT_Z, OPT_BUFSIZE, OPT_K, OPT_KFILE, OPT_UPPER_K, OPT_NONE, 51e1051a39Sopenharmony_ci OPT_UPPER_S, OPT_IV, OPT_MD, OPT_ITER, OPT_PBKDF2, OPT_CIPHER, 52e1051a39Sopenharmony_ci OPT_R_ENUM, OPT_PROV_ENUM 53e1051a39Sopenharmony_ci} OPTION_CHOICE; 54e1051a39Sopenharmony_ci 55e1051a39Sopenharmony_ciconst OPTIONS enc_options[] = { 56e1051a39Sopenharmony_ci OPT_SECTION("General"), 57e1051a39Sopenharmony_ci {"help", OPT_HELP, '-', "Display this summary"}, 58e1051a39Sopenharmony_ci {"list", OPT_LIST, '-', "List ciphers"}, 59e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DEPRECATED_3_0 60e1051a39Sopenharmony_ci {"ciphers", OPT_LIST, '-', "Alias for -list"}, 61e1051a39Sopenharmony_ci#endif 62e1051a39Sopenharmony_ci {"e", OPT_E, '-', "Encrypt"}, 63e1051a39Sopenharmony_ci {"d", OPT_D, '-', "Decrypt"}, 64e1051a39Sopenharmony_ci {"p", OPT_P, '-', "Print the iv/key"}, 65e1051a39Sopenharmony_ci {"P", OPT_UPPER_P, '-', "Print the iv/key and exit"}, 66e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_ENGINE 67e1051a39Sopenharmony_ci {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, 68e1051a39Sopenharmony_ci#endif 69e1051a39Sopenharmony_ci 70e1051a39Sopenharmony_ci OPT_SECTION("Input"), 71e1051a39Sopenharmony_ci {"in", OPT_IN, '<', "Input file"}, 72e1051a39Sopenharmony_ci {"k", OPT_K, 's', "Passphrase"}, 73e1051a39Sopenharmony_ci {"kfile", OPT_KFILE, '<', "Read passphrase from file"}, 74e1051a39Sopenharmony_ci 75e1051a39Sopenharmony_ci OPT_SECTION("Output"), 76e1051a39Sopenharmony_ci {"out", OPT_OUT, '>', "Output file"}, 77e1051a39Sopenharmony_ci {"pass", OPT_PASS, 's', "Passphrase source"}, 78e1051a39Sopenharmony_ci {"v", OPT_V, '-', "Verbose output"}, 79e1051a39Sopenharmony_ci {"a", OPT_A, '-', "Base64 encode/decode, depending on encryption flag"}, 80e1051a39Sopenharmony_ci {"base64", OPT_A, '-', "Same as option -a"}, 81e1051a39Sopenharmony_ci {"A", OPT_UPPER_A, '-', 82e1051a39Sopenharmony_ci "Used with -[base64|a] to specify base64 buffer as a single line"}, 83e1051a39Sopenharmony_ci 84e1051a39Sopenharmony_ci OPT_SECTION("Encryption"), 85e1051a39Sopenharmony_ci {"nopad", OPT_NOPAD, '-', "Disable standard block padding"}, 86e1051a39Sopenharmony_ci {"salt", OPT_SALT, '-', "Use salt in the KDF (default)"}, 87e1051a39Sopenharmony_ci {"nosalt", OPT_NOSALT, '-', "Do not use salt in the KDF"}, 88e1051a39Sopenharmony_ci {"debug", OPT_DEBUG, '-', "Print debug info"}, 89e1051a39Sopenharmony_ci 90e1051a39Sopenharmony_ci {"bufsize", OPT_BUFSIZE, 's', "Buffer size"}, 91e1051a39Sopenharmony_ci {"K", OPT_UPPER_K, 's', "Raw key, in hex"}, 92e1051a39Sopenharmony_ci {"S", OPT_UPPER_S, 's', "Salt, in hex"}, 93e1051a39Sopenharmony_ci {"iv", OPT_IV, 's', "IV in hex"}, 94e1051a39Sopenharmony_ci {"md", OPT_MD, 's', "Use specified digest to create a key from the passphrase"}, 95e1051a39Sopenharmony_ci {"iter", OPT_ITER, 'p', 96e1051a39Sopenharmony_ci "Specify the iteration count and force the use of PBKDF2"}, 97e1051a39Sopenharmony_ci {OPT_MORE_STR, 0, 0, "Default: " STR(PBKDF2_ITER_DEFAULT)}, 98e1051a39Sopenharmony_ci {"pbkdf2", OPT_PBKDF2, '-', 99e1051a39Sopenharmony_ci "Use password-based key derivation function 2 (PBKDF2)"}, 100e1051a39Sopenharmony_ci {OPT_MORE_STR, 0, 0, 101e1051a39Sopenharmony_ci "Use -iter to change the iteration count from " STR(PBKDF2_ITER_DEFAULT)}, 102e1051a39Sopenharmony_ci {"none", OPT_NONE, '-', "Don't encrypt"}, 103e1051a39Sopenharmony_ci#ifdef ZLIB 104e1051a39Sopenharmony_ci {"z", OPT_Z, '-', "Compress or decompress encrypted data using zlib"}, 105e1051a39Sopenharmony_ci#endif 106e1051a39Sopenharmony_ci {"", OPT_CIPHER, '-', "Any supported cipher"}, 107e1051a39Sopenharmony_ci 108e1051a39Sopenharmony_ci OPT_R_OPTIONS, 109e1051a39Sopenharmony_ci OPT_PROV_OPTIONS, 110e1051a39Sopenharmony_ci {NULL} 111e1051a39Sopenharmony_ci}; 112e1051a39Sopenharmony_ci 113e1051a39Sopenharmony_ciint enc_main(int argc, char **argv) 114e1051a39Sopenharmony_ci{ 115e1051a39Sopenharmony_ci static char buf[128]; 116e1051a39Sopenharmony_ci static const char magic[] = "Salted__"; 117e1051a39Sopenharmony_ci ENGINE *e = NULL; 118e1051a39Sopenharmony_ci BIO *in = NULL, *out = NULL, *b64 = NULL, *benc = NULL, *rbio = 119e1051a39Sopenharmony_ci NULL, *wbio = NULL; 120e1051a39Sopenharmony_ci EVP_CIPHER_CTX *ctx = NULL; 121e1051a39Sopenharmony_ci EVP_CIPHER *cipher = NULL; 122e1051a39Sopenharmony_ci EVP_MD *dgst = NULL; 123e1051a39Sopenharmony_ci const char *digestname = NULL; 124e1051a39Sopenharmony_ci char *hkey = NULL, *hiv = NULL, *hsalt = NULL, *p; 125e1051a39Sopenharmony_ci char *infile = NULL, *outfile = NULL, *prog; 126e1051a39Sopenharmony_ci char *str = NULL, *passarg = NULL, *pass = NULL, *strbuf = NULL; 127e1051a39Sopenharmony_ci const char *ciphername = NULL; 128e1051a39Sopenharmony_ci char mbuf[sizeof(magic) - 1]; 129e1051a39Sopenharmony_ci OPTION_CHOICE o; 130e1051a39Sopenharmony_ci int bsize = BSIZE, verbose = 0, debug = 0, olb64 = 0, nosalt = 0; 131e1051a39Sopenharmony_ci int enc = 1, printkey = 0, i, k; 132e1051a39Sopenharmony_ci int base64 = 0, informat = FORMAT_BINARY, outformat = FORMAT_BINARY; 133e1051a39Sopenharmony_ci int ret = 1, inl, nopad = 0; 134e1051a39Sopenharmony_ci unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH]; 135e1051a39Sopenharmony_ci unsigned char *buff = NULL, salt[PKCS5_SALT_LEN]; 136e1051a39Sopenharmony_ci int pbkdf2 = 0; 137e1051a39Sopenharmony_ci int iter = 0; 138e1051a39Sopenharmony_ci long n; 139e1051a39Sopenharmony_ci struct doall_enc_ciphers dec; 140e1051a39Sopenharmony_ci#ifdef ZLIB 141e1051a39Sopenharmony_ci int do_zlib = 0; 142e1051a39Sopenharmony_ci BIO *bzl = NULL; 143e1051a39Sopenharmony_ci#endif 144e1051a39Sopenharmony_ci 145e1051a39Sopenharmony_ci /* first check the command name */ 146e1051a39Sopenharmony_ci if (strcmp(argv[0], "base64") == 0) 147e1051a39Sopenharmony_ci base64 = 1; 148e1051a39Sopenharmony_ci#ifdef ZLIB 149e1051a39Sopenharmony_ci else if (strcmp(argv[0], "zlib") == 0) 150e1051a39Sopenharmony_ci do_zlib = 1; 151e1051a39Sopenharmony_ci#endif 152e1051a39Sopenharmony_ci else if (strcmp(argv[0], "enc") != 0) 153e1051a39Sopenharmony_ci ciphername = argv[0]; 154e1051a39Sopenharmony_ci 155e1051a39Sopenharmony_ci prog = opt_init(argc, argv, enc_options); 156e1051a39Sopenharmony_ci while ((o = opt_next()) != OPT_EOF) { 157e1051a39Sopenharmony_ci switch (o) { 158e1051a39Sopenharmony_ci case OPT_EOF: 159e1051a39Sopenharmony_ci case OPT_ERR: 160e1051a39Sopenharmony_ci opthelp: 161e1051a39Sopenharmony_ci BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 162e1051a39Sopenharmony_ci goto end; 163e1051a39Sopenharmony_ci case OPT_HELP: 164e1051a39Sopenharmony_ci opt_help(enc_options); 165e1051a39Sopenharmony_ci ret = 0; 166e1051a39Sopenharmony_ci goto end; 167e1051a39Sopenharmony_ci case OPT_LIST: 168e1051a39Sopenharmony_ci BIO_printf(bio_out, "Supported ciphers:\n"); 169e1051a39Sopenharmony_ci dec.bio = bio_out; 170e1051a39Sopenharmony_ci dec.n = 0; 171e1051a39Sopenharmony_ci OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, 172e1051a39Sopenharmony_ci show_ciphers, &dec); 173e1051a39Sopenharmony_ci BIO_printf(bio_out, "\n"); 174e1051a39Sopenharmony_ci ret = 0; 175e1051a39Sopenharmony_ci goto end; 176e1051a39Sopenharmony_ci case OPT_E: 177e1051a39Sopenharmony_ci enc = 1; 178e1051a39Sopenharmony_ci break; 179e1051a39Sopenharmony_ci case OPT_IN: 180e1051a39Sopenharmony_ci infile = opt_arg(); 181e1051a39Sopenharmony_ci break; 182e1051a39Sopenharmony_ci case OPT_OUT: 183e1051a39Sopenharmony_ci outfile = opt_arg(); 184e1051a39Sopenharmony_ci break; 185e1051a39Sopenharmony_ci case OPT_PASS: 186e1051a39Sopenharmony_ci passarg = opt_arg(); 187e1051a39Sopenharmony_ci break; 188e1051a39Sopenharmony_ci case OPT_ENGINE: 189e1051a39Sopenharmony_ci e = setup_engine(opt_arg(), 0); 190e1051a39Sopenharmony_ci break; 191e1051a39Sopenharmony_ci case OPT_D: 192e1051a39Sopenharmony_ci enc = 0; 193e1051a39Sopenharmony_ci break; 194e1051a39Sopenharmony_ci case OPT_P: 195e1051a39Sopenharmony_ci printkey = 1; 196e1051a39Sopenharmony_ci break; 197e1051a39Sopenharmony_ci case OPT_V: 198e1051a39Sopenharmony_ci verbose = 1; 199e1051a39Sopenharmony_ci break; 200e1051a39Sopenharmony_ci case OPT_NOPAD: 201e1051a39Sopenharmony_ci nopad = 1; 202e1051a39Sopenharmony_ci break; 203e1051a39Sopenharmony_ci case OPT_SALT: 204e1051a39Sopenharmony_ci nosalt = 0; 205e1051a39Sopenharmony_ci break; 206e1051a39Sopenharmony_ci case OPT_NOSALT: 207e1051a39Sopenharmony_ci nosalt = 1; 208e1051a39Sopenharmony_ci break; 209e1051a39Sopenharmony_ci case OPT_DEBUG: 210e1051a39Sopenharmony_ci debug = 1; 211e1051a39Sopenharmony_ci break; 212e1051a39Sopenharmony_ci case OPT_UPPER_P: 213e1051a39Sopenharmony_ci printkey = 2; 214e1051a39Sopenharmony_ci break; 215e1051a39Sopenharmony_ci case OPT_UPPER_A: 216e1051a39Sopenharmony_ci olb64 = 1; 217e1051a39Sopenharmony_ci break; 218e1051a39Sopenharmony_ci case OPT_A: 219e1051a39Sopenharmony_ci base64 = 1; 220e1051a39Sopenharmony_ci break; 221e1051a39Sopenharmony_ci case OPT_Z: 222e1051a39Sopenharmony_ci#ifdef ZLIB 223e1051a39Sopenharmony_ci do_zlib = 1; 224e1051a39Sopenharmony_ci#endif 225e1051a39Sopenharmony_ci break; 226e1051a39Sopenharmony_ci case OPT_BUFSIZE: 227e1051a39Sopenharmony_ci p = opt_arg(); 228e1051a39Sopenharmony_ci i = (int)strlen(p) - 1; 229e1051a39Sopenharmony_ci k = i >= 1 && p[i] == 'k'; 230e1051a39Sopenharmony_ci if (k) 231e1051a39Sopenharmony_ci p[i] = '\0'; 232e1051a39Sopenharmony_ci if (!opt_long(opt_arg(), &n) 233e1051a39Sopenharmony_ci || n < 0 || (k && n >= LONG_MAX / 1024)) 234e1051a39Sopenharmony_ci goto opthelp; 235e1051a39Sopenharmony_ci if (k) 236e1051a39Sopenharmony_ci n *= 1024; 237e1051a39Sopenharmony_ci bsize = (int)n; 238e1051a39Sopenharmony_ci break; 239e1051a39Sopenharmony_ci case OPT_K: 240e1051a39Sopenharmony_ci str = opt_arg(); 241e1051a39Sopenharmony_ci break; 242e1051a39Sopenharmony_ci case OPT_KFILE: 243e1051a39Sopenharmony_ci in = bio_open_default(opt_arg(), 'r', FORMAT_TEXT); 244e1051a39Sopenharmony_ci if (in == NULL) 245e1051a39Sopenharmony_ci goto opthelp; 246e1051a39Sopenharmony_ci i = BIO_gets(in, buf, sizeof(buf)); 247e1051a39Sopenharmony_ci BIO_free(in); 248e1051a39Sopenharmony_ci in = NULL; 249e1051a39Sopenharmony_ci if (i <= 0) { 250e1051a39Sopenharmony_ci BIO_printf(bio_err, 251e1051a39Sopenharmony_ci "%s Can't read key from %s\n", prog, opt_arg()); 252e1051a39Sopenharmony_ci goto opthelp; 253e1051a39Sopenharmony_ci } 254e1051a39Sopenharmony_ci while (--i > 0 && (buf[i] == '\r' || buf[i] == '\n')) 255e1051a39Sopenharmony_ci buf[i] = '\0'; 256e1051a39Sopenharmony_ci if (i <= 0) { 257e1051a39Sopenharmony_ci BIO_printf(bio_err, "%s: zero length password\n", prog); 258e1051a39Sopenharmony_ci goto opthelp; 259e1051a39Sopenharmony_ci } 260e1051a39Sopenharmony_ci str = buf; 261e1051a39Sopenharmony_ci break; 262e1051a39Sopenharmony_ci case OPT_UPPER_K: 263e1051a39Sopenharmony_ci hkey = opt_arg(); 264e1051a39Sopenharmony_ci break; 265e1051a39Sopenharmony_ci case OPT_UPPER_S: 266e1051a39Sopenharmony_ci hsalt = opt_arg(); 267e1051a39Sopenharmony_ci break; 268e1051a39Sopenharmony_ci case OPT_IV: 269e1051a39Sopenharmony_ci hiv = opt_arg(); 270e1051a39Sopenharmony_ci break; 271e1051a39Sopenharmony_ci case OPT_MD: 272e1051a39Sopenharmony_ci digestname = opt_arg(); 273e1051a39Sopenharmony_ci break; 274e1051a39Sopenharmony_ci case OPT_CIPHER: 275e1051a39Sopenharmony_ci ciphername = opt_unknown(); 276e1051a39Sopenharmony_ci break; 277e1051a39Sopenharmony_ci case OPT_ITER: 278e1051a39Sopenharmony_ci iter = opt_int_arg(); 279e1051a39Sopenharmony_ci pbkdf2 = 1; 280e1051a39Sopenharmony_ci break; 281e1051a39Sopenharmony_ci case OPT_PBKDF2: 282e1051a39Sopenharmony_ci pbkdf2 = 1; 283e1051a39Sopenharmony_ci if (iter == 0) /* do not overwrite a chosen value */ 284e1051a39Sopenharmony_ci iter = PBKDF2_ITER_DEFAULT; 285e1051a39Sopenharmony_ci break; 286e1051a39Sopenharmony_ci case OPT_NONE: 287e1051a39Sopenharmony_ci cipher = NULL; 288e1051a39Sopenharmony_ci break; 289e1051a39Sopenharmony_ci case OPT_R_CASES: 290e1051a39Sopenharmony_ci if (!opt_rand(o)) 291e1051a39Sopenharmony_ci goto end; 292e1051a39Sopenharmony_ci break; 293e1051a39Sopenharmony_ci case OPT_PROV_CASES: 294e1051a39Sopenharmony_ci if (!opt_provider(o)) 295e1051a39Sopenharmony_ci goto end; 296e1051a39Sopenharmony_ci break; 297e1051a39Sopenharmony_ci } 298e1051a39Sopenharmony_ci } 299e1051a39Sopenharmony_ci 300e1051a39Sopenharmony_ci /* No extra arguments. */ 301e1051a39Sopenharmony_ci argc = opt_num_rest(); 302e1051a39Sopenharmony_ci if (argc != 0) 303e1051a39Sopenharmony_ci goto opthelp; 304e1051a39Sopenharmony_ci if (!app_RAND_load()) 305e1051a39Sopenharmony_ci goto end; 306e1051a39Sopenharmony_ci 307e1051a39Sopenharmony_ci /* Get the cipher name, either from progname (if set) or flag. */ 308e1051a39Sopenharmony_ci if (ciphername != NULL) { 309e1051a39Sopenharmony_ci if (!opt_cipher(ciphername, &cipher)) 310e1051a39Sopenharmony_ci goto opthelp; 311e1051a39Sopenharmony_ci } 312e1051a39Sopenharmony_ci if (digestname != NULL) { 313e1051a39Sopenharmony_ci if (!opt_md(digestname, &dgst)) 314e1051a39Sopenharmony_ci goto opthelp; 315e1051a39Sopenharmony_ci } 316e1051a39Sopenharmony_ci if (dgst == NULL) 317e1051a39Sopenharmony_ci dgst = (EVP_MD *)EVP_sha256(); 318e1051a39Sopenharmony_ci 319e1051a39Sopenharmony_ci if (iter == 0) 320e1051a39Sopenharmony_ci iter = 1; 321e1051a39Sopenharmony_ci 322e1051a39Sopenharmony_ci /* It must be large enough for a base64 encoded line */ 323e1051a39Sopenharmony_ci if (base64 && bsize < 80) 324e1051a39Sopenharmony_ci bsize = 80; 325e1051a39Sopenharmony_ci if (verbose) 326e1051a39Sopenharmony_ci BIO_printf(bio_err, "bufsize=%d\n", bsize); 327e1051a39Sopenharmony_ci 328e1051a39Sopenharmony_ci#ifdef ZLIB 329e1051a39Sopenharmony_ci if (!do_zlib) 330e1051a39Sopenharmony_ci#endif 331e1051a39Sopenharmony_ci if (base64) { 332e1051a39Sopenharmony_ci if (enc) 333e1051a39Sopenharmony_ci outformat = FORMAT_BASE64; 334e1051a39Sopenharmony_ci else 335e1051a39Sopenharmony_ci informat = FORMAT_BASE64; 336e1051a39Sopenharmony_ci } 337e1051a39Sopenharmony_ci 338e1051a39Sopenharmony_ci strbuf = app_malloc(SIZE, "strbuf"); 339e1051a39Sopenharmony_ci buff = app_malloc(EVP_ENCODE_LENGTH(bsize), "evp buffer"); 340e1051a39Sopenharmony_ci 341e1051a39Sopenharmony_ci if (infile == NULL) { 342e1051a39Sopenharmony_ci in = dup_bio_in(informat); 343e1051a39Sopenharmony_ci } else { 344e1051a39Sopenharmony_ci in = bio_open_default(infile, 'r', informat); 345e1051a39Sopenharmony_ci } 346e1051a39Sopenharmony_ci if (in == NULL) 347e1051a39Sopenharmony_ci goto end; 348e1051a39Sopenharmony_ci 349e1051a39Sopenharmony_ci if (str == NULL && passarg != NULL) { 350e1051a39Sopenharmony_ci if (!app_passwd(passarg, NULL, &pass, NULL)) { 351e1051a39Sopenharmony_ci BIO_printf(bio_err, "Error getting password\n"); 352e1051a39Sopenharmony_ci goto end; 353e1051a39Sopenharmony_ci } 354e1051a39Sopenharmony_ci str = pass; 355e1051a39Sopenharmony_ci } 356e1051a39Sopenharmony_ci 357e1051a39Sopenharmony_ci if ((str == NULL) && (cipher != NULL) && (hkey == NULL)) { 358e1051a39Sopenharmony_ci if (1) { 359e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_UI_CONSOLE 360e1051a39Sopenharmony_ci for (;;) { 361e1051a39Sopenharmony_ci char prompt[200]; 362e1051a39Sopenharmony_ci 363e1051a39Sopenharmony_ci BIO_snprintf(prompt, sizeof(prompt), "enter %s %s password:", 364e1051a39Sopenharmony_ci EVP_CIPHER_get0_name(cipher), 365e1051a39Sopenharmony_ci (enc) ? "encryption" : "decryption"); 366e1051a39Sopenharmony_ci strbuf[0] = '\0'; 367e1051a39Sopenharmony_ci i = EVP_read_pw_string((char *)strbuf, SIZE, prompt, enc); 368e1051a39Sopenharmony_ci if (i == 0) { 369e1051a39Sopenharmony_ci if (strbuf[0] == '\0') { 370e1051a39Sopenharmony_ci ret = 1; 371e1051a39Sopenharmony_ci goto end; 372e1051a39Sopenharmony_ci } 373e1051a39Sopenharmony_ci str = strbuf; 374e1051a39Sopenharmony_ci break; 375e1051a39Sopenharmony_ci } 376e1051a39Sopenharmony_ci if (i < 0) { 377e1051a39Sopenharmony_ci BIO_printf(bio_err, "bad password read\n"); 378e1051a39Sopenharmony_ci goto end; 379e1051a39Sopenharmony_ci } 380e1051a39Sopenharmony_ci } 381e1051a39Sopenharmony_ci } else { 382e1051a39Sopenharmony_ci#endif 383e1051a39Sopenharmony_ci BIO_printf(bio_err, "password required\n"); 384e1051a39Sopenharmony_ci goto end; 385e1051a39Sopenharmony_ci } 386e1051a39Sopenharmony_ci } 387e1051a39Sopenharmony_ci 388e1051a39Sopenharmony_ci out = bio_open_default(outfile, 'w', outformat); 389e1051a39Sopenharmony_ci if (out == NULL) 390e1051a39Sopenharmony_ci goto end; 391e1051a39Sopenharmony_ci 392e1051a39Sopenharmony_ci if (debug) { 393e1051a39Sopenharmony_ci BIO_set_callback_ex(in, BIO_debug_callback_ex); 394e1051a39Sopenharmony_ci BIO_set_callback_ex(out, BIO_debug_callback_ex); 395e1051a39Sopenharmony_ci BIO_set_callback_arg(in, (char *)bio_err); 396e1051a39Sopenharmony_ci BIO_set_callback_arg(out, (char *)bio_err); 397e1051a39Sopenharmony_ci } 398e1051a39Sopenharmony_ci 399e1051a39Sopenharmony_ci rbio = in; 400e1051a39Sopenharmony_ci wbio = out; 401e1051a39Sopenharmony_ci 402e1051a39Sopenharmony_ci#ifdef ZLIB 403e1051a39Sopenharmony_ci if (do_zlib) { 404e1051a39Sopenharmony_ci if ((bzl = BIO_new(BIO_f_zlib())) == NULL) 405e1051a39Sopenharmony_ci goto end; 406e1051a39Sopenharmony_ci if (debug) { 407e1051a39Sopenharmony_ci BIO_set_callback_ex(bzl, BIO_debug_callback_ex); 408e1051a39Sopenharmony_ci BIO_set_callback_arg(bzl, (char *)bio_err); 409e1051a39Sopenharmony_ci } 410e1051a39Sopenharmony_ci if (enc) 411e1051a39Sopenharmony_ci wbio = BIO_push(bzl, wbio); 412e1051a39Sopenharmony_ci else 413e1051a39Sopenharmony_ci rbio = BIO_push(bzl, rbio); 414e1051a39Sopenharmony_ci } 415e1051a39Sopenharmony_ci#endif 416e1051a39Sopenharmony_ci 417e1051a39Sopenharmony_ci if (base64) { 418e1051a39Sopenharmony_ci if ((b64 = BIO_new(BIO_f_base64())) == NULL) 419e1051a39Sopenharmony_ci goto end; 420e1051a39Sopenharmony_ci if (debug) { 421e1051a39Sopenharmony_ci BIO_set_callback_ex(b64, BIO_debug_callback_ex); 422e1051a39Sopenharmony_ci BIO_set_callback_arg(b64, (char *)bio_err); 423e1051a39Sopenharmony_ci } 424e1051a39Sopenharmony_ci if (olb64) 425e1051a39Sopenharmony_ci BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); 426e1051a39Sopenharmony_ci if (enc) 427e1051a39Sopenharmony_ci wbio = BIO_push(b64, wbio); 428e1051a39Sopenharmony_ci else 429e1051a39Sopenharmony_ci rbio = BIO_push(b64, rbio); 430e1051a39Sopenharmony_ci } 431e1051a39Sopenharmony_ci 432e1051a39Sopenharmony_ci if (cipher != NULL) { 433e1051a39Sopenharmony_ci if (str != NULL) { /* a passphrase is available */ 434e1051a39Sopenharmony_ci /* 435e1051a39Sopenharmony_ci * Salt handling: if encrypting generate a salt if not supplied, 436e1051a39Sopenharmony_ci * and write to output BIO. If decrypting use salt from input BIO 437e1051a39Sopenharmony_ci * if not given with args 438e1051a39Sopenharmony_ci */ 439e1051a39Sopenharmony_ci unsigned char *sptr; 440e1051a39Sopenharmony_ci size_t str_len = strlen(str); 441e1051a39Sopenharmony_ci 442e1051a39Sopenharmony_ci if (nosalt) { 443e1051a39Sopenharmony_ci sptr = NULL; 444e1051a39Sopenharmony_ci } else { 445e1051a39Sopenharmony_ci if (hsalt != NULL && !set_hex(hsalt, salt, sizeof(salt))) { 446e1051a39Sopenharmony_ci BIO_printf(bio_err, "invalid hex salt value\n"); 447e1051a39Sopenharmony_ci goto end; 448e1051a39Sopenharmony_ci } 449e1051a39Sopenharmony_ci if (enc) { /* encryption */ 450e1051a39Sopenharmony_ci if (hsalt == NULL) { 451e1051a39Sopenharmony_ci if (RAND_bytes(salt, sizeof(salt)) <= 0) { 452e1051a39Sopenharmony_ci BIO_printf(bio_err, "RAND_bytes failed\n"); 453e1051a39Sopenharmony_ci goto end; 454e1051a39Sopenharmony_ci } 455e1051a39Sopenharmony_ci /* 456e1051a39Sopenharmony_ci * If -P option then don't bother writing. 457e1051a39Sopenharmony_ci * If salt is given, shouldn't either ? 458e1051a39Sopenharmony_ci */ 459e1051a39Sopenharmony_ci if ((printkey != 2) 460e1051a39Sopenharmony_ci && (BIO_write(wbio, magic, 461e1051a39Sopenharmony_ci sizeof(magic) - 1) != sizeof(magic) - 1 462e1051a39Sopenharmony_ci || BIO_write(wbio, 463e1051a39Sopenharmony_ci (char *)salt, 464e1051a39Sopenharmony_ci sizeof(salt)) != sizeof(salt))) { 465e1051a39Sopenharmony_ci BIO_printf(bio_err, "error writing output file\n"); 466e1051a39Sopenharmony_ci goto end; 467e1051a39Sopenharmony_ci } 468e1051a39Sopenharmony_ci } 469e1051a39Sopenharmony_ci } else { /* decryption */ 470e1051a39Sopenharmony_ci if (hsalt == NULL) { 471e1051a39Sopenharmony_ci if (BIO_read(rbio, mbuf, sizeof(mbuf)) != sizeof(mbuf)) { 472e1051a39Sopenharmony_ci BIO_printf(bio_err, "error reading input file\n"); 473e1051a39Sopenharmony_ci goto end; 474e1051a39Sopenharmony_ci } 475e1051a39Sopenharmony_ci if (memcmp(mbuf, magic, sizeof(mbuf)) == 0) { /* file IS salted */ 476e1051a39Sopenharmony_ci if (BIO_read(rbio, salt, 477e1051a39Sopenharmony_ci sizeof(salt)) != sizeof(salt)) { 478e1051a39Sopenharmony_ci BIO_printf(bio_err, "error reading input file\n"); 479e1051a39Sopenharmony_ci goto end; 480e1051a39Sopenharmony_ci } 481e1051a39Sopenharmony_ci } else { /* file is NOT salted, NO salt available */ 482e1051a39Sopenharmony_ci BIO_printf(bio_err, "bad magic number\n"); 483e1051a39Sopenharmony_ci goto end; 484e1051a39Sopenharmony_ci } 485e1051a39Sopenharmony_ci } 486e1051a39Sopenharmony_ci } 487e1051a39Sopenharmony_ci sptr = salt; 488e1051a39Sopenharmony_ci } 489e1051a39Sopenharmony_ci 490e1051a39Sopenharmony_ci if (pbkdf2 == 1) { 491e1051a39Sopenharmony_ci /* 492e1051a39Sopenharmony_ci * derive key and default iv 493e1051a39Sopenharmony_ci * concatenated into a temporary buffer 494e1051a39Sopenharmony_ci */ 495e1051a39Sopenharmony_ci unsigned char tmpkeyiv[EVP_MAX_KEY_LENGTH + EVP_MAX_IV_LENGTH]; 496e1051a39Sopenharmony_ci int iklen = EVP_CIPHER_get_key_length(cipher); 497e1051a39Sopenharmony_ci int ivlen = EVP_CIPHER_get_iv_length(cipher); 498e1051a39Sopenharmony_ci /* not needed if HASH_UPDATE() is fixed : */ 499e1051a39Sopenharmony_ci int islen = (sptr != NULL ? sizeof(salt) : 0); 500e1051a39Sopenharmony_ci if (!PKCS5_PBKDF2_HMAC(str, str_len, sptr, islen, 501e1051a39Sopenharmony_ci iter, dgst, iklen+ivlen, tmpkeyiv)) { 502e1051a39Sopenharmony_ci BIO_printf(bio_err, "PKCS5_PBKDF2_HMAC failed\n"); 503e1051a39Sopenharmony_ci goto end; 504e1051a39Sopenharmony_ci } 505e1051a39Sopenharmony_ci /* split and move data back to global buffer */ 506e1051a39Sopenharmony_ci memcpy(key, tmpkeyiv, iklen); 507e1051a39Sopenharmony_ci memcpy(iv, tmpkeyiv+iklen, ivlen); 508e1051a39Sopenharmony_ci } else { 509e1051a39Sopenharmony_ci BIO_printf(bio_err, "*** WARNING : " 510e1051a39Sopenharmony_ci "deprecated key derivation used.\n" 511e1051a39Sopenharmony_ci "Using -iter or -pbkdf2 would be better.\n"); 512e1051a39Sopenharmony_ci if (!EVP_BytesToKey(cipher, dgst, sptr, 513e1051a39Sopenharmony_ci (unsigned char *)str, str_len, 514e1051a39Sopenharmony_ci 1, key, iv)) { 515e1051a39Sopenharmony_ci BIO_printf(bio_err, "EVP_BytesToKey failed\n"); 516e1051a39Sopenharmony_ci goto end; 517e1051a39Sopenharmony_ci } 518e1051a39Sopenharmony_ci } 519e1051a39Sopenharmony_ci /* 520e1051a39Sopenharmony_ci * zero the complete buffer or the string passed from the command 521e1051a39Sopenharmony_ci * line. 522e1051a39Sopenharmony_ci */ 523e1051a39Sopenharmony_ci if (str == strbuf) 524e1051a39Sopenharmony_ci OPENSSL_cleanse(str, SIZE); 525e1051a39Sopenharmony_ci else 526e1051a39Sopenharmony_ci OPENSSL_cleanse(str, str_len); 527e1051a39Sopenharmony_ci } 528e1051a39Sopenharmony_ci if (hiv != NULL) { 529e1051a39Sopenharmony_ci int siz = EVP_CIPHER_get_iv_length(cipher); 530e1051a39Sopenharmony_ci if (siz == 0) { 531e1051a39Sopenharmony_ci BIO_printf(bio_err, "warning: iv not used by this cipher\n"); 532e1051a39Sopenharmony_ci } else if (!set_hex(hiv, iv, siz)) { 533e1051a39Sopenharmony_ci BIO_printf(bio_err, "invalid hex iv value\n"); 534e1051a39Sopenharmony_ci goto end; 535e1051a39Sopenharmony_ci } 536e1051a39Sopenharmony_ci } 537e1051a39Sopenharmony_ci if ((hiv == NULL) && (str == NULL) 538e1051a39Sopenharmony_ci && EVP_CIPHER_get_iv_length(cipher) != 0) { 539e1051a39Sopenharmony_ci /* 540e1051a39Sopenharmony_ci * No IV was explicitly set and no IV was generated. 541e1051a39Sopenharmony_ci * Hence the IV is undefined, making correct decryption impossible. 542e1051a39Sopenharmony_ci */ 543e1051a39Sopenharmony_ci BIO_printf(bio_err, "iv undefined\n"); 544e1051a39Sopenharmony_ci goto end; 545e1051a39Sopenharmony_ci } 546e1051a39Sopenharmony_ci if (hkey != NULL) { 547e1051a39Sopenharmony_ci if (!set_hex(hkey, key, EVP_CIPHER_get_key_length(cipher))) { 548e1051a39Sopenharmony_ci BIO_printf(bio_err, "invalid hex key value\n"); 549e1051a39Sopenharmony_ci goto end; 550e1051a39Sopenharmony_ci } 551e1051a39Sopenharmony_ci /* wiping secret data as we no longer need it */ 552e1051a39Sopenharmony_ci cleanse(hkey); 553e1051a39Sopenharmony_ci } 554e1051a39Sopenharmony_ci 555e1051a39Sopenharmony_ci if ((benc = BIO_new(BIO_f_cipher())) == NULL) 556e1051a39Sopenharmony_ci goto end; 557e1051a39Sopenharmony_ci 558e1051a39Sopenharmony_ci /* 559e1051a39Sopenharmony_ci * Since we may be changing parameters work on the encryption context 560e1051a39Sopenharmony_ci * rather than calling BIO_set_cipher(). 561e1051a39Sopenharmony_ci */ 562e1051a39Sopenharmony_ci 563e1051a39Sopenharmony_ci BIO_get_cipher_ctx(benc, &ctx); 564e1051a39Sopenharmony_ci 565e1051a39Sopenharmony_ci if (!EVP_CipherInit_ex(ctx, cipher, e, NULL, NULL, enc)) { 566e1051a39Sopenharmony_ci BIO_printf(bio_err, "Error setting cipher %s\n", 567e1051a39Sopenharmony_ci EVP_CIPHER_get0_name(cipher)); 568e1051a39Sopenharmony_ci ERR_print_errors(bio_err); 569e1051a39Sopenharmony_ci goto end; 570e1051a39Sopenharmony_ci } 571e1051a39Sopenharmony_ci 572e1051a39Sopenharmony_ci if (nopad) 573e1051a39Sopenharmony_ci EVP_CIPHER_CTX_set_padding(ctx, 0); 574e1051a39Sopenharmony_ci 575e1051a39Sopenharmony_ci if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, enc)) { 576e1051a39Sopenharmony_ci BIO_printf(bio_err, "Error setting cipher %s\n", 577e1051a39Sopenharmony_ci EVP_CIPHER_get0_name(cipher)); 578e1051a39Sopenharmony_ci ERR_print_errors(bio_err); 579e1051a39Sopenharmony_ci goto end; 580e1051a39Sopenharmony_ci } 581e1051a39Sopenharmony_ci 582e1051a39Sopenharmony_ci if (debug) { 583e1051a39Sopenharmony_ci BIO_set_callback_ex(benc, BIO_debug_callback_ex); 584e1051a39Sopenharmony_ci BIO_set_callback_arg(benc, (char *)bio_err); 585e1051a39Sopenharmony_ci } 586e1051a39Sopenharmony_ci 587e1051a39Sopenharmony_ci if (printkey) { 588e1051a39Sopenharmony_ci if (!nosalt) { 589e1051a39Sopenharmony_ci printf("salt="); 590e1051a39Sopenharmony_ci for (i = 0; i < (int)sizeof(salt); i++) 591e1051a39Sopenharmony_ci printf("%02X", salt[i]); 592e1051a39Sopenharmony_ci printf("\n"); 593e1051a39Sopenharmony_ci } 594e1051a39Sopenharmony_ci if (EVP_CIPHER_get_key_length(cipher) > 0) { 595e1051a39Sopenharmony_ci printf("key="); 596e1051a39Sopenharmony_ci for (i = 0; i < EVP_CIPHER_get_key_length(cipher); i++) 597e1051a39Sopenharmony_ci printf("%02X", key[i]); 598e1051a39Sopenharmony_ci printf("\n"); 599e1051a39Sopenharmony_ci } 600e1051a39Sopenharmony_ci if (EVP_CIPHER_get_iv_length(cipher) > 0) { 601e1051a39Sopenharmony_ci printf("iv ="); 602e1051a39Sopenharmony_ci for (i = 0; i < EVP_CIPHER_get_iv_length(cipher); i++) 603e1051a39Sopenharmony_ci printf("%02X", iv[i]); 604e1051a39Sopenharmony_ci printf("\n"); 605e1051a39Sopenharmony_ci } 606e1051a39Sopenharmony_ci if (printkey == 2) { 607e1051a39Sopenharmony_ci ret = 0; 608e1051a39Sopenharmony_ci goto end; 609e1051a39Sopenharmony_ci } 610e1051a39Sopenharmony_ci } 611e1051a39Sopenharmony_ci } 612e1051a39Sopenharmony_ci 613e1051a39Sopenharmony_ci /* Only encrypt/decrypt as we write the file */ 614e1051a39Sopenharmony_ci if (benc != NULL) 615e1051a39Sopenharmony_ci wbio = BIO_push(benc, wbio); 616e1051a39Sopenharmony_ci 617e1051a39Sopenharmony_ci while (BIO_pending(rbio) || !BIO_eof(rbio)) { 618e1051a39Sopenharmony_ci inl = BIO_read(rbio, (char *)buff, bsize); 619e1051a39Sopenharmony_ci if (inl <= 0) 620e1051a39Sopenharmony_ci break; 621e1051a39Sopenharmony_ci if (BIO_write(wbio, (char *)buff, inl) != inl) { 622e1051a39Sopenharmony_ci BIO_printf(bio_err, "error writing output file\n"); 623e1051a39Sopenharmony_ci goto end; 624e1051a39Sopenharmony_ci } 625e1051a39Sopenharmony_ci } 626e1051a39Sopenharmony_ci if (!BIO_flush(wbio)) { 627e1051a39Sopenharmony_ci BIO_printf(bio_err, "bad decrypt\n"); 628e1051a39Sopenharmony_ci goto end; 629e1051a39Sopenharmony_ci } 630e1051a39Sopenharmony_ci 631e1051a39Sopenharmony_ci ret = 0; 632e1051a39Sopenharmony_ci if (verbose) { 633e1051a39Sopenharmony_ci BIO_printf(bio_err, "bytes read : %8ju\n", BIO_number_read(in)); 634e1051a39Sopenharmony_ci BIO_printf(bio_err, "bytes written: %8ju\n", BIO_number_written(out)); 635e1051a39Sopenharmony_ci } 636e1051a39Sopenharmony_ci end: 637e1051a39Sopenharmony_ci ERR_print_errors(bio_err); 638e1051a39Sopenharmony_ci OPENSSL_free(strbuf); 639e1051a39Sopenharmony_ci OPENSSL_free(buff); 640e1051a39Sopenharmony_ci BIO_free(in); 641e1051a39Sopenharmony_ci BIO_free_all(out); 642e1051a39Sopenharmony_ci BIO_free(benc); 643e1051a39Sopenharmony_ci BIO_free(b64); 644e1051a39Sopenharmony_ci EVP_MD_free(dgst); 645e1051a39Sopenharmony_ci EVP_CIPHER_free(cipher); 646e1051a39Sopenharmony_ci#ifdef ZLIB 647e1051a39Sopenharmony_ci BIO_free(bzl); 648e1051a39Sopenharmony_ci#endif 649e1051a39Sopenharmony_ci release_engine(e); 650e1051a39Sopenharmony_ci OPENSSL_free(pass); 651e1051a39Sopenharmony_ci return ret; 652e1051a39Sopenharmony_ci} 653e1051a39Sopenharmony_ci 654e1051a39Sopenharmony_cistatic void show_ciphers(const OBJ_NAME *name, void *arg) 655e1051a39Sopenharmony_ci{ 656e1051a39Sopenharmony_ci struct doall_enc_ciphers *dec = (struct doall_enc_ciphers *)arg; 657e1051a39Sopenharmony_ci const EVP_CIPHER *cipher; 658e1051a39Sopenharmony_ci 659e1051a39Sopenharmony_ci if (!islower((unsigned char)*name->name)) 660e1051a39Sopenharmony_ci return; 661e1051a39Sopenharmony_ci 662e1051a39Sopenharmony_ci /* Filter out ciphers that we cannot use */ 663e1051a39Sopenharmony_ci cipher = EVP_get_cipherbyname(name->name); 664e1051a39Sopenharmony_ci if (cipher == NULL 665e1051a39Sopenharmony_ci || (EVP_CIPHER_get_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) != 0 666e1051a39Sopenharmony_ci || EVP_CIPHER_get_mode(cipher) == EVP_CIPH_XTS_MODE) 667e1051a39Sopenharmony_ci return; 668e1051a39Sopenharmony_ci 669e1051a39Sopenharmony_ci BIO_printf(dec->bio, "-%-25s", name->name); 670e1051a39Sopenharmony_ci if (++dec->n == 3) { 671e1051a39Sopenharmony_ci BIO_printf(dec->bio, "\n"); 672e1051a39Sopenharmony_ci dec->n = 0; 673e1051a39Sopenharmony_ci } else 674e1051a39Sopenharmony_ci BIO_printf(dec->bio, " "); 675e1051a39Sopenharmony_ci} 676e1051a39Sopenharmony_ci 677e1051a39Sopenharmony_cistatic int set_hex(const char *in, unsigned char *out, int size) 678e1051a39Sopenharmony_ci{ 679e1051a39Sopenharmony_ci int i, n; 680e1051a39Sopenharmony_ci unsigned char j; 681e1051a39Sopenharmony_ci 682e1051a39Sopenharmony_ci i = size * 2; 683e1051a39Sopenharmony_ci n = strlen(in); 684e1051a39Sopenharmony_ci if (n > i) { 685e1051a39Sopenharmony_ci BIO_printf(bio_err, "hex string is too long, ignoring excess\n"); 686e1051a39Sopenharmony_ci n = i; /* ignore exceeding part */ 687e1051a39Sopenharmony_ci } else if (n < i) { 688e1051a39Sopenharmony_ci BIO_printf(bio_err, "hex string is too short, padding with zero bytes to length\n"); 689e1051a39Sopenharmony_ci } 690e1051a39Sopenharmony_ci 691e1051a39Sopenharmony_ci memset(out, 0, size); 692e1051a39Sopenharmony_ci for (i = 0; i < n; i++) { 693e1051a39Sopenharmony_ci j = (unsigned char)*in++; 694e1051a39Sopenharmony_ci if (!isxdigit(j)) { 695e1051a39Sopenharmony_ci BIO_printf(bio_err, "non-hex digit\n"); 696e1051a39Sopenharmony_ci return 0; 697e1051a39Sopenharmony_ci } 698e1051a39Sopenharmony_ci j = (unsigned char)OPENSSL_hexchar2int(j); 699e1051a39Sopenharmony_ci if (i & 1) 700e1051a39Sopenharmony_ci out[i / 2] |= j; 701e1051a39Sopenharmony_ci else 702e1051a39Sopenharmony_ci out[i / 2] = (j << 4); 703e1051a39Sopenharmony_ci } 704e1051a39Sopenharmony_ci return 1; 705e1051a39Sopenharmony_ci} 706