Blame apps/passwd.c

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