diff options
author | deshevoy <deshevoy@yandex-team.ru> | 2022-02-10 16:46:57 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:46:57 +0300 |
commit | 28148f76dbfcc644d96427d41c92f36cbf2fdc6e (patch) | |
tree | b83306b6e37edeea782e9eed673d89286c4fef35 /contrib/libs/openssl/apps/passwd.c | |
parent | e988f30484abe5fdeedcc7a5d3c226c01a21800c (diff) | |
download | ydb-28148f76dbfcc644d96427d41c92f36cbf2fdc6e.tar.gz |
Restoring authorship annotation for <deshevoy@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/openssl/apps/passwd.c')
-rw-r--r-- | contrib/libs/openssl/apps/passwd.c | 1704 |
1 files changed, 852 insertions, 852 deletions
diff --git a/contrib/libs/openssl/apps/passwd.c b/contrib/libs/openssl/apps/passwd.c index f05156a113..d741d05335 100644 --- a/contrib/libs/openssl/apps/passwd.c +++ b/contrib/libs/openssl/apps/passwd.c @@ -1,853 +1,853 @@ -/* - * Copyright 2000-2018 The OpenSSL Project Authors. All Rights Reserved. - * - * Licensed under the OpenSSL license (the "License"). You may not use - * this file except in compliance with the License. You can obtain a copy - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <string.h> - -#include "apps.h" -#include "progs.h" - -#include <openssl/bio.h> -#include <openssl/err.h> -#include <openssl/evp.h> -#include <openssl/rand.h> -#ifndef OPENSSL_NO_DES -# include <openssl/des.h> -#endif -#include <openssl/md5.h> -#include <openssl/sha.h> - -static unsigned const char cov_2char[64] = { - /* from crypto/des/fcrypt.c */ - 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, - 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, - 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, - 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, - 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, - 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A -}; - -static const char ascii_dollar[] = { 0x24, 0x00 }; - -typedef enum { - passwd_unset = 0, - passwd_crypt, - passwd_md5, - passwd_apr1, - passwd_sha256, - passwd_sha512, - passwd_aixmd5 -} passwd_modes; - -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, passwd_modes mode); - -typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_IN, - OPT_NOVERIFY, OPT_QUIET, OPT_TABLE, OPT_REVERSE, OPT_APR1, - OPT_1, OPT_5, OPT_6, OPT_CRYPT, OPT_AIXMD5, OPT_SALT, OPT_STDIN, - OPT_R_ENUM -} OPTION_CHOICE; - -const OPTIONS passwd_options[] = { - {"help", OPT_HELP, '-', "Display this summary"}, - {"in", OPT_IN, '<', "Read passwords from file"}, - {"noverify", OPT_NOVERIFY, '-', - "Never verify when reading password from terminal"}, - {"quiet", OPT_QUIET, '-', "No warnings"}, - {"table", OPT_TABLE, '-', "Format output as table"}, - {"reverse", OPT_REVERSE, '-', "Switch table columns"}, - {"salt", OPT_SALT, 's', "Use provided salt"}, - {"stdin", OPT_STDIN, '-', "Read passwords from stdin"}, - {"6", OPT_6, '-', "SHA512-based password algorithm"}, - {"5", OPT_5, '-', "SHA256-based password algorithm"}, - {"apr1", OPT_APR1, '-', "MD5-based password algorithm, Apache variant"}, - {"1", OPT_1, '-', "MD5-based password algorithm"}, - {"aixmd5", OPT_AIXMD5, '-', "AIX MD5-based password algorithm"}, -#ifndef OPENSSL_NO_DES - {"crypt", OPT_CRYPT, '-', "Standard Unix password algorithm (default)"}, -#endif - OPT_R_OPTIONS, - {NULL} -}; - -int passwd_main(int argc, char **argv) -{ - BIO *in = NULL; - char *infile = NULL, *salt = NULL, *passwd = NULL, **passwds = NULL; - char *salt_malloc = NULL, *passwd_malloc = NULL, *prog; - OPTION_CHOICE o; - int in_stdin = 0, pw_source_defined = 0; -#ifndef OPENSSL_NO_UI_CONSOLE - int in_noverify = 0; -#endif - int passed_salt = 0, quiet = 0, table = 0, reverse = 0; - int ret = 1; - passwd_modes mode = passwd_unset; - size_t passwd_malloc_size = 0; - size_t pw_maxlen = 256; /* arbitrary limit, should be enough for most - * passwords */ - - prog = opt_init(argc, argv, passwd_options); - while ((o = opt_next()) != OPT_EOF) { - switch (o) { - case OPT_EOF: - case OPT_ERR: - opthelp: - BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); - goto end; - case OPT_HELP: - opt_help(passwd_options); - ret = 0; - goto end; - case OPT_IN: - if (pw_source_defined) - goto opthelp; - infile = opt_arg(); - pw_source_defined = 1; - break; - case OPT_NOVERIFY: -#ifndef OPENSSL_NO_UI_CONSOLE - in_noverify = 1; -#endif - break; - case OPT_QUIET: - quiet = 1; - break; - case OPT_TABLE: - table = 1; - break; - case OPT_REVERSE: - reverse = 1; - break; - case OPT_1: - if (mode != passwd_unset) - goto opthelp; - mode = passwd_md5; - break; - case OPT_5: - if (mode != passwd_unset) - goto opthelp; - mode = passwd_sha256; - break; - case OPT_6: - if (mode != passwd_unset) - goto opthelp; - mode = passwd_sha512; - break; - case OPT_APR1: - if (mode != passwd_unset) - goto opthelp; - mode = passwd_apr1; - break; - case OPT_AIXMD5: - if (mode != passwd_unset) - goto opthelp; - mode = passwd_aixmd5; - break; - case OPT_CRYPT: -#ifndef OPENSSL_NO_DES - if (mode != passwd_unset) - goto opthelp; - mode = passwd_crypt; -#endif - break; - case OPT_SALT: - passed_salt = 1; - salt = opt_arg(); - break; - case OPT_STDIN: - if (pw_source_defined) - goto opthelp; - in_stdin = 1; - pw_source_defined = 1; - break; - case OPT_R_CASES: - if (!opt_rand(o)) - goto end; - break; - } - } - argc = opt_num_rest(); - argv = opt_rest(); - - if (*argv != NULL) { - if (pw_source_defined) - goto opthelp; - pw_source_defined = 1; - passwds = argv; - } - - if (mode == passwd_unset) { - /* use default */ - mode = passwd_crypt; - } - -#ifdef OPENSSL_NO_DES - if (mode == passwd_crypt) - goto opthelp; -#endif - - if (infile != NULL && in_stdin) { - BIO_printf(bio_err, "%s: Can't combine -in and -stdin\n", prog); - goto end; - } - - if (infile != NULL || in_stdin) { - /* - * If in_stdin is true, we know that infile is NULL, and that - * bio_open_default() will give us back an alias for stdin. - */ - in = bio_open_default(infile, 'r', FORMAT_TEXT); - if (in == NULL) - goto end; - } - - if (mode == passwd_crypt) - pw_maxlen = 8; - - if (passwds == NULL) { - /* no passwords on the command line */ - - passwd_malloc_size = pw_maxlen + 2; - /* longer than necessary so that we can warn about truncation */ - passwd = passwd_malloc = - app_malloc(passwd_malloc_size, "password buffer"); - } - - if ((in == NULL) && (passwds == NULL)) { - /* - * we use the following method to make sure what - * in the 'else' section is always compiled, to - * avoid rot of not-frequently-used code. - */ - if (1) { -#ifndef OPENSSL_NO_UI_CONSOLE - /* build a null-terminated list */ - static char *passwds_static[2] = { NULL, NULL }; - - passwds = passwds_static; - if (in == NULL) { - if (EVP_read_pw_string - (passwd_malloc, passwd_malloc_size, "Password: ", - !(passed_salt || in_noverify)) != 0) - goto end; - } - passwds[0] = passwd_malloc; - } else { -#endif - BIO_printf(bio_err, "password required\n"); - goto end; - } - } - - if (in == NULL) { - assert(passwds != NULL); - assert(*passwds != NULL); - - do { /* loop over list of passwords */ - passwd = *passwds++; - if (!do_passwd(passed_salt, &salt, &salt_malloc, passwd, bio_out, - quiet, table, reverse, pw_maxlen, mode)) - goto end; - } while (*passwds != NULL); - } else { - /* in != NULL */ - int done; - - assert(passwd != NULL); - do { - int r = BIO_gets(in, passwd, pw_maxlen + 1); - if (r > 0) { - char *c = (strchr(passwd, '\n')); - if (c != NULL) { - *c = 0; /* truncate at newline */ - } else { - /* ignore rest of line */ - char trash[BUFSIZ]; - do - r = BIO_gets(in, trash, sizeof(trash)); - while ((r > 0) && (!strchr(trash, '\n'))); - } - - if (!do_passwd - (passed_salt, &salt, &salt_malloc, passwd, bio_out, quiet, - table, reverse, pw_maxlen, mode)) - goto end; - } - done = (r <= 0); - } while (!done); - } - ret = 0; - - end: -#if 0 - ERR_print_errors(bio_err); -#endif - OPENSSL_free(salt_malloc); - OPENSSL_free(passwd_malloc); - BIO_free(in); - return ret; -} - -/* - * MD5-based password algorithm (should probably be available as a library - * function; then the static buffer would not be acceptable). For magic - * string "1", this should be compatible to the MD5-based BSD password - * algorithm. For 'magic' string "apr1", this is compatible to the MD5-based - * Apache password algorithm. (Apparently, the Apache password algorithm is - * identical except that the 'magic' string was changed -- the laziest - * application of the NIH principle I've ever encountered.) - */ -static char *md5crypt(const char *passwd, const char *magic, const char *salt) -{ - /* "$apr1$..salt..$.......md5hash..........\0" */ - static char out_buf[6 + 9 + 24 + 2]; - unsigned char buf[MD5_DIGEST_LENGTH]; - char ascii_magic[5]; /* "apr1" plus '\0' */ - char ascii_salt[9]; /* Max 8 chars plus '\0' */ - char *ascii_passwd = NULL; - char *salt_out; - int n; - unsigned int i; - EVP_MD_CTX *md = NULL, *md2 = NULL; - size_t passwd_len, salt_len, magic_len; - - passwd_len = strlen(passwd); - - out_buf[0] = 0; - magic_len = strlen(magic); - OPENSSL_strlcpy(ascii_magic, magic, sizeof(ascii_magic)); -#ifdef CHARSET_EBCDIC - if ((magic[0] & 0x80) != 0) /* High bit is 1 in EBCDIC alnums */ - ebcdic2ascii(ascii_magic, ascii_magic, magic_len); -#endif - - /* The salt gets truncated to 8 chars */ - OPENSSL_strlcpy(ascii_salt, salt, sizeof(ascii_salt)); - salt_len = strlen(ascii_salt); -#ifdef CHARSET_EBCDIC - ebcdic2ascii(ascii_salt, ascii_salt, salt_len); -#endif - -#ifdef CHARSET_EBCDIC - ascii_passwd = OPENSSL_strdup(passwd); - if (ascii_passwd == NULL) - return NULL; - ebcdic2ascii(ascii_passwd, ascii_passwd, passwd_len); - passwd = ascii_passwd; -#endif - - if (magic_len > 0) { - OPENSSL_strlcat(out_buf, ascii_dollar, sizeof(out_buf)); - - if (magic_len > 4) /* assert it's "1" or "apr1" */ - goto err; - - OPENSSL_strlcat(out_buf, ascii_magic, sizeof(out_buf)); - OPENSSL_strlcat(out_buf, ascii_dollar, sizeof(out_buf)); - } - - OPENSSL_strlcat(out_buf, ascii_salt, sizeof(out_buf)); - - if (strlen(out_buf) > 6 + 8) /* assert "$apr1$..salt.." */ - goto err; - - salt_out = out_buf; - if (magic_len > 0) - salt_out += 2 + magic_len; - - if (salt_len > 8) - goto err; - - md = EVP_MD_CTX_new(); - if (md == NULL - || !EVP_DigestInit_ex(md, EVP_md5(), NULL) - || !EVP_DigestUpdate(md, passwd, passwd_len)) - goto err; - - if (magic_len > 0) - if (!EVP_DigestUpdate(md, ascii_dollar, 1) - || !EVP_DigestUpdate(md, ascii_magic, magic_len) - || !EVP_DigestUpdate(md, ascii_dollar, 1)) - goto err; - - if (!EVP_DigestUpdate(md, ascii_salt, salt_len)) - goto err; - - md2 = EVP_MD_CTX_new(); - if (md2 == NULL - || !EVP_DigestInit_ex(md2, EVP_md5(), NULL) - || !EVP_DigestUpdate(md2, passwd, passwd_len) - || !EVP_DigestUpdate(md2, ascii_salt, salt_len) - || !EVP_DigestUpdate(md2, passwd, passwd_len) - || !EVP_DigestFinal_ex(md2, buf, NULL)) - goto err; - - for (i = passwd_len; i > sizeof(buf); i -= sizeof(buf)) { - if (!EVP_DigestUpdate(md, buf, sizeof(buf))) - goto err; - } - if (!EVP_DigestUpdate(md, buf, i)) - goto err; - - n = passwd_len; - while (n) { - if (!EVP_DigestUpdate(md, (n & 1) ? "\0" : passwd, 1)) - goto err; - n >>= 1; - } - if (!EVP_DigestFinal_ex(md, buf, NULL)) - return NULL; - - for (i = 0; i < 1000; i++) { - if (!EVP_DigestInit_ex(md2, EVP_md5(), NULL)) - goto err; - if (!EVP_DigestUpdate(md2, - (i & 1) ? (unsigned const char *)passwd : buf, - (i & 1) ? passwd_len : sizeof(buf))) - goto err; - if (i % 3) { - if (!EVP_DigestUpdate(md2, ascii_salt, salt_len)) - goto err; - } - if (i % 7) { - if (!EVP_DigestUpdate(md2, passwd, passwd_len)) - goto err; - } - if (!EVP_DigestUpdate(md2, - (i & 1) ? buf : (unsigned const char *)passwd, - (i & 1) ? sizeof(buf) : passwd_len)) - goto err; - if (!EVP_DigestFinal_ex(md2, buf, NULL)) - goto err; - } - EVP_MD_CTX_free(md2); - EVP_MD_CTX_free(md); - md2 = NULL; - md = NULL; - - { - /* transform buf into output string */ - unsigned char buf_perm[sizeof(buf)]; - int dest, source; - char *output; - - /* silly output permutation */ - for (dest = 0, source = 0; dest < 14; - dest++, source = (source + 6) % 17) - buf_perm[dest] = buf[source]; - buf_perm[14] = buf[5]; - buf_perm[15] = buf[11]; -# ifndef PEDANTIC /* Unfortunately, this generates a "no - * effect" warning */ - assert(16 == sizeof(buf_perm)); -# endif - - output = salt_out + salt_len; - assert(output == out_buf + strlen(out_buf)); - - *output++ = ascii_dollar[0]; - - for (i = 0; i < 15; i += 3) { - *output++ = cov_2char[buf_perm[i + 2] & 0x3f]; - *output++ = cov_2char[((buf_perm[i + 1] & 0xf) << 2) | - (buf_perm[i + 2] >> 6)]; - *output++ = cov_2char[((buf_perm[i] & 3) << 4) | - (buf_perm[i + 1] >> 4)]; - *output++ = cov_2char[buf_perm[i] >> 2]; - } - assert(i == 15); - *output++ = cov_2char[buf_perm[i] & 0x3f]; - *output++ = cov_2char[buf_perm[i] >> 6]; - *output = 0; - assert(strlen(out_buf) < sizeof(out_buf)); -#ifdef CHARSET_EBCDIC - ascii2ebcdic(out_buf, out_buf, strlen(out_buf)); -#endif - } - - return out_buf; - - err: - OPENSSL_free(ascii_passwd); - EVP_MD_CTX_free(md2); - EVP_MD_CTX_free(md); - return NULL; -} - -/* - * SHA based password algorithm, describe by Ulrich Drepper here: - * https://www.akkadia.org/drepper/SHA-crypt.txt - * (note that it's in the public domain) - */ -static char *shacrypt(const char *passwd, const char *magic, const char *salt) -{ - /* Prefix for optional rounds specification. */ - static const char rounds_prefix[] = "rounds="; - /* Maximum salt string length. */ -# define SALT_LEN_MAX 16 - /* Default number of rounds if not explicitly specified. */ -# define ROUNDS_DEFAULT 5000 - /* Minimum number of rounds. */ -# define ROUNDS_MIN 1000 - /* Maximum number of rounds. */ -# define ROUNDS_MAX 999999999 - - /* "$6$rounds=<N>$......salt......$...shahash(up to 86 chars)...\0" */ - static char out_buf[3 + 17 + 17 + 86 + 1]; - unsigned char buf[SHA512_DIGEST_LENGTH]; - unsigned char temp_buf[SHA512_DIGEST_LENGTH]; - size_t buf_size = 0; - char ascii_magic[2]; - char ascii_salt[17]; /* Max 16 chars plus '\0' */ - char *ascii_passwd = NULL; - size_t n; - EVP_MD_CTX *md = NULL, *md2 = NULL; - const EVP_MD *sha = NULL; - size_t passwd_len, salt_len, magic_len; - unsigned int rounds = 5000; /* Default */ - char rounds_custom = 0; - char *p_bytes = NULL; - char *s_bytes = NULL; - char *cp = NULL; - - passwd_len = strlen(passwd); - magic_len = strlen(magic); - - /* assert it's "5" or "6" */ - if (magic_len != 1) - return NULL; - - switch (magic[0]) { - case '5': - sha = EVP_sha256(); - buf_size = 32; - break; - case '6': - sha = EVP_sha512(); - buf_size = 64; - break; - default: - return NULL; - } - - if (strncmp(salt, rounds_prefix, sizeof(rounds_prefix) - 1) == 0) { - const char *num = salt + sizeof(rounds_prefix) - 1; - char *endp; - unsigned long int srounds = strtoul (num, &endp, 10); - if (*endp == '$') { - salt = endp + 1; - if (srounds > ROUNDS_MAX) - rounds = ROUNDS_MAX; - else if (srounds < ROUNDS_MIN) - rounds = ROUNDS_MIN; - else - rounds = (unsigned int)srounds; - rounds_custom = 1; - } else { - return NULL; - } - } - - OPENSSL_strlcpy(ascii_magic, magic, sizeof(ascii_magic)); -#ifdef CHARSET_EBCDIC - if ((magic[0] & 0x80) != 0) /* High bit is 1 in EBCDIC alnums */ - ebcdic2ascii(ascii_magic, ascii_magic, magic_len); -#endif - - /* The salt gets truncated to 16 chars */ - OPENSSL_strlcpy(ascii_salt, salt, sizeof(ascii_salt)); - salt_len = strlen(ascii_salt); -#ifdef CHARSET_EBCDIC - ebcdic2ascii(ascii_salt, ascii_salt, salt_len); -#endif - -#ifdef CHARSET_EBCDIC - ascii_passwd = OPENSSL_strdup(passwd); - if (ascii_passwd == NULL) - return NULL; - ebcdic2ascii(ascii_passwd, ascii_passwd, passwd_len); - passwd = ascii_passwd; -#endif - - out_buf[0] = 0; - OPENSSL_strlcat(out_buf, ascii_dollar, sizeof(out_buf)); - OPENSSL_strlcat(out_buf, ascii_magic, sizeof(out_buf)); - OPENSSL_strlcat(out_buf, ascii_dollar, sizeof(out_buf)); - if (rounds_custom) { - char tmp_buf[80]; /* "rounds=999999999" */ - sprintf(tmp_buf, "rounds=%u", rounds); -#ifdef CHARSET_EBCDIC - /* In case we're really on a ASCII based platform and just pretend */ - if (tmp_buf[0] != 0x72) /* ASCII 'r' */ - ebcdic2ascii(tmp_buf, tmp_buf, strlen(tmp_buf)); -#endif - OPENSSL_strlcat(out_buf, tmp_buf, sizeof(out_buf)); - OPENSSL_strlcat(out_buf, ascii_dollar, sizeof(out_buf)); - } - OPENSSL_strlcat(out_buf, ascii_salt, sizeof(out_buf)); - - /* assert "$5$rounds=999999999$......salt......" */ - if (strlen(out_buf) > 3 + 17 * rounds_custom + salt_len ) - goto err; - - md = EVP_MD_CTX_new(); - if (md == NULL - || !EVP_DigestInit_ex(md, sha, NULL) - || !EVP_DigestUpdate(md, passwd, passwd_len) - || !EVP_DigestUpdate(md, ascii_salt, salt_len)) - goto err; - - md2 = EVP_MD_CTX_new(); - if (md2 == NULL - || !EVP_DigestInit_ex(md2, sha, NULL) - || !EVP_DigestUpdate(md2, passwd, passwd_len) - || !EVP_DigestUpdate(md2, ascii_salt, salt_len) - || !EVP_DigestUpdate(md2, passwd, passwd_len) - || !EVP_DigestFinal_ex(md2, buf, NULL)) - goto err; - - for (n = passwd_len; n > buf_size; n -= buf_size) { - if (!EVP_DigestUpdate(md, buf, buf_size)) - goto err; - } - if (!EVP_DigestUpdate(md, buf, n)) - goto err; - - n = passwd_len; - while (n) { - if (!EVP_DigestUpdate(md, - (n & 1) ? buf : (unsigned const char *)passwd, - (n & 1) ? buf_size : passwd_len)) - goto err; - n >>= 1; - } - if (!EVP_DigestFinal_ex(md, buf, NULL)) - return NULL; - - /* P sequence */ - if (!EVP_DigestInit_ex(md2, sha, NULL)) - goto err; - - for (n = passwd_len; n > 0; n--) - if (!EVP_DigestUpdate(md2, passwd, passwd_len)) - goto err; - - if (!EVP_DigestFinal_ex(md2, temp_buf, NULL)) - return NULL; - - if ((p_bytes = OPENSSL_zalloc(passwd_len)) == NULL) - goto err; - for (cp = p_bytes, n = passwd_len; n > buf_size; n -= buf_size, cp += buf_size) - memcpy(cp, temp_buf, buf_size); - memcpy(cp, temp_buf, n); - - /* S sequence */ - if (!EVP_DigestInit_ex(md2, sha, NULL)) - goto err; - - for (n = 16 + buf[0]; n > 0; n--) - if (!EVP_DigestUpdate(md2, ascii_salt, salt_len)) - goto err; - - if (!EVP_DigestFinal_ex(md2, temp_buf, NULL)) - return NULL; - - if ((s_bytes = OPENSSL_zalloc(salt_len)) == NULL) - goto err; - for (cp = s_bytes, n = salt_len; n > buf_size; n -= buf_size, cp += buf_size) - memcpy(cp, temp_buf, buf_size); - memcpy(cp, temp_buf, n); - - for (n = 0; n < rounds; n++) { - if (!EVP_DigestInit_ex(md2, sha, NULL)) - goto err; - if (!EVP_DigestUpdate(md2, - (n & 1) ? (unsigned const char *)p_bytes : buf, - (n & 1) ? passwd_len : buf_size)) - goto err; - if (n % 3) { - if (!EVP_DigestUpdate(md2, s_bytes, salt_len)) - goto err; - } - if (n % 7) { - if (!EVP_DigestUpdate(md2, p_bytes, passwd_len)) - goto err; - } - if (!EVP_DigestUpdate(md2, - (n & 1) ? buf : (unsigned const char *)p_bytes, - (n & 1) ? buf_size : passwd_len)) - goto err; - if (!EVP_DigestFinal_ex(md2, buf, NULL)) - goto err; - } - EVP_MD_CTX_free(md2); - EVP_MD_CTX_free(md); - md2 = NULL; - md = NULL; - OPENSSL_free(p_bytes); - OPENSSL_free(s_bytes); - p_bytes = NULL; - s_bytes = NULL; - - cp = out_buf + strlen(out_buf); - *cp++ = ascii_dollar[0]; - -# define b64_from_24bit(B2, B1, B0, N) \ - do { \ - unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \ - int i = (N); \ - while (i-- > 0) \ - { \ - *cp++ = cov_2char[w & 0x3f]; \ - w >>= 6; \ - } \ - } while (0) - - switch (magic[0]) { - case '5': - b64_from_24bit (buf[0], buf[10], buf[20], 4); - b64_from_24bit (buf[21], buf[1], buf[11], 4); - b64_from_24bit (buf[12], buf[22], buf[2], 4); - b64_from_24bit (buf[3], buf[13], buf[23], 4); - b64_from_24bit (buf[24], buf[4], buf[14], 4); - b64_from_24bit (buf[15], buf[25], buf[5], 4); - b64_from_24bit (buf[6], buf[16], buf[26], 4); - b64_from_24bit (buf[27], buf[7], buf[17], 4); - b64_from_24bit (buf[18], buf[28], buf[8], 4); - b64_from_24bit (buf[9], buf[19], buf[29], 4); - b64_from_24bit (0, buf[31], buf[30], 3); - break; - case '6': - b64_from_24bit (buf[0], buf[21], buf[42], 4); - b64_from_24bit (buf[22], buf[43], buf[1], 4); - b64_from_24bit (buf[44], buf[2], buf[23], 4); - b64_from_24bit (buf[3], buf[24], buf[45], 4); - b64_from_24bit (buf[25], buf[46], buf[4], 4); - b64_from_24bit (buf[47], buf[5], buf[26], 4); - b64_from_24bit (buf[6], buf[27], buf[48], 4); - b64_from_24bit (buf[28], buf[49], buf[7], 4); - b64_from_24bit (buf[50], buf[8], buf[29], 4); - b64_from_24bit (buf[9], buf[30], buf[51], 4); - b64_from_24bit (buf[31], buf[52], buf[10], 4); - b64_from_24bit (buf[53], buf[11], buf[32], 4); - b64_from_24bit (buf[12], buf[33], buf[54], 4); - b64_from_24bit (buf[34], buf[55], buf[13], 4); - b64_from_24bit (buf[56], buf[14], buf[35], 4); - b64_from_24bit (buf[15], buf[36], buf[57], 4); - b64_from_24bit (buf[37], buf[58], buf[16], 4); - b64_from_24bit (buf[59], buf[17], buf[38], 4); - b64_from_24bit (buf[18], buf[39], buf[60], 4); - b64_from_24bit (buf[40], buf[61], buf[19], 4); - b64_from_24bit (buf[62], buf[20], buf[41], 4); - b64_from_24bit (0, 0, buf[63], 2); - break; - default: - goto err; - } - *cp = '\0'; -#ifdef CHARSET_EBCDIC - ascii2ebcdic(out_buf, out_buf, strlen(out_buf)); -#endif - - return out_buf; - - err: - EVP_MD_CTX_free(md2); - EVP_MD_CTX_free(md); - OPENSSL_free(p_bytes); - OPENSSL_free(s_bytes); - OPENSSL_free(ascii_passwd); - return NULL; -} - -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, passwd_modes mode) -{ - char *hash = NULL; - - assert(salt_p != NULL); - assert(salt_malloc_p != NULL); - - /* first make sure we have a salt */ - if (!passed_salt) { - size_t saltlen = 0; - size_t i; - -#ifndef OPENSSL_NO_DES - if (mode == passwd_crypt) - saltlen = 2; -#endif /* !OPENSSL_NO_DES */ - - if (mode == passwd_md5 || mode == passwd_apr1 || mode == passwd_aixmd5) - saltlen = 8; - - if (mode == passwd_sha256 || mode == passwd_sha512) - saltlen = 16; - - assert(saltlen != 0); - - if (*salt_malloc_p == NULL) - *salt_p = *salt_malloc_p = app_malloc(saltlen + 1, "salt buffer"); - if (RAND_bytes((unsigned char *)*salt_p, saltlen) <= 0) - goto end; - - for (i = 0; i < saltlen; i++) - (*salt_p)[i] = cov_2char[(*salt_p)[i] & 0x3f]; /* 6 bits */ - (*salt_p)[i] = 0; -# ifdef CHARSET_EBCDIC +/* + * Copyright 2000-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <string.h> + +#include "apps.h" +#include "progs.h" + +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/rand.h> +#ifndef OPENSSL_NO_DES +# include <openssl/des.h> +#endif +#include <openssl/md5.h> +#include <openssl/sha.h> + +static unsigned const char cov_2char[64] = { + /* from crypto/des/fcrypt.c */ + 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, + 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, + 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, + 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, + 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A +}; + +static const char ascii_dollar[] = { 0x24, 0x00 }; + +typedef enum { + passwd_unset = 0, + passwd_crypt, + passwd_md5, + passwd_apr1, + passwd_sha256, + passwd_sha512, + passwd_aixmd5 +} passwd_modes; + +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, passwd_modes mode); + +typedef enum OPTION_choice { + OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_IN, + OPT_NOVERIFY, OPT_QUIET, OPT_TABLE, OPT_REVERSE, OPT_APR1, + OPT_1, OPT_5, OPT_6, OPT_CRYPT, OPT_AIXMD5, OPT_SALT, OPT_STDIN, + OPT_R_ENUM +} OPTION_CHOICE; + +const OPTIONS passwd_options[] = { + {"help", OPT_HELP, '-', "Display this summary"}, + {"in", OPT_IN, '<', "Read passwords from file"}, + {"noverify", OPT_NOVERIFY, '-', + "Never verify when reading password from terminal"}, + {"quiet", OPT_QUIET, '-', "No warnings"}, + {"table", OPT_TABLE, '-', "Format output as table"}, + {"reverse", OPT_REVERSE, '-', "Switch table columns"}, + {"salt", OPT_SALT, 's', "Use provided salt"}, + {"stdin", OPT_STDIN, '-', "Read passwords from stdin"}, + {"6", OPT_6, '-', "SHA512-based password algorithm"}, + {"5", OPT_5, '-', "SHA256-based password algorithm"}, + {"apr1", OPT_APR1, '-', "MD5-based password algorithm, Apache variant"}, + {"1", OPT_1, '-', "MD5-based password algorithm"}, + {"aixmd5", OPT_AIXMD5, '-', "AIX MD5-based password algorithm"}, +#ifndef OPENSSL_NO_DES + {"crypt", OPT_CRYPT, '-', "Standard Unix password algorithm (default)"}, +#endif + OPT_R_OPTIONS, + {NULL} +}; + +int passwd_main(int argc, char **argv) +{ + BIO *in = NULL; + char *infile = NULL, *salt = NULL, *passwd = NULL, **passwds = NULL; + char *salt_malloc = NULL, *passwd_malloc = NULL, *prog; + OPTION_CHOICE o; + int in_stdin = 0, pw_source_defined = 0; +#ifndef OPENSSL_NO_UI_CONSOLE + int in_noverify = 0; +#endif + int passed_salt = 0, quiet = 0, table = 0, reverse = 0; + int ret = 1; + passwd_modes mode = passwd_unset; + size_t passwd_malloc_size = 0; + size_t pw_maxlen = 256; /* arbitrary limit, should be enough for most + * passwords */ + + prog = opt_init(argc, argv, passwd_options); + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + case OPT_EOF: + case OPT_ERR: + opthelp: + BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); + goto end; + case OPT_HELP: + opt_help(passwd_options); + ret = 0; + goto end; + case OPT_IN: + if (pw_source_defined) + goto opthelp; + infile = opt_arg(); + pw_source_defined = 1; + break; + case OPT_NOVERIFY: +#ifndef OPENSSL_NO_UI_CONSOLE + in_noverify = 1; +#endif + break; + case OPT_QUIET: + quiet = 1; + break; + case OPT_TABLE: + table = 1; + break; + case OPT_REVERSE: + reverse = 1; + break; + case OPT_1: + if (mode != passwd_unset) + goto opthelp; + mode = passwd_md5; + break; + case OPT_5: + if (mode != passwd_unset) + goto opthelp; + mode = passwd_sha256; + break; + case OPT_6: + if (mode != passwd_unset) + goto opthelp; + mode = passwd_sha512; + break; + case OPT_APR1: + if (mode != passwd_unset) + goto opthelp; + mode = passwd_apr1; + break; + case OPT_AIXMD5: + if (mode != passwd_unset) + goto opthelp; + mode = passwd_aixmd5; + break; + case OPT_CRYPT: +#ifndef OPENSSL_NO_DES + if (mode != passwd_unset) + goto opthelp; + mode = passwd_crypt; +#endif + break; + case OPT_SALT: + passed_salt = 1; + salt = opt_arg(); + break; + case OPT_STDIN: + if (pw_source_defined) + goto opthelp; + in_stdin = 1; + pw_source_defined = 1; + break; + case OPT_R_CASES: + if (!opt_rand(o)) + goto end; + break; + } + } + argc = opt_num_rest(); + argv = opt_rest(); + + if (*argv != NULL) { + if (pw_source_defined) + goto opthelp; + pw_source_defined = 1; + passwds = argv; + } + + if (mode == passwd_unset) { + /* use default */ + mode = passwd_crypt; + } + +#ifdef OPENSSL_NO_DES + if (mode == passwd_crypt) + goto opthelp; +#endif + + if (infile != NULL && in_stdin) { + BIO_printf(bio_err, "%s: Can't combine -in and -stdin\n", prog); + goto end; + } + + if (infile != NULL || in_stdin) { + /* + * If in_stdin is true, we know that infile is NULL, and that + * bio_open_default() will give us back an alias for stdin. + */ + in = bio_open_default(infile, 'r', FORMAT_TEXT); + if (in == NULL) + goto end; + } + + if (mode == passwd_crypt) + pw_maxlen = 8; + + if (passwds == NULL) { + /* no passwords on the command line */ + + passwd_malloc_size = pw_maxlen + 2; + /* longer than necessary so that we can warn about truncation */ + passwd = passwd_malloc = + app_malloc(passwd_malloc_size, "password buffer"); + } + + if ((in == NULL) && (passwds == NULL)) { + /* + * we use the following method to make sure what + * in the 'else' section is always compiled, to + * avoid rot of not-frequently-used code. + */ + if (1) { +#ifndef OPENSSL_NO_UI_CONSOLE + /* build a null-terminated list */ + static char *passwds_static[2] = { NULL, NULL }; + + passwds = passwds_static; + if (in == NULL) { + if (EVP_read_pw_string + (passwd_malloc, passwd_malloc_size, "Password: ", + !(passed_salt || in_noverify)) != 0) + goto end; + } + passwds[0] = passwd_malloc; + } else { +#endif + BIO_printf(bio_err, "password required\n"); + goto end; + } + } + + if (in == NULL) { + assert(passwds != NULL); + assert(*passwds != NULL); + + do { /* loop over list of passwords */ + passwd = *passwds++; + if (!do_passwd(passed_salt, &salt, &salt_malloc, passwd, bio_out, + quiet, table, reverse, pw_maxlen, mode)) + goto end; + } while (*passwds != NULL); + } else { + /* in != NULL */ + int done; + + assert(passwd != NULL); + do { + int r = BIO_gets(in, passwd, pw_maxlen + 1); + if (r > 0) { + char *c = (strchr(passwd, '\n')); + if (c != NULL) { + *c = 0; /* truncate at newline */ + } else { + /* ignore rest of line */ + char trash[BUFSIZ]; + do + r = BIO_gets(in, trash, sizeof(trash)); + while ((r > 0) && (!strchr(trash, '\n'))); + } + + if (!do_passwd + (passed_salt, &salt, &salt_malloc, passwd, bio_out, quiet, + table, reverse, pw_maxlen, mode)) + goto end; + } + done = (r <= 0); + } while (!done); + } + ret = 0; + + end: +#if 0 + ERR_print_errors(bio_err); +#endif + OPENSSL_free(salt_malloc); + OPENSSL_free(passwd_malloc); + BIO_free(in); + return ret; +} + +/* + * MD5-based password algorithm (should probably be available as a library + * function; then the static buffer would not be acceptable). For magic + * string "1", this should be compatible to the MD5-based BSD password + * algorithm. For 'magic' string "apr1", this is compatible to the MD5-based + * Apache password algorithm. (Apparently, the Apache password algorithm is + * identical except that the 'magic' string was changed -- the laziest + * application of the NIH principle I've ever encountered.) + */ +static char *md5crypt(const char *passwd, const char *magic, const char *salt) +{ + /* "$apr1$..salt..$.......md5hash..........\0" */ + static char out_buf[6 + 9 + 24 + 2]; + unsigned char buf[MD5_DIGEST_LENGTH]; + char ascii_magic[5]; /* "apr1" plus '\0' */ + char ascii_salt[9]; /* Max 8 chars plus '\0' */ + char *ascii_passwd = NULL; + char *salt_out; + int n; + unsigned int i; + EVP_MD_CTX *md = NULL, *md2 = NULL; + size_t passwd_len, salt_len, magic_len; + + passwd_len = strlen(passwd); + + out_buf[0] = 0; + magic_len = strlen(magic); + OPENSSL_strlcpy(ascii_magic, magic, sizeof(ascii_magic)); +#ifdef CHARSET_EBCDIC + if ((magic[0] & 0x80) != 0) /* High bit is 1 in EBCDIC alnums */ + ebcdic2ascii(ascii_magic, ascii_magic, magic_len); +#endif + + /* The salt gets truncated to 8 chars */ + OPENSSL_strlcpy(ascii_salt, salt, sizeof(ascii_salt)); + salt_len = strlen(ascii_salt); +#ifdef CHARSET_EBCDIC + ebcdic2ascii(ascii_salt, ascii_salt, salt_len); +#endif + +#ifdef CHARSET_EBCDIC + ascii_passwd = OPENSSL_strdup(passwd); + if (ascii_passwd == NULL) + return NULL; + ebcdic2ascii(ascii_passwd, ascii_passwd, passwd_len); + passwd = ascii_passwd; +#endif + + if (magic_len > 0) { + OPENSSL_strlcat(out_buf, ascii_dollar, sizeof(out_buf)); + + if (magic_len > 4) /* assert it's "1" or "apr1" */ + goto err; + + OPENSSL_strlcat(out_buf, ascii_magic, sizeof(out_buf)); + OPENSSL_strlcat(out_buf, ascii_dollar, sizeof(out_buf)); + } + + OPENSSL_strlcat(out_buf, ascii_salt, sizeof(out_buf)); + + if (strlen(out_buf) > 6 + 8) /* assert "$apr1$..salt.." */ + goto err; + + salt_out = out_buf; + if (magic_len > 0) + salt_out += 2 + magic_len; + + if (salt_len > 8) + goto err; + + md = EVP_MD_CTX_new(); + if (md == NULL + || !EVP_DigestInit_ex(md, EVP_md5(), NULL) + || !EVP_DigestUpdate(md, passwd, passwd_len)) + goto err; + + if (magic_len > 0) + if (!EVP_DigestUpdate(md, ascii_dollar, 1) + || !EVP_DigestUpdate(md, ascii_magic, magic_len) + || !EVP_DigestUpdate(md, ascii_dollar, 1)) + goto err; + + if (!EVP_DigestUpdate(md, ascii_salt, salt_len)) + goto err; + + md2 = EVP_MD_CTX_new(); + if (md2 == NULL + || !EVP_DigestInit_ex(md2, EVP_md5(), NULL) + || !EVP_DigestUpdate(md2, passwd, passwd_len) + || !EVP_DigestUpdate(md2, ascii_salt, salt_len) + || !EVP_DigestUpdate(md2, passwd, passwd_len) + || !EVP_DigestFinal_ex(md2, buf, NULL)) + goto err; + + for (i = passwd_len; i > sizeof(buf); i -= sizeof(buf)) { + if (!EVP_DigestUpdate(md, buf, sizeof(buf))) + goto err; + } + if (!EVP_DigestUpdate(md, buf, i)) + goto err; + + n = passwd_len; + while (n) { + if (!EVP_DigestUpdate(md, (n & 1) ? "\0" : passwd, 1)) + goto err; + n >>= 1; + } + if (!EVP_DigestFinal_ex(md, buf, NULL)) + return NULL; + + for (i = 0; i < 1000; i++) { + if (!EVP_DigestInit_ex(md2, EVP_md5(), NULL)) + goto err; + if (!EVP_DigestUpdate(md2, + (i & 1) ? (unsigned const char *)passwd : buf, + (i & 1) ? passwd_len : sizeof(buf))) + goto err; + if (i % 3) { + if (!EVP_DigestUpdate(md2, ascii_salt, salt_len)) + goto err; + } + if (i % 7) { + if (!EVP_DigestUpdate(md2, passwd, passwd_len)) + goto err; + } + if (!EVP_DigestUpdate(md2, + (i & 1) ? buf : (unsigned const char *)passwd, + (i & 1) ? sizeof(buf) : passwd_len)) + goto err; + if (!EVP_DigestFinal_ex(md2, buf, NULL)) + goto err; + } + EVP_MD_CTX_free(md2); + EVP_MD_CTX_free(md); + md2 = NULL; + md = NULL; + + { + /* transform buf into output string */ + unsigned char buf_perm[sizeof(buf)]; + int dest, source; + char *output; + + /* silly output permutation */ + for (dest = 0, source = 0; dest < 14; + dest++, source = (source + 6) % 17) + buf_perm[dest] = buf[source]; + buf_perm[14] = buf[5]; + buf_perm[15] = buf[11]; +# ifndef PEDANTIC /* Unfortunately, this generates a "no + * effect" warning */ + assert(16 == sizeof(buf_perm)); +# endif + + output = salt_out + salt_len; + assert(output == out_buf + strlen(out_buf)); + + *output++ = ascii_dollar[0]; + + for (i = 0; i < 15; i += 3) { + *output++ = cov_2char[buf_perm[i + 2] & 0x3f]; + *output++ = cov_2char[((buf_perm[i + 1] & 0xf) << 2) | + (buf_perm[i + 2] >> 6)]; + *output++ = cov_2char[((buf_perm[i] & 3) << 4) | + (buf_perm[i + 1] >> 4)]; + *output++ = cov_2char[buf_perm[i] >> 2]; + } + assert(i == 15); + *output++ = cov_2char[buf_perm[i] & 0x3f]; + *output++ = cov_2char[buf_perm[i] >> 6]; + *output = 0; + assert(strlen(out_buf) < sizeof(out_buf)); +#ifdef CHARSET_EBCDIC + ascii2ebcdic(out_buf, out_buf, strlen(out_buf)); +#endif + } + + return out_buf; + + err: + OPENSSL_free(ascii_passwd); + EVP_MD_CTX_free(md2); + EVP_MD_CTX_free(md); + return NULL; +} + +/* + * SHA based password algorithm, describe by Ulrich Drepper here: + * https://www.akkadia.org/drepper/SHA-crypt.txt + * (note that it's in the public domain) + */ +static char *shacrypt(const char *passwd, const char *magic, const char *salt) +{ + /* Prefix for optional rounds specification. */ + static const char rounds_prefix[] = "rounds="; + /* Maximum salt string length. */ +# define SALT_LEN_MAX 16 + /* Default number of rounds if not explicitly specified. */ +# define ROUNDS_DEFAULT 5000 + /* Minimum number of rounds. */ +# define ROUNDS_MIN 1000 + /* Maximum number of rounds. */ +# define ROUNDS_MAX 999999999 + + /* "$6$rounds=<N>$......salt......$...shahash(up to 86 chars)...\0" */ + static char out_buf[3 + 17 + 17 + 86 + 1]; + unsigned char buf[SHA512_DIGEST_LENGTH]; + unsigned char temp_buf[SHA512_DIGEST_LENGTH]; + size_t buf_size = 0; + char ascii_magic[2]; + char ascii_salt[17]; /* Max 16 chars plus '\0' */ + char *ascii_passwd = NULL; + size_t n; + EVP_MD_CTX *md = NULL, *md2 = NULL; + const EVP_MD *sha = NULL; + size_t passwd_len, salt_len, magic_len; + unsigned int rounds = 5000; /* Default */ + char rounds_custom = 0; + char *p_bytes = NULL; + char *s_bytes = NULL; + char *cp = NULL; + + passwd_len = strlen(passwd); + magic_len = strlen(magic); + + /* assert it's "5" or "6" */ + if (magic_len != 1) + return NULL; + + switch (magic[0]) { + case '5': + sha = EVP_sha256(); + buf_size = 32; + break; + case '6': + sha = EVP_sha512(); + buf_size = 64; + break; + default: + return NULL; + } + + if (strncmp(salt, rounds_prefix, sizeof(rounds_prefix) - 1) == 0) { + const char *num = salt + sizeof(rounds_prefix) - 1; + char *endp; + unsigned long int srounds = strtoul (num, &endp, 10); + if (*endp == '$') { + salt = endp + 1; + if (srounds > ROUNDS_MAX) + rounds = ROUNDS_MAX; + else if (srounds < ROUNDS_MIN) + rounds = ROUNDS_MIN; + else + rounds = (unsigned int)srounds; + rounds_custom = 1; + } else { + return NULL; + } + } + + OPENSSL_strlcpy(ascii_magic, magic, sizeof(ascii_magic)); +#ifdef CHARSET_EBCDIC + if ((magic[0] & 0x80) != 0) /* High bit is 1 in EBCDIC alnums */ + ebcdic2ascii(ascii_magic, ascii_magic, magic_len); +#endif + + /* The salt gets truncated to 16 chars */ + OPENSSL_strlcpy(ascii_salt, salt, sizeof(ascii_salt)); + salt_len = strlen(ascii_salt); +#ifdef CHARSET_EBCDIC + ebcdic2ascii(ascii_salt, ascii_salt, salt_len); +#endif + +#ifdef CHARSET_EBCDIC + ascii_passwd = OPENSSL_strdup(passwd); + if (ascii_passwd == NULL) + return NULL; + ebcdic2ascii(ascii_passwd, ascii_passwd, passwd_len); + passwd = ascii_passwd; +#endif + + out_buf[0] = 0; + OPENSSL_strlcat(out_buf, ascii_dollar, sizeof(out_buf)); + OPENSSL_strlcat(out_buf, ascii_magic, sizeof(out_buf)); + OPENSSL_strlcat(out_buf, ascii_dollar, sizeof(out_buf)); + if (rounds_custom) { + char tmp_buf[80]; /* "rounds=999999999" */ + sprintf(tmp_buf, "rounds=%u", rounds); +#ifdef CHARSET_EBCDIC + /* In case we're really on a ASCII based platform and just pretend */ + if (tmp_buf[0] != 0x72) /* ASCII 'r' */ + ebcdic2ascii(tmp_buf, tmp_buf, strlen(tmp_buf)); +#endif + OPENSSL_strlcat(out_buf, tmp_buf, sizeof(out_buf)); + OPENSSL_strlcat(out_buf, ascii_dollar, sizeof(out_buf)); + } + OPENSSL_strlcat(out_buf, ascii_salt, sizeof(out_buf)); + + /* assert "$5$rounds=999999999$......salt......" */ + if (strlen(out_buf) > 3 + 17 * rounds_custom + salt_len ) + goto err; + + md = EVP_MD_CTX_new(); + if (md == NULL + || !EVP_DigestInit_ex(md, sha, NULL) + || !EVP_DigestUpdate(md, passwd, passwd_len) + || !EVP_DigestUpdate(md, ascii_salt, salt_len)) + goto err; + + md2 = EVP_MD_CTX_new(); + if (md2 == NULL + || !EVP_DigestInit_ex(md2, sha, NULL) + || !EVP_DigestUpdate(md2, passwd, passwd_len) + || !EVP_DigestUpdate(md2, ascii_salt, salt_len) + || !EVP_DigestUpdate(md2, passwd, passwd_len) + || !EVP_DigestFinal_ex(md2, buf, NULL)) + goto err; + + for (n = passwd_len; n > buf_size; n -= buf_size) { + if (!EVP_DigestUpdate(md, buf, buf_size)) + goto err; + } + if (!EVP_DigestUpdate(md, buf, n)) + goto err; + + n = passwd_len; + while (n) { + if (!EVP_DigestUpdate(md, + (n & 1) ? buf : (unsigned const char *)passwd, + (n & 1) ? buf_size : passwd_len)) + goto err; + n >>= 1; + } + if (!EVP_DigestFinal_ex(md, buf, NULL)) + return NULL; + + /* P sequence */ + if (!EVP_DigestInit_ex(md2, sha, NULL)) + goto err; + + for (n = passwd_len; n > 0; n--) + if (!EVP_DigestUpdate(md2, passwd, passwd_len)) + goto err; + + if (!EVP_DigestFinal_ex(md2, temp_buf, NULL)) + return NULL; + + if ((p_bytes = OPENSSL_zalloc(passwd_len)) == NULL) + goto err; + for (cp = p_bytes, n = passwd_len; n > buf_size; n -= buf_size, cp += buf_size) + memcpy(cp, temp_buf, buf_size); + memcpy(cp, temp_buf, n); + + /* S sequence */ + if (!EVP_DigestInit_ex(md2, sha, NULL)) + goto err; + + for (n = 16 + buf[0]; n > 0; n--) + if (!EVP_DigestUpdate(md2, ascii_salt, salt_len)) + goto err; + + if (!EVP_DigestFinal_ex(md2, temp_buf, NULL)) + return NULL; + + if ((s_bytes = OPENSSL_zalloc(salt_len)) == NULL) + goto err; + for (cp = s_bytes, n = salt_len; n > buf_size; n -= buf_size, cp += buf_size) + memcpy(cp, temp_buf, buf_size); + memcpy(cp, temp_buf, n); + + for (n = 0; n < rounds; n++) { + if (!EVP_DigestInit_ex(md2, sha, NULL)) + goto err; + if (!EVP_DigestUpdate(md2, + (n & 1) ? (unsigned const char *)p_bytes : buf, + (n & 1) ? passwd_len : buf_size)) + goto err; + if (n % 3) { + if (!EVP_DigestUpdate(md2, s_bytes, salt_len)) + goto err; + } + if (n % 7) { + if (!EVP_DigestUpdate(md2, p_bytes, passwd_len)) + goto err; + } + if (!EVP_DigestUpdate(md2, + (n & 1) ? buf : (unsigned const char *)p_bytes, + (n & 1) ? buf_size : passwd_len)) + goto err; + if (!EVP_DigestFinal_ex(md2, buf, NULL)) + goto err; + } + EVP_MD_CTX_free(md2); + EVP_MD_CTX_free(md); + md2 = NULL; + md = NULL; + OPENSSL_free(p_bytes); + OPENSSL_free(s_bytes); + p_bytes = NULL; + s_bytes = NULL; + + cp = out_buf + strlen(out_buf); + *cp++ = ascii_dollar[0]; + +# define b64_from_24bit(B2, B1, B0, N) \ + do { \ + unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \ + int i = (N); \ + while (i-- > 0) \ + { \ + *cp++ = cov_2char[w & 0x3f]; \ + w >>= 6; \ + } \ + } while (0) + + switch (magic[0]) { + case '5': + b64_from_24bit (buf[0], buf[10], buf[20], 4); + b64_from_24bit (buf[21], buf[1], buf[11], 4); + b64_from_24bit (buf[12], buf[22], buf[2], 4); + b64_from_24bit (buf[3], buf[13], buf[23], 4); + b64_from_24bit (buf[24], buf[4], buf[14], 4); + b64_from_24bit (buf[15], buf[25], buf[5], 4); + b64_from_24bit (buf[6], buf[16], buf[26], 4); + b64_from_24bit (buf[27], buf[7], buf[17], 4); + b64_from_24bit (buf[18], buf[28], buf[8], 4); + b64_from_24bit (buf[9], buf[19], buf[29], 4); + b64_from_24bit (0, buf[31], buf[30], 3); + break; + case '6': + b64_from_24bit (buf[0], buf[21], buf[42], 4); + b64_from_24bit (buf[22], buf[43], buf[1], 4); + b64_from_24bit (buf[44], buf[2], buf[23], 4); + b64_from_24bit (buf[3], buf[24], buf[45], 4); + b64_from_24bit (buf[25], buf[46], buf[4], 4); + b64_from_24bit (buf[47], buf[5], buf[26], 4); + b64_from_24bit (buf[6], buf[27], buf[48], 4); + b64_from_24bit (buf[28], buf[49], buf[7], 4); + b64_from_24bit (buf[50], buf[8], buf[29], 4); + b64_from_24bit (buf[9], buf[30], buf[51], 4); + b64_from_24bit (buf[31], buf[52], buf[10], 4); + b64_from_24bit (buf[53], buf[11], buf[32], 4); + b64_from_24bit (buf[12], buf[33], buf[54], 4); + b64_from_24bit (buf[34], buf[55], buf[13], 4); + b64_from_24bit (buf[56], buf[14], buf[35], 4); + b64_from_24bit (buf[15], buf[36], buf[57], 4); + b64_from_24bit (buf[37], buf[58], buf[16], 4); + b64_from_24bit (buf[59], buf[17], buf[38], 4); + b64_from_24bit (buf[18], buf[39], buf[60], 4); + b64_from_24bit (buf[40], buf[61], buf[19], 4); + b64_from_24bit (buf[62], buf[20], buf[41], 4); + b64_from_24bit (0, 0, buf[63], 2); + break; + default: + goto err; + } + *cp = '\0'; +#ifdef CHARSET_EBCDIC + ascii2ebcdic(out_buf, out_buf, strlen(out_buf)); +#endif + + return out_buf; + + err: + EVP_MD_CTX_free(md2); + EVP_MD_CTX_free(md); + OPENSSL_free(p_bytes); + OPENSSL_free(s_bytes); + OPENSSL_free(ascii_passwd); + return NULL; +} + +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, passwd_modes mode) +{ + char *hash = NULL; + + assert(salt_p != NULL); + assert(salt_malloc_p != NULL); + + /* first make sure we have a salt */ + if (!passed_salt) { + size_t saltlen = 0; + size_t i; + +#ifndef OPENSSL_NO_DES + if (mode == passwd_crypt) + saltlen = 2; +#endif /* !OPENSSL_NO_DES */ + + if (mode == passwd_md5 || mode == passwd_apr1 || mode == passwd_aixmd5) + saltlen = 8; + + if (mode == passwd_sha256 || mode == passwd_sha512) + saltlen = 16; + + assert(saltlen != 0); + + if (*salt_malloc_p == NULL) + *salt_p = *salt_malloc_p = app_malloc(saltlen + 1, "salt buffer"); + if (RAND_bytes((unsigned char *)*salt_p, saltlen) <= 0) + goto end; + + for (i = 0; i < saltlen; i++) + (*salt_p)[i] = cov_2char[(*salt_p)[i] & 0x3f]; /* 6 bits */ + (*salt_p)[i] = 0; +# ifdef CHARSET_EBCDIC /* The password encryption function will convert back to ASCII */ - ascii2ebcdic(*salt_p, *salt_p, saltlen); -# endif - } - - assert(*salt_p != NULL); - - /* truncate password if necessary */ - if ((strlen(passwd) > pw_maxlen)) { - if (!quiet) - /* - * XXX: really we should know how to print a size_t, not cast it - */ - BIO_printf(bio_err, - "Warning: truncating password to %u characters\n", - (unsigned)pw_maxlen); - passwd[pw_maxlen] = 0; - } - assert(strlen(passwd) <= pw_maxlen); - - /* now compute password hash */ -#ifndef OPENSSL_NO_DES - if (mode == passwd_crypt) - hash = DES_crypt(passwd, *salt_p); -#endif - if (mode == passwd_md5 || mode == passwd_apr1) - hash = md5crypt(passwd, (mode == passwd_md5 ? "1" : "apr1"), *salt_p); - if (mode == passwd_aixmd5) - hash = md5crypt(passwd, "", *salt_p); - if (mode == passwd_sha256 || mode == passwd_sha512) - hash = shacrypt(passwd, (mode == passwd_sha256 ? "5" : "6"), *salt_p); - assert(hash != NULL); - - if (table && !reverse) - BIO_printf(out, "%s\t%s\n", passwd, hash); - else if (table && reverse) - BIO_printf(out, "%s\t%s\n", hash, passwd); - else - BIO_printf(out, "%s\n", hash); - return 1; - - end: - return 0; -} + ascii2ebcdic(*salt_p, *salt_p, saltlen); +# endif + } + + assert(*salt_p != NULL); + + /* truncate password if necessary */ + if ((strlen(passwd) > pw_maxlen)) { + if (!quiet) + /* + * XXX: really we should know how to print a size_t, not cast it + */ + BIO_printf(bio_err, + "Warning: truncating password to %u characters\n", + (unsigned)pw_maxlen); + passwd[pw_maxlen] = 0; + } + assert(strlen(passwd) <= pw_maxlen); + + /* now compute password hash */ +#ifndef OPENSSL_NO_DES + if (mode == passwd_crypt) + hash = DES_crypt(passwd, *salt_p); +#endif + if (mode == passwd_md5 || mode == passwd_apr1) + hash = md5crypt(passwd, (mode == passwd_md5 ? "1" : "apr1"), *salt_p); + if (mode == passwd_aixmd5) + hash = md5crypt(passwd, "", *salt_p); + if (mode == passwd_sha256 || mode == passwd_sha512) + hash = shacrypt(passwd, (mode == passwd_sha256 ? "5" : "6"), *salt_p); + assert(hash != NULL); + + if (table && !reverse) + BIO_printf(out, "%s\t%s\n", passwd, hash); + else if (table && reverse) + BIO_printf(out, "%s\t%s\n", hash, passwd); + else + BIO_printf(out, "%s\n", hash); + return 1; + + end: + return 0; +} |