xref: /openbsd-src/usr.bin/openssl/passwd.c (revision e7718adaf9bdf5a32db0f291795197a85ccbb6ed)
1*e7718adaStb /* $OpenBSD: passwd.c,v 1.14 2023/03/06 14:32:06 tb Exp $ */
2dab3f910Sjsing 
3dab3f910Sjsing #if defined OPENSSL_NO_MD5
4dab3f910Sjsing #define NO_MD5CRYPT_1
5dab3f910Sjsing #endif
6dab3f910Sjsing 
7dab3f910Sjsing #if !defined(OPENSSL_NO_DES) || !defined(NO_MD5CRYPT_1)
8dab3f910Sjsing 
9dab3f910Sjsing #include <assert.h>
10dab3f910Sjsing #include <string.h>
11dab3f910Sjsing 
12dab3f910Sjsing #include "apps.h"
13dab3f910Sjsing 
14dab3f910Sjsing #include <openssl/bio.h>
15dab3f910Sjsing #include <openssl/err.h>
16dab3f910Sjsing #include <openssl/evp.h>
17dab3f910Sjsing 
18dab3f910Sjsing #ifndef OPENSSL_NO_DES
19dab3f910Sjsing #include <openssl/des.h>
20dab3f910Sjsing #endif
21dab3f910Sjsing 
22dab3f910Sjsing #ifndef NO_MD5CRYPT_1
23dab3f910Sjsing #include <openssl/md5.h>
24dab3f910Sjsing #endif
25dab3f910Sjsing 
26dab3f910Sjsing static unsigned const char cov_2char[64] = {
27dab3f910Sjsing 	/* from crypto/des/fcrypt.c */
28dab3f910Sjsing 	0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
29dab3f910Sjsing 	0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44,
30dab3f910Sjsing 	0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C,
31dab3f910Sjsing 	0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54,
32dab3f910Sjsing 	0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62,
33dab3f910Sjsing 	0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A,
34dab3f910Sjsing 	0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72,
35dab3f910Sjsing 	0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A
36dab3f910Sjsing };
37dab3f910Sjsing 
38dab3f910Sjsing static int
39dab3f910Sjsing do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p,
40dab3f910Sjsing     char *passwd, BIO * out, int quiet, int table, int reverse,
41dab3f910Sjsing     size_t pw_maxlen, int usecrypt, int use1, int useapr1);
42dab3f910Sjsing 
43b6995238Sjsing static struct {
44b6995238Sjsing 	char *infile;
45b6995238Sjsing 	int in_stdin;
46b6995238Sjsing 	int noverify;
47b6995238Sjsing 	int quiet;
48b6995238Sjsing 	int reverse;
49b6995238Sjsing 	char *salt;
50b6995238Sjsing 	int table;
51b6995238Sjsing 	int use1;
52b6995238Sjsing 	int useapr1;
53b6995238Sjsing 	int usecrypt;
54*e7718adaStb } cfg;
55b6995238Sjsing 
56ea149709Sguenther static const struct option passwd_options[] = {
57b6995238Sjsing #ifndef NO_MD5CRYPT_1
58b6995238Sjsing 	{
59b6995238Sjsing 		.name = "1",
60b6995238Sjsing 		.desc = "Use MD5 based BSD password algorithm 1",
61b6995238Sjsing 		.type = OPTION_FLAG,
62*e7718adaStb 		.opt.flag = &cfg.use1,
63b6995238Sjsing 	},
64b6995238Sjsing 	{
65b6995238Sjsing 		.name = "apr1",
66b6995238Sjsing 		.desc = "Use apr1 algorithm (Apache variant of BSD algorithm)",
67b6995238Sjsing 		.type = OPTION_FLAG,
68*e7718adaStb 		.opt.flag = &cfg.useapr1,
69b6995238Sjsing 	},
70b6995238Sjsing #endif
71b6995238Sjsing #ifndef OPENSSL_NO_DES
72b6995238Sjsing 	{
73b6995238Sjsing 		.name = "crypt",
74b6995238Sjsing 		.desc = "Use crypt algorithm (default)",
75b6995238Sjsing 		.type = OPTION_FLAG,
76*e7718adaStb 		.opt.flag = &cfg.usecrypt,
77b6995238Sjsing 	},
78b6995238Sjsing #endif
79b6995238Sjsing 	{
80b6995238Sjsing 		.name = "in",
81b6995238Sjsing 		.argname = "file",
82b6995238Sjsing 		.desc = "Read passwords from specified file",
83b6995238Sjsing 		.type = OPTION_ARG,
84*e7718adaStb 		.opt.arg = &cfg.infile,
85b6995238Sjsing 	},
86b6995238Sjsing 	{
87b6995238Sjsing 		.name = "noverify",
88b6995238Sjsing 		.desc = "Do not verify password",
89b6995238Sjsing 		.type = OPTION_FLAG,
90*e7718adaStb 		.opt.flag = &cfg.noverify,
91b6995238Sjsing 	},
92b6995238Sjsing 	{
93b6995238Sjsing 		.name = "quiet",
94b6995238Sjsing 		.desc = "Do not output warnings",
95b6995238Sjsing 		.type = OPTION_FLAG,
96*e7718adaStb 		.opt.flag = &cfg.quiet,
97b6995238Sjsing 	},
98b6995238Sjsing 	{
99b6995238Sjsing 		.name = "reverse",
100b6995238Sjsing 		.desc = "Reverse table columns (requires -table)",
101b6995238Sjsing 		.type = OPTION_FLAG,
102*e7718adaStb 		.opt.flag = &cfg.reverse,
103b6995238Sjsing 	},
104b6995238Sjsing 	{
105b6995238Sjsing 		.name = "salt",
106b6995238Sjsing 		.argname = "string",
107b6995238Sjsing 		.desc = "Use specified salt",
108b6995238Sjsing 		.type = OPTION_ARG,
109*e7718adaStb 		.opt.arg = &cfg.salt,
110b6995238Sjsing 	},
111b6995238Sjsing 	{
112b6995238Sjsing 		.name = "stdin",
113b6995238Sjsing 		.desc = "Read passwords from stdin",
114b6995238Sjsing 		.type = OPTION_FLAG,
115*e7718adaStb 		.opt.flag = &cfg.in_stdin,
116b6995238Sjsing 	},
117b6995238Sjsing 	{
118b6995238Sjsing 		.name = "table",
119b6995238Sjsing 		.desc = "Output cleartext and hashed passwords (tab separated)",
120b6995238Sjsing 		.type = OPTION_FLAG,
121*e7718adaStb 		.opt.flag = &cfg.table,
122b6995238Sjsing 	},
123b6995238Sjsing 	{ NULL },
124b6995238Sjsing };
125b6995238Sjsing 
126b6995238Sjsing static void
passwd_usage(void)127b6995238Sjsing passwd_usage(void)
128b6995238Sjsing {
129b6995238Sjsing         fprintf(stderr, "usage: passwd [-1 | -apr1 | -crypt] [-in file] "
130b6995238Sjsing 	    "[-noverify] [-quiet]\n"
131b6995238Sjsing 	    "    [-reverse] [-salt string] [-stdin] [-table] [password]\n\n");
132b6995238Sjsing         options_usage(passwd_options);
133b6995238Sjsing }
134dab3f910Sjsing 
135dab3f910Sjsing int
passwd_main(int argc,char ** argv)136dab3f910Sjsing passwd_main(int argc, char **argv)
137dab3f910Sjsing {
138b6995238Sjsing 	char *passwd = NULL, **passwds = NULL;
139dab3f910Sjsing 	char *salt_malloc = NULL, *passwd_malloc = NULL;
140dab3f910Sjsing 	size_t passwd_malloc_size = 0;
141dab3f910Sjsing 	BIO *in = NULL, *out = NULL;
142b6995238Sjsing 	int badopt = 0;
143b6995238Sjsing 	int passed_salt = 0;
144dab3f910Sjsing 	size_t pw_maxlen = 0;
145b6995238Sjsing 	int argsused;
146b6995238Sjsing 	int ret = 1;
147dab3f910Sjsing 
14851811eadSderaadt 	if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
1499bc487adSdoug 		perror("pledge");
150e370f0eeSdoug 		exit(1);
151e370f0eeSdoug 	}
1529bc487adSdoug 
153*e7718adaStb 	memset(&cfg, 0, sizeof(cfg));
154b6995238Sjsing 
155b6995238Sjsing 	if (options_parse(argc, argv, passwd_options, NULL, &argsused) != 0) {
156b6995238Sjsing 		passwd_usage();
157dab3f910Sjsing 		goto err;
158dab3f910Sjsing 	}
159dab3f910Sjsing 
160b6995238Sjsing 	if (argsused < argc)
161b6995238Sjsing 		passwds = &argv[argsused];
162*e7718adaStb 	if (cfg.salt != NULL)
163b6995238Sjsing 		passed_salt = 1;
164dab3f910Sjsing 
165*e7718adaStb 	if (!cfg.usecrypt && !cfg.use1 &&
166*e7718adaStb 	    !cfg.useapr1)
167*e7718adaStb 		cfg.usecrypt = 1;	/* use default */
168*e7718adaStb 	if (cfg.usecrypt + cfg.use1 +
169*e7718adaStb 	    cfg.useapr1 > 1)
170b6995238Sjsing 		badopt = 1;	/* conflicting options */
171b6995238Sjsing 
172b6995238Sjsing 	/* Reject unsupported algorithms */
173dab3f910Sjsing #ifdef OPENSSL_NO_DES
174*e7718adaStb 	if (cfg.usecrypt)
175dab3f910Sjsing 		badopt = 1;
176dab3f910Sjsing #endif
177dab3f910Sjsing #ifdef NO_MD5CRYPT_1
178*e7718adaStb 	if (cfg.use1 || cfg.useapr1)
179dab3f910Sjsing 		badopt = 1;
180dab3f910Sjsing #endif
181dab3f910Sjsing 
182dab3f910Sjsing 	if (badopt) {
183b6995238Sjsing 		passwd_usage();
184dab3f910Sjsing 		goto err;
185dab3f910Sjsing 	}
186b6995238Sjsing 
187b6995238Sjsing 	if ((out = BIO_new(BIO_s_file())) == NULL)
188dab3f910Sjsing 		goto err;
189b6995238Sjsing 	BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT);
190b6995238Sjsing 
191*e7718adaStb 	if (cfg.infile != NULL || cfg.in_stdin) {
192b6995238Sjsing 		if ((in = BIO_new(BIO_s_file())) == NULL)
193b6995238Sjsing 			goto err;
194*e7718adaStb 		if (cfg.infile != NULL) {
195*e7718adaStb 			assert(cfg.in_stdin == 0);
196*e7718adaStb 			if (BIO_read_filename(in, cfg.infile) <= 0)
197dab3f910Sjsing 				goto err;
198dab3f910Sjsing 		} else {
199*e7718adaStb 			assert(cfg.in_stdin);
200dab3f910Sjsing 			BIO_set_fp(in, stdin, BIO_NOCLOSE);
201dab3f910Sjsing 		}
202dab3f910Sjsing 	}
203*e7718adaStb 	if (cfg.usecrypt)
204dab3f910Sjsing 		pw_maxlen = 8;
205*e7718adaStb 	else if (cfg.use1 || cfg.useapr1)
206dab3f910Sjsing 		pw_maxlen = 256;/* arbitrary limit, should be enough for most
207dab3f910Sjsing 				 * passwords */
208dab3f910Sjsing 
209dab3f910Sjsing 	if (passwds == NULL) {
210dab3f910Sjsing 		/* no passwords on the command line */
211dab3f910Sjsing 
212dab3f910Sjsing 		passwd_malloc_size = pw_maxlen + 2;
213dab3f910Sjsing 		/* longer than necessary so that we can warn about truncation */
214dab3f910Sjsing 		passwd = passwd_malloc = malloc(passwd_malloc_size);
215dab3f910Sjsing 		if (passwd_malloc == NULL)
216dab3f910Sjsing 			goto err;
217dab3f910Sjsing 	}
218b6995238Sjsing 	if (in == NULL && passwds == NULL) {
219dab3f910Sjsing 		/* build a null-terminated list */
220dab3f910Sjsing 		static char *passwds_static[2] = {NULL, NULL};
221dab3f910Sjsing 
222dab3f910Sjsing 		passwds = passwds_static;
223dab3f910Sjsing 		if (in == NULL)
224b6995238Sjsing 			if (EVP_read_pw_string(passwd_malloc,
225b6995238Sjsing 			    passwd_malloc_size, "Password: ",
226*e7718adaStb 			    !(passed_salt || cfg.noverify)) != 0)
227dab3f910Sjsing 				goto err;
228dab3f910Sjsing 		passwds[0] = passwd_malloc;
229dab3f910Sjsing 	}
230dab3f910Sjsing 	if (in == NULL) {
231dab3f910Sjsing 		assert(passwds != NULL);
232dab3f910Sjsing 		assert(*passwds != NULL);
233dab3f910Sjsing 
234dab3f910Sjsing 		do {	/* loop over list of passwords */
235dab3f910Sjsing 			passwd = *passwds++;
236*e7718adaStb 			if (!do_passwd(passed_salt, &cfg.salt,
237*e7718adaStb 			    &salt_malloc, passwd, out, cfg.quiet,
238*e7718adaStb 			    cfg.table, cfg.reverse,
239*e7718adaStb 			    pw_maxlen, cfg.usecrypt,
240*e7718adaStb 			    cfg.use1, cfg.useapr1))
241dab3f910Sjsing 				goto err;
242b6995238Sjsing 		} while (*passwds != NULL);
243b6995238Sjsing 	} else {
244dab3f910Sjsing 		int done;
245dab3f910Sjsing 
246dab3f910Sjsing 		assert(passwd != NULL);
247dab3f910Sjsing 		do {
248dab3f910Sjsing 			int r = BIO_gets(in, passwd, pw_maxlen + 1);
249dab3f910Sjsing 			if (r > 0) {
250dab3f910Sjsing 				char *c = (strchr(passwd, '\n'));
251dab3f910Sjsing 				if (c != NULL)
252dab3f910Sjsing 					*c = 0;	/* truncate at newline */
253dab3f910Sjsing 				else {
254dab3f910Sjsing 					/* ignore rest of line */
255dab3f910Sjsing 					char trash[BUFSIZ];
256dab3f910Sjsing 					do
257dab3f910Sjsing 						r = BIO_gets(in, trash, sizeof trash);
258dab3f910Sjsing 					while ((r > 0) && (!strchr(trash, '\n')));
259dab3f910Sjsing 				}
260dab3f910Sjsing 
261*e7718adaStb 				if (!do_passwd(passed_salt, &cfg.salt,
262b6995238Sjsing 				    &salt_malloc, passwd, out,
263*e7718adaStb 				    cfg.quiet, cfg.table,
264*e7718adaStb 				    cfg.reverse, pw_maxlen,
265*e7718adaStb 				    cfg.usecrypt, cfg.use1,
266*e7718adaStb 				    cfg.useapr1))
267dab3f910Sjsing 					goto err;
268dab3f910Sjsing 			}
269dab3f910Sjsing 			done = (r <= 0);
270b6995238Sjsing 		} while (!done);
271dab3f910Sjsing 	}
272dab3f910Sjsing 	ret = 0;
273dab3f910Sjsing 
274dab3f910Sjsing  err:
275dab3f910Sjsing 	ERR_print_errors(bio_err);
276b6995238Sjsing 
277dab3f910Sjsing 	free(salt_malloc);
278dab3f910Sjsing 	free(passwd_malloc);
279b6995238Sjsing 
280dab3f910Sjsing 	BIO_free(in);
281dab3f910Sjsing 	BIO_free_all(out);
282dab3f910Sjsing 
283dab3f910Sjsing 	return (ret);
284dab3f910Sjsing }
285dab3f910Sjsing 
286dab3f910Sjsing 
287dab3f910Sjsing #ifndef NO_MD5CRYPT_1
288dab3f910Sjsing /* MD5-based password algorithm (should probably be available as a library
289dab3f910Sjsing  * function; then the static buffer would not be acceptable).
290dab3f910Sjsing  * For magic string "1", this should be compatible to the MD5-based BSD
291dab3f910Sjsing  * password algorithm.
292dab3f910Sjsing  * For 'magic' string "apr1", this is compatible to the MD5-based Apache
293dab3f910Sjsing  * password algorithm.
294dab3f910Sjsing  * (Apparently, the Apache password algorithm is identical except that the
295dab3f910Sjsing  * 'magic' string was changed -- the laziest application of the NIH principle
296dab3f910Sjsing  * I've ever encountered.)
297dab3f910Sjsing  */
298dab3f910Sjsing static char *
md5crypt(const char * passwd,const char * magic,const char * salt)299dab3f910Sjsing md5crypt(const char *passwd, const char *magic, const char *salt)
300dab3f910Sjsing {
301dab3f910Sjsing 	static char out_buf[6 + 9 + 24 + 2];	/* "$apr1$..salt..$.......md5h
302dab3f910Sjsing 						 * ash..........\0" */
303dab3f910Sjsing 	unsigned char buf[MD5_DIGEST_LENGTH];
304dab3f910Sjsing 	char *salt_out;
305dab3f910Sjsing 	int n;
306dab3f910Sjsing 	unsigned int i;
30770158555Stb 	EVP_MD_CTX *md = NULL, *md2 = NULL;
308dab3f910Sjsing 	size_t passwd_len, salt_len;
309dab3f910Sjsing 
310dab3f910Sjsing 	passwd_len = strlen(passwd);
311dab3f910Sjsing 	out_buf[0] = '$';
312dab3f910Sjsing 	out_buf[1] = 0;
313dab3f910Sjsing 	assert(strlen(magic) <= 4);	/* "1" or "apr1" */
314dab3f910Sjsing 	strlcat(out_buf, magic, sizeof(out_buf));
315dab3f910Sjsing 	strlcat(out_buf, "$", sizeof(out_buf));
316dab3f910Sjsing 	strlcat(out_buf, salt, sizeof(out_buf));
317dab3f910Sjsing 	assert(strlen(out_buf) <= 6 + 8);	/* "$apr1$..salt.." */
318dab3f910Sjsing 	salt_out = out_buf + 2 + strlen(magic);
319dab3f910Sjsing 	salt_len = strlen(salt_out);
320dab3f910Sjsing 	assert(salt_len <= 8);
321dab3f910Sjsing 
32270158555Stb 	if ((md = EVP_MD_CTX_new()) == NULL)
32370158555Stb 		goto err;
32470158555Stb 	if (!EVP_DigestInit_ex(md, EVP_md5(), NULL))
32570158555Stb 		goto err;
32670158555Stb 	if (!EVP_DigestUpdate(md, passwd, passwd_len))
32770158555Stb 		goto err;
32870158555Stb 	if (!EVP_DigestUpdate(md, "$", 1))
32970158555Stb 		goto err;
33070158555Stb 	if (!EVP_DigestUpdate(md, magic, strlen(magic)))
33170158555Stb 		goto err;
33270158555Stb 	if (!EVP_DigestUpdate(md, "$", 1))
33370158555Stb 		goto err;
33470158555Stb 	if (!EVP_DigestUpdate(md, salt_out, salt_len))
33570158555Stb 		goto err;
336dab3f910Sjsing 
33770158555Stb 	if ((md2 = EVP_MD_CTX_new()) == NULL)
33870158555Stb 		goto err;
33970158555Stb 	if (!EVP_DigestInit_ex(md2, EVP_md5(), NULL))
34070158555Stb 		goto err;
34170158555Stb 	if (!EVP_DigestUpdate(md2, passwd, passwd_len))
34270158555Stb 		goto err;
34370158555Stb 	if (!EVP_DigestUpdate(md2, salt_out, salt_len))
34470158555Stb 		goto err;
34570158555Stb 	if (!EVP_DigestUpdate(md2, passwd, passwd_len))
34670158555Stb 		goto err;
34770158555Stb 	if (!EVP_DigestFinal_ex(md2, buf, NULL))
34870158555Stb 		goto err;
349dab3f910Sjsing 
35070158555Stb 	for (i = passwd_len; i > sizeof buf; i -= sizeof buf) {
35170158555Stb 		if (!EVP_DigestUpdate(md, buf, sizeof buf))
35270158555Stb 			goto err;
35370158555Stb 	}
35470158555Stb 	if (!EVP_DigestUpdate(md, buf, i))
35570158555Stb 		goto err;
356dab3f910Sjsing 
357dab3f910Sjsing 	n = passwd_len;
358dab3f910Sjsing 	while (n) {
35970158555Stb 		if (!EVP_DigestUpdate(md, (n & 1) ? "\0" : passwd, 1))
36070158555Stb 			goto err;
361dab3f910Sjsing 		n >>= 1;
362dab3f910Sjsing 	}
36370158555Stb 	if (!EVP_DigestFinal_ex(md, buf, NULL))
36470158555Stb 		goto err;
365dab3f910Sjsing 
366dab3f910Sjsing 	for (i = 0; i < 1000; i++) {
36770158555Stb 		if (!EVP_DigestInit_ex(md2, EVP_md5(), NULL))
36870158555Stb 			goto err;
36970158555Stb 		if (!EVP_DigestUpdate(md2,
37070158555Stb 		    (i & 1) ? (unsigned const char *) passwd : buf,
37170158555Stb 		    (i & 1) ? passwd_len : sizeof buf))
37270158555Stb 			goto err;
37370158555Stb 		if (i % 3) {
37470158555Stb 			if (!EVP_DigestUpdate(md2, salt_out, salt_len))
37570158555Stb 				goto err;
376dab3f910Sjsing 		}
37770158555Stb 		if (i % 7) {
37870158555Stb 			if (!EVP_DigestUpdate(md2, passwd, passwd_len))
37970158555Stb 				goto err;
38070158555Stb 		}
38170158555Stb 		if (!EVP_DigestUpdate(md2,
38270158555Stb 		    (i & 1) ? buf : (unsigned const char *) passwd,
38370158555Stb 		    (i & 1) ? sizeof buf : passwd_len))
38470158555Stb 			goto err;
38570158555Stb 		if (!EVP_DigestFinal_ex(md2, buf, NULL))
38670158555Stb 			goto err;
38770158555Stb 	}
38870158555Stb 	EVP_MD_CTX_free(md2);
38970158555Stb 	md2 = NULL;
390dab3f910Sjsing 
391dab3f910Sjsing 	{
392dab3f910Sjsing 		/* transform buf into output string */
393dab3f910Sjsing 
394dab3f910Sjsing 		unsigned char buf_perm[sizeof buf];
395dab3f910Sjsing 		int dest, source;
396dab3f910Sjsing 		char *output;
397dab3f910Sjsing 
398dab3f910Sjsing 		/* silly output permutation */
399dab3f910Sjsing 		for (dest = 0, source = 0; dest < 14; dest++, source = (source + 6) % 17)
400dab3f910Sjsing 			buf_perm[dest] = buf[source];
401dab3f910Sjsing 		buf_perm[14] = buf[5];
402dab3f910Sjsing 		buf_perm[15] = buf[11];
403dab3f910Sjsing 		assert(16 == sizeof buf_perm);
404dab3f910Sjsing 
405dab3f910Sjsing 		output = salt_out + salt_len;
406dab3f910Sjsing 		assert(output == out_buf + strlen(out_buf));
407dab3f910Sjsing 
408dab3f910Sjsing 		*output++ = '$';
409dab3f910Sjsing 
410dab3f910Sjsing 		for (i = 0; i < 15; i += 3) {
411dab3f910Sjsing 			*output++ = cov_2char[buf_perm[i + 2] & 0x3f];
412dab3f910Sjsing 			*output++ = cov_2char[((buf_perm[i + 1] & 0xf) << 2) |
413dab3f910Sjsing 			    (buf_perm[i + 2] >> 6)];
414dab3f910Sjsing 			*output++ = cov_2char[((buf_perm[i] & 3) << 4) |
415dab3f910Sjsing 			    (buf_perm[i + 1] >> 4)];
416dab3f910Sjsing 			*output++ = cov_2char[buf_perm[i] >> 2];
417dab3f910Sjsing 		}
418dab3f910Sjsing 		assert(i == 15);
419dab3f910Sjsing 		*output++ = cov_2char[buf_perm[i] & 0x3f];
420dab3f910Sjsing 		*output++ = cov_2char[buf_perm[i] >> 6];
421dab3f910Sjsing 		*output = 0;
422dab3f910Sjsing 		assert(strlen(out_buf) < sizeof(out_buf));
423dab3f910Sjsing 	}
42470158555Stb 	EVP_MD_CTX_free(md);
425dab3f910Sjsing 
426dab3f910Sjsing 	return out_buf;
42770158555Stb  err:
42870158555Stb 	EVP_MD_CTX_free(md);
42970158555Stb 	EVP_MD_CTX_free(md2);
43070158555Stb 
43170158555Stb 	return NULL;
432dab3f910Sjsing }
433dab3f910Sjsing #endif
434dab3f910Sjsing 
435dab3f910Sjsing 
436dab3f910Sjsing static int
do_passwd(int passed_salt,char ** salt_p,char ** salt_malloc_p,char * passwd,BIO * out,int quiet,int table,int reverse,size_t pw_maxlen,int usecrypt,int use1,int useapr1)437dab3f910Sjsing do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p,
438dab3f910Sjsing     char *passwd, BIO * out, int quiet, int table, int reverse,
439dab3f910Sjsing     size_t pw_maxlen, int usecrypt, int use1, int useapr1)
440dab3f910Sjsing {
441dab3f910Sjsing 	char *hash = NULL;
442dab3f910Sjsing 
443dab3f910Sjsing 	assert(salt_p != NULL);
444dab3f910Sjsing 	assert(salt_malloc_p != NULL);
445dab3f910Sjsing 
446dab3f910Sjsing 	/* first make sure we have a salt */
447dab3f910Sjsing 	if (!passed_salt) {
448dab3f910Sjsing #ifndef OPENSSL_NO_DES
449dab3f910Sjsing 		if (usecrypt) {
450dab3f910Sjsing 			if (*salt_malloc_p == NULL) {
451dab3f910Sjsing 				*salt_p = *salt_malloc_p = malloc(3);
452dab3f910Sjsing 				if (*salt_malloc_p == NULL)
453dab3f910Sjsing 					goto err;
454dab3f910Sjsing 			}
455fd6ab616Sjsing 			arc4random_buf(*salt_p, 2);
456dab3f910Sjsing 			(*salt_p)[0] = cov_2char[(*salt_p)[0] & 0x3f];	/* 6 bits */
457dab3f910Sjsing 			(*salt_p)[1] = cov_2char[(*salt_p)[1] & 0x3f];	/* 6 bits */
458dab3f910Sjsing 			(*salt_p)[2] = 0;
459dab3f910Sjsing 		}
460dab3f910Sjsing #endif				/* !OPENSSL_NO_DES */
461dab3f910Sjsing 
462dab3f910Sjsing #ifndef NO_MD5CRYPT_1
463dab3f910Sjsing 		if (use1 || useapr1) {
464dab3f910Sjsing 			int i;
465dab3f910Sjsing 
466dab3f910Sjsing 			if (*salt_malloc_p == NULL) {
467dab3f910Sjsing 				*salt_p = *salt_malloc_p = malloc(9);
468dab3f910Sjsing 				if (*salt_malloc_p == NULL)
469dab3f910Sjsing 					goto err;
470dab3f910Sjsing 			}
471fd6ab616Sjsing 			arc4random_buf(*salt_p, 8);
472dab3f910Sjsing 
473dab3f910Sjsing 			for (i = 0; i < 8; i++)
474dab3f910Sjsing 				(*salt_p)[i] = cov_2char[(*salt_p)[i] & 0x3f];	/* 6 bits */
475dab3f910Sjsing 			(*salt_p)[8] = 0;
476dab3f910Sjsing 		}
477dab3f910Sjsing #endif				/* !NO_MD5CRYPT_1 */
478dab3f910Sjsing 	}
479dab3f910Sjsing 	assert(*salt_p != NULL);
480dab3f910Sjsing 
481dab3f910Sjsing 	/* truncate password if necessary */
482dab3f910Sjsing 	if ((strlen(passwd) > pw_maxlen)) {
483dab3f910Sjsing 		if (!quiet)
484129f13dcStb 			BIO_printf(bio_err,
485129f13dcStb 			    "Warning: truncating password to %zu characters\n",
486129f13dcStb 			    pw_maxlen);
487dab3f910Sjsing 		passwd[pw_maxlen] = 0;
488dab3f910Sjsing 	}
489dab3f910Sjsing 	assert(strlen(passwd) <= pw_maxlen);
490dab3f910Sjsing 
491dab3f910Sjsing 	/* now compute password hash */
492dab3f910Sjsing #ifndef OPENSSL_NO_DES
493dab3f910Sjsing 	if (usecrypt)
494dab3f910Sjsing 		hash = DES_crypt(passwd, *salt_p);
495dab3f910Sjsing #endif
496dab3f910Sjsing #ifndef NO_MD5CRYPT_1
497dab3f910Sjsing 	if (use1 || useapr1)
49870158555Stb 		if ((hash = md5crypt(passwd, (use1 ? "1" : "apr1"), *salt_p)) == NULL)
49970158555Stb 			goto err;
500dab3f910Sjsing #endif
501dab3f910Sjsing 	assert(hash != NULL);
502dab3f910Sjsing 
503dab3f910Sjsing 	if (table && !reverse)
504dab3f910Sjsing 		BIO_printf(out, "%s\t%s\n", passwd, hash);
505dab3f910Sjsing 	else if (table && reverse)
506dab3f910Sjsing 		BIO_printf(out, "%s\t%s\n", hash, passwd);
507dab3f910Sjsing 	else
508dab3f910Sjsing 		BIO_printf(out, "%s\n", hash);
509dab3f910Sjsing 	return 1;
510dab3f910Sjsing 
511dab3f910Sjsing  err:
51270158555Stb 	free(*salt_malloc_p);
51370158555Stb 	*salt_malloc_p = NULL;
514dab3f910Sjsing 	return 0;
515dab3f910Sjsing }
516dab3f910Sjsing #else
517dab3f910Sjsing 
518dab3f910Sjsing int
passwd_main(int argc,char ** argv)519dab3f910Sjsing passwd_main(int argc, char **argv)
520dab3f910Sjsing {
521dab3f910Sjsing 	fputs("Program not available.\n", stderr)
522dab3f910Sjsing 	return (1);
523dab3f910Sjsing }
524dab3f910Sjsing #endif
525