xref: /openbsd-src/usr.bin/openssl/enc.c (revision f7c26a86b760bf723f1a72ea3d988d76ca55729d)
1*f7c26a86Stb /* $OpenBSD: enc.c,v 1.31 2023/07/29 17:15:45 tb Exp $ */
2dab3f910Sjsing /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3dab3f910Sjsing  * All rights reserved.
4dab3f910Sjsing  *
5dab3f910Sjsing  * This package is an SSL implementation written
6dab3f910Sjsing  * by Eric Young (eay@cryptsoft.com).
7dab3f910Sjsing  * The implementation was written so as to conform with Netscapes SSL.
8dab3f910Sjsing  *
9dab3f910Sjsing  * This library is free for commercial and non-commercial use as long as
10dab3f910Sjsing  * the following conditions are aheared to.  The following conditions
11dab3f910Sjsing  * apply to all code found in this distribution, be it the RC4, RSA,
12dab3f910Sjsing  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13dab3f910Sjsing  * included with this distribution is covered by the same copyright terms
14dab3f910Sjsing  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15dab3f910Sjsing  *
16dab3f910Sjsing  * Copyright remains Eric Young's, and as such any Copyright notices in
17dab3f910Sjsing  * the code are not to be removed.
18dab3f910Sjsing  * If this package is used in a product, Eric Young should be given attribution
19dab3f910Sjsing  * as the author of the parts of the library used.
20dab3f910Sjsing  * This can be in the form of a textual message at program startup or
21dab3f910Sjsing  * in documentation (online or textual) provided with the package.
22dab3f910Sjsing  *
23dab3f910Sjsing  * Redistribution and use in source and binary forms, with or without
24dab3f910Sjsing  * modification, are permitted provided that the following conditions
25dab3f910Sjsing  * are met:
26dab3f910Sjsing  * 1. Redistributions of source code must retain the copyright
27dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer.
28dab3f910Sjsing  * 2. Redistributions in binary form must reproduce the above copyright
29dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer in the
30dab3f910Sjsing  *    documentation and/or other materials provided with the distribution.
31dab3f910Sjsing  * 3. All advertising materials mentioning features or use of this software
32dab3f910Sjsing  *    must display the following acknowledgement:
33dab3f910Sjsing  *    "This product includes cryptographic software written by
34dab3f910Sjsing  *     Eric Young (eay@cryptsoft.com)"
35dab3f910Sjsing  *    The word 'cryptographic' can be left out if the rouines from the library
36dab3f910Sjsing  *    being used are not cryptographic related :-).
37dab3f910Sjsing  * 4. If you include any Windows specific code (or a derivative thereof) from
38dab3f910Sjsing  *    the apps directory (application code) you must include an acknowledgement:
39dab3f910Sjsing  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40dab3f910Sjsing  *
41dab3f910Sjsing  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42dab3f910Sjsing  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43dab3f910Sjsing  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44dab3f910Sjsing  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45dab3f910Sjsing  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46dab3f910Sjsing  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47dab3f910Sjsing  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48dab3f910Sjsing  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49dab3f910Sjsing  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50dab3f910Sjsing  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51dab3f910Sjsing  * SUCH DAMAGE.
52dab3f910Sjsing  *
53dab3f910Sjsing  * The licence and distribution terms for any publically available version or
54dab3f910Sjsing  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55dab3f910Sjsing  * copied and put under another distribution licence
56dab3f910Sjsing  * [including the GNU Public Licence.]
57dab3f910Sjsing  */
58dab3f910Sjsing 
59dab3f910Sjsing #include <stdio.h>
60dab3f910Sjsing #include <stdlib.h>
61dab3f910Sjsing #include <string.h>
62*f7c26a86Stb #include <unistd.h>
63dab3f910Sjsing 
64dab3f910Sjsing #include "apps.h"
65dab3f910Sjsing 
66dab3f910Sjsing #include <openssl/bio.h>
67dab3f910Sjsing #include <openssl/err.h>
68dab3f910Sjsing #include <openssl/evp.h>
69dab3f910Sjsing #include <openssl/objects.h>
70dab3f910Sjsing 
71dab3f910Sjsing int set_hex(char *in, unsigned char *out, int size);
72dab3f910Sjsing 
73dab3f910Sjsing #define SIZE	(512)
74dab3f910Sjsing #define BSIZE	(8*1024)
757ed34fb2Sjsing 
767ed34fb2Sjsing static struct {
777ed34fb2Sjsing 	int base64;
787ed34fb2Sjsing 	char *bufsize;
797ed34fb2Sjsing 	const EVP_CIPHER *cipher;
807ed34fb2Sjsing 	int debug;
817ed34fb2Sjsing 	int enc;
827ed34fb2Sjsing 	char *hiv;
837ed34fb2Sjsing 	char *hkey;
847ed34fb2Sjsing 	char *hsalt;
857ed34fb2Sjsing 	char *inf;
86e8e42339Sjsing 	int iter;
877ed34fb2Sjsing 	char *keyfile;
887ed34fb2Sjsing 	char *keystr;
897ed34fb2Sjsing 	char *md;
907ed34fb2Sjsing 	int nopad;
917ed34fb2Sjsing 	int nosalt;
927ed34fb2Sjsing 	int olb64;
937ed34fb2Sjsing 	char *outf;
947ed34fb2Sjsing 	char *passarg;
95e8e42339Sjsing 	int pbkdf2;
967ed34fb2Sjsing 	int printkey;
977ed34fb2Sjsing 	int verbose;
98e7718adaStb } cfg;
997ed34fb2Sjsing 
1007ed34fb2Sjsing static int
enc_opt_cipher(int argc,char ** argv,int * argsused)1017ed34fb2Sjsing enc_opt_cipher(int argc, char **argv, int *argsused)
1027ed34fb2Sjsing {
1037ed34fb2Sjsing 	char *name = argv[0];
1047ed34fb2Sjsing 
1057ed34fb2Sjsing 	if (*name++ != '-')
1067ed34fb2Sjsing 		return (1);
1077ed34fb2Sjsing 
1087ed34fb2Sjsing 	if (strcmp(name, "none") == 0) {
109e7718adaStb 		cfg.cipher = NULL;
1107ed34fb2Sjsing 		*argsused = 1;
1117ed34fb2Sjsing 		return (0);
1127ed34fb2Sjsing 	}
1137ed34fb2Sjsing 
114e7718adaStb 	if ((cfg.cipher = EVP_get_cipherbyname(name)) != NULL) {
1157ed34fb2Sjsing 		*argsused = 1;
1167ed34fb2Sjsing 		return (0);
1177ed34fb2Sjsing 	}
1187ed34fb2Sjsing 
1197ed34fb2Sjsing 	return (1);
1207ed34fb2Sjsing }
1217ed34fb2Sjsing 
122ea149709Sguenther static const struct option enc_options[] = {
1237ed34fb2Sjsing 	{
1247ed34fb2Sjsing 		.name = "A",
1257ed34fb2Sjsing 		.desc = "Process base64 data on one line (requires -a)",
1267ed34fb2Sjsing 		.type = OPTION_FLAG,
127e7718adaStb 		.opt.flag = &cfg.olb64,
1287ed34fb2Sjsing 	},
1297ed34fb2Sjsing 	{
1307ed34fb2Sjsing 		.name = "a",
1317ed34fb2Sjsing 		.desc = "Perform base64 encoding/decoding (alias -base64)",
1327ed34fb2Sjsing 		.type = OPTION_FLAG,
133e7718adaStb 		.opt.flag = &cfg.base64,
1347ed34fb2Sjsing 	},
1357ed34fb2Sjsing 	{
1367ed34fb2Sjsing 		.name = "base64",
1377ed34fb2Sjsing 		.type = OPTION_FLAG,
138e7718adaStb 		.opt.flag = &cfg.base64,
1397ed34fb2Sjsing 	},
1407ed34fb2Sjsing 	{
1417ed34fb2Sjsing 		.name = "bufsize",
1427ed34fb2Sjsing 		.argname = "size",
1437ed34fb2Sjsing 		.desc = "Specify the buffer size to use for I/O",
1447ed34fb2Sjsing 		.type = OPTION_ARG,
145e7718adaStb 		.opt.arg = &cfg.bufsize,
1467ed34fb2Sjsing 	},
1477ed34fb2Sjsing 	{
1487ed34fb2Sjsing 		.name = "d",
1497ed34fb2Sjsing 		.desc = "Decrypt the input data",
1507ed34fb2Sjsing 		.type = OPTION_VALUE,
151e7718adaStb 		.opt.value = &cfg.enc,
1527ed34fb2Sjsing 		.value = 0,
1537ed34fb2Sjsing 	},
1547ed34fb2Sjsing 	{
1557ed34fb2Sjsing 		.name = "debug",
1567ed34fb2Sjsing 		.desc = "Print debugging information",
1577ed34fb2Sjsing 		.type = OPTION_FLAG,
158e7718adaStb 		.opt.flag = &cfg.debug,
1597ed34fb2Sjsing 	},
1607ed34fb2Sjsing 	{
1617ed34fb2Sjsing 		.name = "e",
1627ed34fb2Sjsing 		.desc = "Encrypt the input data (default)",
1637ed34fb2Sjsing 		.type = OPTION_VALUE,
164e7718adaStb 		.opt.value = &cfg.enc,
1657ed34fb2Sjsing 		.value = 1,
1667ed34fb2Sjsing 	},
1677ed34fb2Sjsing 	{
1687ed34fb2Sjsing 		.name = "in",
1697ed34fb2Sjsing 		.argname = "file",
1707ed34fb2Sjsing 		.desc = "Input file to read from (default stdin)",
1717ed34fb2Sjsing 		.type = OPTION_ARG,
172e7718adaStb 		.opt.arg = &cfg.inf,
1737ed34fb2Sjsing 	},
1747ed34fb2Sjsing 	{
1753f94473bSnaddy 		.name = "iter",
1763f94473bSnaddy 		.argname = "iterations",
1773f94473bSnaddy 		.desc = "Specify iteration count and force use of PBKDF2",
178ce0472c5Sjsing 		.type = OPTION_ARG_INT,
179e7718adaStb 		.opt.value = &cfg.iter,
1803f94473bSnaddy 	},
1813f94473bSnaddy 	{
1827ed34fb2Sjsing 		.name = "iv",
1837ed34fb2Sjsing 		.argname = "IV",
184cd3126d6Sjmc 		.desc = "IV to use, specified as a hexadecimal string",
1857ed34fb2Sjsing 		.type = OPTION_ARG,
186e7718adaStb 		.opt.arg = &cfg.hiv,
1877ed34fb2Sjsing 	},
1887ed34fb2Sjsing 	{
1897ed34fb2Sjsing 		.name = "K",
1907ed34fb2Sjsing 		.argname = "key",
191cd3126d6Sjmc 		.desc = "Key to use, specified as a hexadecimal string",
1927ed34fb2Sjsing 		.type = OPTION_ARG,
193e7718adaStb 		.opt.arg = &cfg.hkey,
1947ed34fb2Sjsing 	},
1957ed34fb2Sjsing 	{
1967ed34fb2Sjsing 		.name = "k",		/* Superseded by -pass. */
1977ed34fb2Sjsing 		.type = OPTION_ARG,
198e7718adaStb 		.opt.arg = &cfg.keystr,
1997ed34fb2Sjsing 	},
2007ed34fb2Sjsing 	{
2017ed34fb2Sjsing 		.name = "kfile",	/* Superseded by -pass. */
2027ed34fb2Sjsing 		.type = OPTION_ARG,
203e7718adaStb 		.opt.arg = &cfg.keyfile,
2047ed34fb2Sjsing 	},
2057ed34fb2Sjsing 	{
2067ed34fb2Sjsing 		.name = "md",
2077ed34fb2Sjsing 		.argname = "digest",
2087ed34fb2Sjsing 		.desc = "Digest to use to create a key from the passphrase",
2097ed34fb2Sjsing 		.type = OPTION_ARG,
210e7718adaStb 		.opt.arg = &cfg.md,
2117ed34fb2Sjsing 	},
2127ed34fb2Sjsing 	{
2137ed34fb2Sjsing 		.name = "none",
2147ed34fb2Sjsing 		.desc = "Use NULL cipher (no encryption or decryption)",
2157ed34fb2Sjsing 		.type = OPTION_ARGV_FUNC,
2167ed34fb2Sjsing 		.opt.argvfunc = enc_opt_cipher,
2177ed34fb2Sjsing 	},
2187ed34fb2Sjsing 	{
2197ed34fb2Sjsing 		.name = "nopad",
2207ed34fb2Sjsing 		.desc = "Disable standard block padding",
2217ed34fb2Sjsing 		.type = OPTION_FLAG,
222e7718adaStb 		.opt.flag = &cfg.nopad,
2237ed34fb2Sjsing 	},
2247ed34fb2Sjsing 	{
2257ed34fb2Sjsing 		.name = "nosalt",
2267ed34fb2Sjsing 		.type = OPTION_VALUE,
227e7718adaStb 		.opt.value = &cfg.nosalt,
2287ed34fb2Sjsing 		.value = 1,
2297ed34fb2Sjsing 	},
2307ed34fb2Sjsing 	{
2317ed34fb2Sjsing 		.name = "out",
2327ed34fb2Sjsing 		.argname = "file",
2337ed34fb2Sjsing 		.desc = "Output file to write to (default stdout)",
2347ed34fb2Sjsing 		.type = OPTION_ARG,
235e7718adaStb 		.opt.arg = &cfg.outf,
2367ed34fb2Sjsing 	},
2377ed34fb2Sjsing 	{
2387ed34fb2Sjsing 		.name = "P",
2397ed34fb2Sjsing 		.desc = "Print out the salt, key and IV used, then exit\n"
2407ed34fb2Sjsing 		    "  (no encryption or decryption is performed)",
2417ed34fb2Sjsing 		.type = OPTION_VALUE,
242e7718adaStb 		.opt.value = &cfg.printkey,
2437ed34fb2Sjsing 		.value = 2,
2447ed34fb2Sjsing 	},
2457ed34fb2Sjsing 	{
2467ed34fb2Sjsing 		.name = "p",
2477ed34fb2Sjsing 		.desc = "Print out the salt, key and IV used",
2487ed34fb2Sjsing 		.type = OPTION_VALUE,
249e7718adaStb 		.opt.value = &cfg.printkey,
2507ed34fb2Sjsing 		.value = 1,
2517ed34fb2Sjsing 	},
2527ed34fb2Sjsing 	{
2537ed34fb2Sjsing 		.name = "pass",
2547ed34fb2Sjsing 		.argname = "source",
2557ed34fb2Sjsing 		.desc = "Password source",
2567ed34fb2Sjsing 		.type = OPTION_ARG,
257e7718adaStb 		.opt.arg = &cfg.passarg,
2587ed34fb2Sjsing 	},
2597ed34fb2Sjsing 	{
2603f94473bSnaddy 		.name = "pbkdf2",
2613f94473bSnaddy 		.desc = "Use the pbkdf2 key derivation function",
2623f94473bSnaddy 		.type = OPTION_FLAG,
263e7718adaStb 		.opt.flag = &cfg.pbkdf2,
2643f94473bSnaddy 	},
2653f94473bSnaddy 	{
2667ed34fb2Sjsing 		.name = "S",
2677ed34fb2Sjsing 		.argname = "salt",
268cd3126d6Sjmc 		.desc = "Salt to use, specified as a hexadecimal string",
2697ed34fb2Sjsing 		.type = OPTION_ARG,
270e7718adaStb 		.opt.arg = &cfg.hsalt,
2717ed34fb2Sjsing 	},
2727ed34fb2Sjsing 	{
2737ed34fb2Sjsing 		.name = "salt",
2747ed34fb2Sjsing 		.desc = "Use a salt in the key derivation routines (default)",
2757ed34fb2Sjsing 		.type = OPTION_VALUE,
276e7718adaStb 		.opt.value = &cfg.nosalt,
2777ed34fb2Sjsing 		.value = 0,
2787ed34fb2Sjsing 	},
2797ed34fb2Sjsing 	{
2807ed34fb2Sjsing 		.name = "v",
2817ed34fb2Sjsing 		.desc = "Verbose",
2827ed34fb2Sjsing 		.type = OPTION_FLAG,
283e7718adaStb 		.opt.flag = &cfg.verbose,
2847ed34fb2Sjsing 	},
2857ed34fb2Sjsing 	{
2867ed34fb2Sjsing 		.name = NULL,
2877ed34fb2Sjsing 		.type = OPTION_ARGV_FUNC,
2887ed34fb2Sjsing 		.opt.argvfunc = enc_opt_cipher,
2897ed34fb2Sjsing 	},
2907ed34fb2Sjsing 	{ NULL },
2917ed34fb2Sjsing };
292dab3f910Sjsing 
293dab3f910Sjsing static void
skip_aead_and_xts(const OBJ_NAME * name,void * arg)2946bdbc113Stb skip_aead_and_xts(const OBJ_NAME *name, void *arg)
2956bdbc113Stb {
2966bdbc113Stb 	const EVP_CIPHER *cipher;
2976bdbc113Stb 
2986bdbc113Stb 	if ((cipher = EVP_get_cipherbyname(name->name)) == NULL)
2996bdbc113Stb 		return;
3006bdbc113Stb 
3016bdbc113Stb 	if ((EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) != 0)
3026bdbc113Stb 		return;
3036bdbc113Stb 	if (EVP_CIPHER_mode(cipher) == EVP_CIPH_XTS_MODE)
3046bdbc113Stb 		return;
3056bdbc113Stb 
3066bdbc113Stb 	show_cipher(name, arg);
3076bdbc113Stb }
3086bdbc113Stb 
3096bdbc113Stb static void
enc_usage(void)3107ed34fb2Sjsing enc_usage(void)
3117ed34fb2Sjsing {
3126685372aSinoguchi 	int n = 0;
3136685372aSinoguchi 
3147ed34fb2Sjsing 	fprintf(stderr, "usage: enc -ciphername [-AadePp] [-base64] "
3157ed34fb2Sjsing 	    "[-bufsize number] [-debug]\n"
3163f94473bSnaddy 	    "    [-in file] [-iter iterations] [-iv IV] [-K key] "
3173f94473bSnaddy             "[-k password]\n"
3187ed34fb2Sjsing 	    "    [-kfile file] [-md digest] [-none] [-nopad] [-nosalt]\n"
3193f94473bSnaddy 	    "    [-out file] [-pass source] [-pbkdf2] [-S salt] [-salt]\n\n");
3207ed34fb2Sjsing 	options_usage(enc_options);
3217ed34fb2Sjsing 	fprintf(stderr, "\n");
3227ed34fb2Sjsing 
3237ed34fb2Sjsing 	fprintf(stderr, "Valid ciphername values:\n\n");
3246bdbc113Stb 	OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, skip_aead_and_xts, &n);
3257ed34fb2Sjsing 	fprintf(stderr, "\n");
326dab3f910Sjsing }
327dab3f910Sjsing 
328dab3f910Sjsing int
enc_main(int argc,char ** argv)329dab3f910Sjsing enc_main(int argc, char **argv)
330dab3f910Sjsing {
331dab3f910Sjsing 	static const char magic[] = "Salted__";
332dab3f910Sjsing 	char mbuf[sizeof magic - 1];
3337ed34fb2Sjsing 	char *strbuf = NULL, *pass = NULL;
3347ed34fb2Sjsing 	unsigned char *buff = NULL;
3357ed34fb2Sjsing 	int bsize = BSIZE;
336dab3f910Sjsing 	int ret = 1, inl;
337dab3f910Sjsing 	unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
338dab3f910Sjsing 	unsigned char salt[PKCS5_SALT_LEN];
339dab3f910Sjsing 	EVP_CIPHER_CTX *ctx = NULL;
3407ed34fb2Sjsing 	const EVP_MD *dgst = NULL;
3417ed34fb2Sjsing 	BIO *in = NULL, *out = NULL, *b64 = NULL, *benc = NULL;
3427ed34fb2Sjsing 	BIO *rbio = NULL, *wbio = NULL;
343dab3f910Sjsing #define PROG_NAME_SIZE  39
344dab3f910Sjsing 	char pname[PROG_NAME_SIZE + 1];
3457ed34fb2Sjsing 	int i;
3467ed34fb2Sjsing 
34751811eadSderaadt 	if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
3489bc487adSdoug 		perror("pledge");
349e370f0eeSdoug 		exit(1);
350e370f0eeSdoug 	}
3519bc487adSdoug 
352e7718adaStb 	memset(&cfg, 0, sizeof(cfg));
353e7718adaStb 	cfg.enc = 1;
354dab3f910Sjsing 
355dab3f910Sjsing 	/* first check the program name */
3567ed34fb2Sjsing 	program_name(argv[0], pname, sizeof(pname));
3577ed34fb2Sjsing 
358dab3f910Sjsing 	if (strcmp(pname, "base64") == 0)
359e7718adaStb 		cfg.base64 = 1;
3607ed34fb2Sjsing 
361e7718adaStb 	cfg.cipher = EVP_get_cipherbyname(pname);
3627ed34fb2Sjsing 
36335f962d3Stb 	if (!cfg.base64 && cfg.cipher == NULL && strcmp(pname, "enc") != 0) {
364dab3f910Sjsing 		BIO_printf(bio_err, "%s is an unknown cipher\n", pname);
3657ed34fb2Sjsing 		goto end;
366dab3f910Sjsing 	}
3677ed34fb2Sjsing 
3687ed34fb2Sjsing 	if (options_parse(argc, argv, enc_options, NULL, NULL) != 0) {
3697ed34fb2Sjsing 		enc_usage();
3707ed34fb2Sjsing 		goto end;
371dab3f910Sjsing 	}
3727ed34fb2Sjsing 
373e7718adaStb 	if (cfg.keyfile != NULL) {
374dab3f910Sjsing 		static char buf[128];
375dab3f910Sjsing 		FILE *infile;
376dab3f910Sjsing 
377e7718adaStb 		infile = fopen(cfg.keyfile, "r");
378dab3f910Sjsing 		if (infile == NULL) {
379dab3f910Sjsing 			BIO_printf(bio_err, "unable to read key from '%s'\n",
380e7718adaStb 			    cfg.keyfile);
3817ed34fb2Sjsing 			goto end;
382dab3f910Sjsing 		}
383dab3f910Sjsing 		buf[0] = '\0';
384dab3f910Sjsing 		if (!fgets(buf, sizeof buf, infile)) {
385dab3f910Sjsing 			BIO_printf(bio_err, "unable to read key from '%s'\n",
386e7718adaStb 			    cfg.keyfile);
387dab3f910Sjsing 			fclose(infile);
3887ed34fb2Sjsing 			goto end;
389dab3f910Sjsing 		}
390dab3f910Sjsing 		fclose(infile);
391dab3f910Sjsing 		i = strlen(buf);
392a785ae5dStb 		if (i > 0 && (buf[i - 1] == '\n' || buf[i - 1] == '\r'))
393dab3f910Sjsing 			buf[--i] = '\0';
394a785ae5dStb 		if (i > 0 && (buf[i - 1] == '\n' || buf[i - 1] == '\r'))
395dab3f910Sjsing 			buf[--i] = '\0';
396dab3f910Sjsing 		if (i < 1) {
397dab3f910Sjsing 			BIO_printf(bio_err, "zero length password\n");
398dab3f910Sjsing 			goto end;
399dab3f910Sjsing 		}
400e7718adaStb 		cfg.keystr = buf;
401dab3f910Sjsing 	}
402dab3f910Sjsing 
403e7718adaStb 	if (cfg.cipher != NULL &&
404e7718adaStb 	    (EVP_CIPHER_flags(cfg.cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) != 0) {
4056bdbc113Stb 		BIO_printf(bio_err, "enc does not support AEAD ciphers\n");
4066bdbc113Stb 		goto end;
4076bdbc113Stb 	}
4086bdbc113Stb 
409e7718adaStb 	if (cfg.cipher != NULL &&
410e7718adaStb 	    EVP_CIPHER_mode(cfg.cipher) == EVP_CIPH_XTS_MODE) {
4116bdbc113Stb 		BIO_printf(bio_err, "enc does not support XTS mode\n");
4126bdbc113Stb 		goto end;
4136bdbc113Stb 	}
4146bdbc113Stb 
415e7718adaStb 	if (cfg.md != NULL &&
416e7718adaStb 	    (dgst = EVP_get_digestbyname(cfg.md)) == NULL) {
4177ed34fb2Sjsing 		BIO_printf(bio_err,
4187ed34fb2Sjsing 		    "%s is an unsupported message digest type\n",
419e7718adaStb 		    cfg.md);
420dab3f910Sjsing 		goto end;
421dab3f910Sjsing 	}
422a785ae5dStb 	if (dgst == NULL)
423d45026d1Sbeck 		dgst = EVP_sha256();
4247ed34fb2Sjsing 
425e7718adaStb 	if (cfg.bufsize != NULL) {
426e7718adaStb 		char *p = cfg.bufsize;
427dab3f910Sjsing 		unsigned long n;
428dab3f910Sjsing 
4297ed34fb2Sjsing 		/* XXX - provide an OPTION_ARG_DISKUNIT. */
4307ed34fb2Sjsing 		for (n = 0; *p != '\0'; p++) {
4317ed34fb2Sjsing 			i = *p;
432dab3f910Sjsing 			if ((i <= '9') && (i >= '0'))
433dab3f910Sjsing 				n = n * 10 + i - '0';
434dab3f910Sjsing 			else if (i == 'k') {
435dab3f910Sjsing 				n *= 1024;
4367ed34fb2Sjsing 				p++;
437dab3f910Sjsing 				break;
438dab3f910Sjsing 			}
439dab3f910Sjsing 		}
4407ed34fb2Sjsing 		if (*p != '\0') {
441dab3f910Sjsing 			BIO_printf(bio_err, "invalid 'bufsize' specified.\n");
442dab3f910Sjsing 			goto end;
443dab3f910Sjsing 		}
4447ed34fb2Sjsing 		/* It must be large enough for a base64 encoded line. */
445e7718adaStb 		if (cfg.base64 && n < 80)
446dab3f910Sjsing 			n = 80;
447dab3f910Sjsing 
448dab3f910Sjsing 		bsize = (int)n;
449e7718adaStb 		if (cfg.verbose)
450dab3f910Sjsing 			BIO_printf(bio_err, "bufsize=%d\n", bsize);
451dab3f910Sjsing 	}
452dab3f910Sjsing 	strbuf = malloc(SIZE);
453dab3f910Sjsing 	buff = malloc(EVP_ENCODE_LENGTH(bsize));
454a785ae5dStb 	if (buff == NULL || strbuf == NULL) {
455dab3f910Sjsing 		BIO_printf(bio_err, "malloc failure %ld\n", (long) EVP_ENCODE_LENGTH(bsize));
456dab3f910Sjsing 		goto end;
457dab3f910Sjsing 	}
458dab3f910Sjsing 	in = BIO_new(BIO_s_file());
459dab3f910Sjsing 	out = BIO_new(BIO_s_file());
460a785ae5dStb 	if (in == NULL || out == NULL) {
461dab3f910Sjsing 		ERR_print_errors(bio_err);
462dab3f910Sjsing 		goto end;
463dab3f910Sjsing 	}
464e7718adaStb 	if (cfg.debug) {
465dab3f910Sjsing 		BIO_set_callback(in, BIO_debug_callback);
466dab3f910Sjsing 		BIO_set_callback(out, BIO_debug_callback);
467dab3f910Sjsing 		BIO_set_callback_arg(in, (char *) bio_err);
468dab3f910Sjsing 		BIO_set_callback_arg(out, (char *) bio_err);
469dab3f910Sjsing 	}
470e7718adaStb 	if (cfg.inf == NULL) {
471e7718adaStb 		if (cfg.bufsize != NULL)
472dab3f910Sjsing 			setvbuf(stdin, (char *) NULL, _IONBF, 0);
473dab3f910Sjsing 		BIO_set_fp(in, stdin, BIO_NOCLOSE);
474dab3f910Sjsing 	} else {
475e7718adaStb 		if (BIO_read_filename(in, cfg.inf) <= 0) {
476e7718adaStb 			perror(cfg.inf);
477dab3f910Sjsing 			goto end;
478dab3f910Sjsing 		}
479dab3f910Sjsing 	}
480dab3f910Sjsing 
481e7718adaStb 	if (!cfg.keystr && cfg.passarg) {
482a785ae5dStb 		if (!app_passwd(bio_err, cfg.passarg, NULL, &pass, NULL)) {
483dab3f910Sjsing 			BIO_printf(bio_err, "Error getting password\n");
484dab3f910Sjsing 			goto end;
485dab3f910Sjsing 		}
486e7718adaStb 		cfg.keystr = pass;
487dab3f910Sjsing 	}
488a785ae5dStb 	if (cfg.keystr == NULL && cfg.cipher != NULL && cfg.hkey == NULL) {
489dab3f910Sjsing 		for (;;) {
490dab3f910Sjsing 			char buf[200];
491695cbeafSdoug 			int retval;
492dab3f910Sjsing 
4937ed34fb2Sjsing 			retval = snprintf(buf, sizeof buf,
4947ed34fb2Sjsing 			    "enter %s %s password:",
495e7718adaStb 			    OBJ_nid2ln(EVP_CIPHER_nid(cfg.cipher)),
496e7718adaStb 			    cfg.enc ? "encryption" : "decryption");
497695cbeafSdoug 			if ((size_t)retval >= sizeof buf) {
4987ed34fb2Sjsing 				BIO_printf(bio_err,
4997ed34fb2Sjsing 				    "Password prompt too long\n");
500dab3f910Sjsing 				goto end;
501dab3f910Sjsing 			}
502dab3f910Sjsing 			strbuf[0] = '\0';
5037ed34fb2Sjsing 			i = EVP_read_pw_string((char *)strbuf, SIZE, buf,
504e7718adaStb 			    cfg.enc);
505dab3f910Sjsing 			if (i == 0) {
506dab3f910Sjsing 				if (strbuf[0] == '\0') {
507dab3f910Sjsing 					ret = 1;
508dab3f910Sjsing 					goto end;
509dab3f910Sjsing 				}
510e7718adaStb 				cfg.keystr = strbuf;
511dab3f910Sjsing 				break;
512dab3f910Sjsing 			}
513dab3f910Sjsing 			if (i < 0) {
514dab3f910Sjsing 				BIO_printf(bio_err, "bad password read\n");
515dab3f910Sjsing 				goto end;
516dab3f910Sjsing 			}
517dab3f910Sjsing 		}
518dab3f910Sjsing 	}
519e7718adaStb 	if (cfg.outf == NULL) {
520dab3f910Sjsing 		BIO_set_fp(out, stdout, BIO_NOCLOSE);
521e7718adaStb 		if (cfg.bufsize != NULL)
522dab3f910Sjsing 			setvbuf(stdout, (char *)NULL, _IONBF, 0);
523dab3f910Sjsing 	} else {
524e7718adaStb 		if (BIO_write_filename(out, cfg.outf) <= 0) {
525e7718adaStb 			perror(cfg.outf);
526dab3f910Sjsing 			goto end;
527dab3f910Sjsing 		}
528dab3f910Sjsing 	}
529dab3f910Sjsing 
530dab3f910Sjsing 	rbio = in;
531dab3f910Sjsing 	wbio = out;
532dab3f910Sjsing 
533e7718adaStb 	if (cfg.base64) {
534dab3f910Sjsing 		if ((b64 = BIO_new(BIO_f_base64())) == NULL)
535dab3f910Sjsing 			goto end;
536e7718adaStb 		if (cfg.debug) {
537dab3f910Sjsing 			BIO_set_callback(b64, BIO_debug_callback);
538dab3f910Sjsing 			BIO_set_callback_arg(b64, (char *) bio_err);
539dab3f910Sjsing 		}
540e7718adaStb 		if (cfg.olb64)
541dab3f910Sjsing 			BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
542e7718adaStb 		if (cfg.enc)
543dab3f910Sjsing 			wbio = BIO_push(b64, wbio);
544dab3f910Sjsing 		else
545dab3f910Sjsing 			rbio = BIO_push(b64, rbio);
546dab3f910Sjsing 	}
547e7718adaStb 	if (cfg.cipher != NULL) {
548dab3f910Sjsing 		/*
5497ed34fb2Sjsing 		 * Note that keystr is NULL if a key was passed on the command
550dab3f910Sjsing 		 * line, so we get no salt in that case. Is this a bug?
551dab3f910Sjsing 		 */
552e7718adaStb 		if (cfg.keystr != NULL) {
553dab3f910Sjsing 			/*
554dab3f910Sjsing 			 * Salt handling: if encrypting generate a salt and
555dab3f910Sjsing 			 * write to output BIO. If decrypting read salt from
556dab3f910Sjsing 			 * input BIO.
557dab3f910Sjsing 			 */
558dab3f910Sjsing 			unsigned char *sptr;
559e7718adaStb 			if (cfg.nosalt)
560dab3f910Sjsing 				sptr = NULL;
561dab3f910Sjsing 			else {
562e7718adaStb 				if (cfg.enc) {
563e7718adaStb 					if (cfg.hsalt) {
564e7718adaStb 						if (!set_hex(cfg.hsalt, salt, sizeof salt)) {
565dab3f910Sjsing 							BIO_printf(bio_err,
566dab3f910Sjsing 							    "invalid hex salt value\n");
567dab3f910Sjsing 							goto end;
568dab3f910Sjsing 						}
569fd6ab616Sjsing 					} else
570fd6ab616Sjsing 						arc4random_buf(salt,
571fd6ab616Sjsing 						    sizeof(salt));
572dab3f910Sjsing 					/*
573dab3f910Sjsing 					 * If -P option then don't bother
574dab3f910Sjsing 					 * writing
575dab3f910Sjsing 					 */
576e7718adaStb 					if ((cfg.printkey != 2)
577dab3f910Sjsing 					    && (BIO_write(wbio, magic,
578dab3f910Sjsing 						    sizeof magic - 1) != sizeof magic - 1
579dab3f910Sjsing 						|| BIO_write(wbio,
580dab3f910Sjsing 						    (char *) salt,
581dab3f910Sjsing 						    sizeof salt) != sizeof salt)) {
582dab3f910Sjsing 						BIO_printf(bio_err, "error writing output file\n");
583dab3f910Sjsing 						goto end;
584dab3f910Sjsing 					}
585dab3f910Sjsing 				} else if (BIO_read(rbio, mbuf, sizeof mbuf) != sizeof mbuf
586dab3f910Sjsing 					    || BIO_read(rbio,
587dab3f910Sjsing 						(unsigned char *) salt,
588dab3f910Sjsing 					sizeof salt) != sizeof salt) {
589dab3f910Sjsing 					BIO_printf(bio_err, "error reading input file\n");
590dab3f910Sjsing 					goto end;
591dab3f910Sjsing 				} else if (memcmp(mbuf, magic, sizeof magic - 1)) {
592dab3f910Sjsing 					BIO_printf(bio_err, "bad magic number\n");
593dab3f910Sjsing 					goto end;
594dab3f910Sjsing 				}
595dab3f910Sjsing 				sptr = salt;
596dab3f910Sjsing 			}
597e7718adaStb 			if (cfg.pbkdf2 == 1 || cfg.iter > 0) {
598d45026d1Sbeck 				/*
599d45026d1Sbeck 				 * derive key and default iv
600d45026d1Sbeck 				 * concatenated into a temporary buffer
601d45026d1Sbeck 				 */
602d45026d1Sbeck 				unsigned char tmpkeyiv[EVP_MAX_KEY_LENGTH + EVP_MAX_IV_LENGTH];
603e7718adaStb 				int iklen = EVP_CIPHER_key_length(cfg.cipher);
604e7718adaStb 				int ivlen = EVP_CIPHER_iv_length(cfg.cipher);
605d45026d1Sbeck 				/* not needed if HASH_UPDATE() is fixed : */
606d45026d1Sbeck 				int islen = (sptr != NULL ? sizeof(salt) : 0);
607dab3f910Sjsing 
608e7718adaStb 				if (cfg.iter == 0)
609e7718adaStb 					cfg.iter = 10000;
610d45026d1Sbeck 
611e7718adaStb 				if (!PKCS5_PBKDF2_HMAC(cfg.keystr,
612e7718adaStb 					strlen(cfg.keystr), sptr, islen,
613e7718adaStb 					cfg.iter, dgst, iklen+ivlen, tmpkeyiv)) {
614d45026d1Sbeck 					BIO_printf(bio_err, "PKCS5_PBKDF2_HMAC failed\n");
615d45026d1Sbeck 					goto end;
616d45026d1Sbeck 				}
617d45026d1Sbeck 				/* split and move data back to global buffer */
618d45026d1Sbeck 				memcpy(key, tmpkeyiv, iklen);
619d45026d1Sbeck 				memcpy(iv, tmpkeyiv + iklen, ivlen);
620972737a6Sbcook 				explicit_bzero(tmpkeyiv, sizeof tmpkeyiv);
621d45026d1Sbeck 			} else {
622e7718adaStb 				EVP_BytesToKey(cfg.cipher, dgst, sptr,
623e7718adaStb 				    (unsigned char *)cfg.keystr,
624e7718adaStb 				    strlen(cfg.keystr), 1, key, iv);
625d45026d1Sbeck 			}
626d45026d1Sbeck 
627dab3f910Sjsing 			/*
628dab3f910Sjsing 			 * zero the complete buffer or the string passed from
629dab3f910Sjsing 			 * the command line bug picked up by Larry J. Hughes
630dab3f910Sjsing 			 * Jr. <hughes@indiana.edu>
631dab3f910Sjsing 			 */
632e7718adaStb 			if (cfg.keystr == strbuf)
633e7718adaStb 				explicit_bzero(cfg.keystr, SIZE);
634dab3f910Sjsing 			else
635e7718adaStb 				explicit_bzero(cfg.keystr,
636e7718adaStb 				    strlen(cfg.keystr));
637dab3f910Sjsing 		}
638a785ae5dStb 		if (cfg.hiv != NULL && !set_hex(cfg.hiv, iv, sizeof iv)) {
639dab3f910Sjsing 			BIO_printf(bio_err, "invalid hex iv value\n");
640dab3f910Sjsing 			goto end;
641dab3f910Sjsing 		}
642e7718adaStb 		if (cfg.hiv == NULL && cfg.keystr == NULL &&
643e7718adaStb 		    EVP_CIPHER_iv_length(cfg.cipher) != 0) {
644dab3f910Sjsing 			/*
645dab3f910Sjsing 			 * No IV was explicitly set and no IV was generated
646dab3f910Sjsing 			 * during EVP_BytesToKey. Hence the IV is undefined,
647dab3f910Sjsing 			 * making correct decryption impossible.
648dab3f910Sjsing 			 */
649dab3f910Sjsing 			BIO_printf(bio_err, "iv undefined\n");
650dab3f910Sjsing 			goto end;
651dab3f910Sjsing 		}
652a785ae5dStb 		if (cfg.hkey != NULL && !set_hex(cfg.hkey, key, sizeof key)) {
653dab3f910Sjsing 			BIO_printf(bio_err, "invalid hex key value\n");
654dab3f910Sjsing 			goto end;
655dab3f910Sjsing 		}
656dab3f910Sjsing 		if ((benc = BIO_new(BIO_f_cipher())) == NULL)
657dab3f910Sjsing 			goto end;
658dab3f910Sjsing 
659dab3f910Sjsing 		/*
660dab3f910Sjsing 		 * Since we may be changing parameters work on the encryption
661dab3f910Sjsing 		 * context rather than calling BIO_set_cipher().
662dab3f910Sjsing 		 */
663dab3f910Sjsing 
664dab3f910Sjsing 		BIO_get_cipher_ctx(benc, &ctx);
665dab3f910Sjsing 
666e7718adaStb 		if (!EVP_CipherInit_ex(ctx, cfg.cipher, NULL, NULL,
667e7718adaStb 		    NULL, cfg.enc)) {
668dab3f910Sjsing 			BIO_printf(bio_err, "Error setting cipher %s\n",
669e7718adaStb 			    EVP_CIPHER_name(cfg.cipher));
670dab3f910Sjsing 			ERR_print_errors(bio_err);
671dab3f910Sjsing 			goto end;
672dab3f910Sjsing 		}
673e7718adaStb 		if (cfg.nopad)
674dab3f910Sjsing 			EVP_CIPHER_CTX_set_padding(ctx, 0);
675dab3f910Sjsing 
676a785ae5dStb 		if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, cfg.enc)) {
677dab3f910Sjsing 			BIO_printf(bio_err, "Error setting cipher %s\n",
678e7718adaStb 			    EVP_CIPHER_name(cfg.cipher));
679dab3f910Sjsing 			ERR_print_errors(bio_err);
680dab3f910Sjsing 			goto end;
681dab3f910Sjsing 		}
682e7718adaStb 		if (cfg.debug) {
683dab3f910Sjsing 			BIO_set_callback(benc, BIO_debug_callback);
684dab3f910Sjsing 			BIO_set_callback_arg(benc, (char *) bio_err);
685dab3f910Sjsing 		}
686e7718adaStb 		if (cfg.printkey) {
68775580eacStb 			int key_len, iv_len;
68875580eacStb 
689e7718adaStb 			if (!cfg.nosalt) {
690dab3f910Sjsing 				printf("salt=");
691dab3f910Sjsing 				for (i = 0; i < (int) sizeof(salt); i++)
692dab3f910Sjsing 					printf("%02X", salt[i]);
693dab3f910Sjsing 				printf("\n");
694dab3f910Sjsing 			}
695e7718adaStb 			key_len = EVP_CIPHER_key_length(cfg.cipher);
69675580eacStb 			if (key_len > 0) {
697dab3f910Sjsing 				printf("key=");
69875580eacStb 				for (i = 0; i < key_len; i++)
699dab3f910Sjsing 					printf("%02X", key[i]);
700dab3f910Sjsing 				printf("\n");
701dab3f910Sjsing 			}
702e7718adaStb 			iv_len = EVP_CIPHER_iv_length(cfg.cipher);
70375580eacStb 			if (iv_len > 0) {
704dab3f910Sjsing 				printf("iv =");
70575580eacStb 				for (i = 0; i < iv_len; i++)
706dab3f910Sjsing 					printf("%02X", iv[i]);
707dab3f910Sjsing 				printf("\n");
708dab3f910Sjsing 			}
709e7718adaStb 			if (cfg.printkey == 2) {
710dab3f910Sjsing 				ret = 0;
711dab3f910Sjsing 				goto end;
712dab3f910Sjsing 			}
713dab3f910Sjsing 		}
714dab3f910Sjsing 	}
715dab3f910Sjsing 	/* Only encrypt/decrypt as we write the file */
716dab3f910Sjsing 	if (benc != NULL)
717dab3f910Sjsing 		wbio = BIO_push(benc, wbio);
718dab3f910Sjsing 
719dab3f910Sjsing 	for (;;) {
720dab3f910Sjsing 		inl = BIO_read(rbio, (char *) buff, bsize);
721dab3f910Sjsing 		if (inl <= 0)
722dab3f910Sjsing 			break;
723dab3f910Sjsing 		if (BIO_write(wbio, (char *) buff, inl) != inl) {
724dab3f910Sjsing 			BIO_printf(bio_err, "error writing output file\n");
725dab3f910Sjsing 			goto end;
726dab3f910Sjsing 		}
727dab3f910Sjsing 	}
728dab3f910Sjsing 	if (!BIO_flush(wbio)) {
729dab3f910Sjsing 		BIO_printf(bio_err, "bad decrypt\n");
730dab3f910Sjsing 		goto end;
731dab3f910Sjsing 	}
732dab3f910Sjsing 	ret = 0;
733e7718adaStb 	if (cfg.verbose) {
734dab3f910Sjsing 		BIO_printf(bio_err, "bytes read   :%8ld\n", BIO_number_read(in));
735dab3f910Sjsing 		BIO_printf(bio_err, "bytes written:%8ld\n", BIO_number_written(out));
736dab3f910Sjsing 	}
737dab3f910Sjsing  end:
738dab3f910Sjsing 	ERR_print_errors(bio_err);
739dab3f910Sjsing 	free(strbuf);
740dab3f910Sjsing 	free(buff);
741dab3f910Sjsing 	BIO_free(in);
742dab3f910Sjsing 	BIO_free_all(out);
743dab3f910Sjsing 	BIO_free(benc);
744dab3f910Sjsing 	BIO_free(b64);
745dab3f910Sjsing 	free(pass);
746dab3f910Sjsing 
747dab3f910Sjsing 	return (ret);
748dab3f910Sjsing }
749dab3f910Sjsing 
750dab3f910Sjsing int
set_hex(char * in,unsigned char * out,int size)751dab3f910Sjsing set_hex(char *in, unsigned char *out, int size)
752dab3f910Sjsing {
753dab3f910Sjsing 	int i, n;
754dab3f910Sjsing 	unsigned char j;
755dab3f910Sjsing 
756dab3f910Sjsing 	n = strlen(in);
757dab3f910Sjsing 	if (n > (size * 2)) {
758dab3f910Sjsing 		BIO_printf(bio_err, "hex string is too long\n");
759dab3f910Sjsing 		return (0);
760dab3f910Sjsing 	}
761dab3f910Sjsing 	memset(out, 0, size);
762dab3f910Sjsing 	for (i = 0; i < n; i++) {
763dab3f910Sjsing 		j = (unsigned char) *in;
764dab3f910Sjsing 		*(in++) = '\0';
765dab3f910Sjsing 		if (j == 0)
766dab3f910Sjsing 			break;
767a785ae5dStb 		if (j >= '0' && j <= '9')
768dab3f910Sjsing 			j -= '0';
769a785ae5dStb 		else if (j >= 'A' && j <= 'F')
770dab3f910Sjsing 			j = j - 'A' + 10;
771a785ae5dStb 		else if (j >= 'a' && j <= 'f')
772dab3f910Sjsing 			j = j - 'a' + 10;
773dab3f910Sjsing 		else {
774dab3f910Sjsing 			BIO_printf(bio_err, "non-hex digit\n");
775dab3f910Sjsing 			return (0);
776dab3f910Sjsing 		}
777dab3f910Sjsing 		if (i & 1)
778dab3f910Sjsing 			out[i / 2] |= j;
779dab3f910Sjsing 		else
780dab3f910Sjsing 			out[i / 2] = (j << 4);
781dab3f910Sjsing 	}
782dab3f910Sjsing 	return (1);
783dab3f910Sjsing }
784