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