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