static char *shacrypt(const char *passwd, const char *magic, const char *salt)
{
    static const char rounds_prefix[] = "rounds=";
# define SALT_LEN_MAX 16
# define ROUNDS_DEFAULT 5000
# define ROUNDS_MIN 1000
# define ROUNDS_MAX 999999999
    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];
    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;
    char rounds_custom = 0;
    char *p_bytes = NULL;
    char *s_bytes = NULL;
    char *cp = NULL;
    passwd_len = strlen(passwd);
    magic_len = strlen(magic);
    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)
        ebcdic2ascii(ascii_magic, ascii_magic, magic_len);
#endif
    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];
        sprintf(tmp_buf, "rounds=%u", rounds);
#ifdef CHARSET_EBCDIC
        if (tmp_buf[0] != 0x72)
            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));
    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;
    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);
    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,\n                     char *passwd, BIO *out, int quiet, int table,\n                     int reverse, size_t pw_maxlen, passwd_modes mode)\n{\n    char *hash = NULL;\n    assert(salt_p != NULL);\n    assert(salt_malloc_p != NULL);\n    if (!passed_salt) {\n        size_t saltlen = 0;\n        size_t i;\n#ifndef OPENSSL_NO_DES\n        if (mode == passwd_crypt)\n            saltlen = 2;\n#endif\n        if (mode == passwd_md5 || mode == passwd_apr1 || mode == passwd_aixmd5)\n            saltlen = 8;\n        if (mode == passwd_sha256 || mode == passwd_sha512)\n            saltlen = 16;\n        assert(saltlen != 0);\n        if (*salt_malloc_p == NULL)\n            *salt_p = *salt_malloc_p = app_malloc(saltlen + 1, "salt buffer");\n        if (RAND_bytes((unsigned char *)*salt_p, saltlen) <= 0)\n            goto end;\n        for (i = 0; i < saltlen; i++)\n            (*salt_p)[i] = cov_2char[(*salt_p)[i] & 0x3f];\n        (*salt_p)[i] = 0;\n# ifdef CHARSET_EBCDIC\n        ascii2ebcdic(*salt_p, *salt_p, saltlen);\n# endif\n    }\n    assert(*salt_p != NULL);\n    if ((strlen(passwd) > pw_maxlen)) {\n        if (!quiet)\n            BIO_printf(bio_err,\n                       "Warning: truncating password to %u characters\\n",\n                       (unsigned)pw_maxlen);\n        passwd[pw_maxlen] = 0;\n    }\n    assert(strlen(passwd) <= pw_maxlen);\n#ifndef OPENSSL_NO_DES\n    if (mode == passwd_crypt)\n        hash = DES_crypt(passwd, *salt_p);\n#endif\n    if (mode == passwd_md5 || mode == passwd_apr1)\n        hash = md5crypt(passwd, (mode == passwd_md5 ? "1" : "apr1"), *salt_p);\n    if (mode == passwd_aixmd5)\n        hash = md5crypt(passwd, "", *salt_p);\n    if (mode == passwd_sha256 || mode == passwd_sha512)\n        hash = shacrypt(passwd, (mode == passwd_sha256 ? "5" : "6"), *salt_p);\n    assert(hash != NULL);\n    if (table && !reverse)\n        BIO_printf(out, "%s\\t%s\\n", passwd, hash);\n    else if (table && reverse)\n        BIO_printf(out, "%s\\t%s\\n", hash, passwd);\n    else\n        BIO_printf(out, "%s\\n", hash);\n    return 1;\n end:\n    return 0;\n}', 'static char *shacrypt(const char *passwd, const char *magic, const char *salt)\n{\n    static const char rounds_prefix[] = "rounds=";\n# define SALT_LEN_MAX 16\n# define ROUNDS_DEFAULT 5000\n# define ROUNDS_MIN 1000\n# define ROUNDS_MAX 999999999\n    static char out_buf[3 + 17 + 17 + 86 + 1];\n    unsigned char buf[SHA512_DIGEST_LENGTH];\n    unsigned char temp_buf[SHA512_DIGEST_LENGTH];\n    size_t buf_size = 0;\n    char ascii_magic[2];\n    char ascii_salt[17];\n    char *ascii_passwd = NULL;\n    size_t n;\n    EVP_MD_CTX *md = NULL, *md2 = NULL;\n    const EVP_MD *sha = NULL;\n    size_t passwd_len, salt_len, magic_len;\n    unsigned int rounds = 5000;\n    char rounds_custom = 0;\n    char *p_bytes = NULL;\n    char *s_bytes = NULL;\n    char *cp = NULL;\n    passwd_len = strlen(passwd);\n    magic_len = strlen(magic);\n    if (magic_len != 1)\n        return NULL;\n    switch (magic[0]) {\n    case \'5\':\n        sha = EVP_sha256();\n        buf_size = 32;\n        break;\n    case \'6\':\n        sha = EVP_sha512();\n        buf_size = 64;\n        break;\n    default:\n        return NULL;\n    }\n    if (strncmp(salt, rounds_prefix, sizeof(rounds_prefix) - 1) == 0) {\n        const char *num = salt + sizeof(rounds_prefix) - 1;\n        char *endp;\n        unsigned long int srounds = strtoul (num, &endp, 10);\n        if (*endp == \'$\') {\n            salt = endp + 1;\n            if (srounds > ROUNDS_MAX)\n                rounds = ROUNDS_MAX;\n            else if (srounds < ROUNDS_MIN)\n                rounds = ROUNDS_MIN;\n            else\n                rounds = (unsigned int)srounds;\n            rounds_custom = 1;\n        } else {\n            return NULL;\n        }\n    }\n    OPENSSL_strlcpy(ascii_magic, magic, sizeof(ascii_magic));\n#ifdef CHARSET_EBCDIC\n    if ((magic[0] & 0x80) != 0)\n        ebcdic2ascii(ascii_magic, ascii_magic, magic_len);\n#endif\n    OPENSSL_strlcpy(ascii_salt, salt, sizeof(ascii_salt));\n    salt_len = strlen(ascii_salt);\n#ifdef CHARSET_EBCDIC\n    ebcdic2ascii(ascii_salt, ascii_salt, salt_len);\n#endif\n#ifdef CHARSET_EBCDIC\n    ascii_passwd = OPENSSL_strdup(passwd);\n    if (ascii_passwd == NULL)\n        return NULL;\n    ebcdic2ascii(ascii_passwd, ascii_passwd, passwd_len);\n    passwd = ascii_passwd;\n#endif\n    out_buf[0] = 0;\n    OPENSSL_strlcat(out_buf, ascii_dollar, sizeof(out_buf));\n    OPENSSL_strlcat(out_buf, ascii_magic, sizeof(out_buf));\n    OPENSSL_strlcat(out_buf, ascii_dollar, sizeof(out_buf));\n    if (rounds_custom) {\n        char tmp_buf[80];\n        sprintf(tmp_buf, "rounds=%u", rounds);\n#ifdef CHARSET_EBCDIC\n        if (tmp_buf[0] != 0x72)\n            ebcdic2ascii(tmp_buf, tmp_buf, strlen(tmp_buf));\n#endif\n        OPENSSL_strlcat(out_buf, tmp_buf, sizeof(out_buf));\n        OPENSSL_strlcat(out_buf, ascii_dollar, sizeof(out_buf));\n    }\n    OPENSSL_strlcat(out_buf, ascii_salt, sizeof(out_buf));\n    if (strlen(out_buf) > 3 + 17 * rounds_custom + salt_len )\n        goto err;\n    md = EVP_MD_CTX_new();\n    if (md == NULL\n        || !EVP_DigestInit_ex(md, sha, NULL)\n        || !EVP_DigestUpdate(md, passwd, passwd_len)\n        || !EVP_DigestUpdate(md, ascii_salt, salt_len))\n        goto err;\n    md2 = EVP_MD_CTX_new();\n    if (md2 == NULL\n        || !EVP_DigestInit_ex(md2, sha, NULL)\n        || !EVP_DigestUpdate(md2, passwd, passwd_len)\n        || !EVP_DigestUpdate(md2, ascii_salt, salt_len)\n        || !EVP_DigestUpdate(md2, passwd, passwd_len)\n        || !EVP_DigestFinal_ex(md2, buf, NULL))\n        goto err;\n    for (n = passwd_len; n > buf_size; n -= buf_size) {\n        if (!EVP_DigestUpdate(md, buf, buf_size))\n            goto err;\n    }\n    if (!EVP_DigestUpdate(md, buf, n))\n        goto err;\n    n = passwd_len;\n    while (n) {\n        if (!EVP_DigestUpdate(md,\n                              (n & 1) ? buf : (unsigned const char *)passwd,\n                              (n & 1) ? buf_size : passwd_len))\n            goto err;\n        n >>= 1;\n    }\n    if (!EVP_DigestFinal_ex(md, buf, NULL))\n        return NULL;\n    if (!EVP_DigestInit_ex(md2, sha, NULL))\n        goto err;\n    for (n = passwd_len; n > 0; n--)\n        if (!EVP_DigestUpdate(md2, passwd, passwd_len))\n            goto err;\n    if (!EVP_DigestFinal_ex(md2, temp_buf, NULL))\n        return NULL;\n    if ((p_bytes = OPENSSL_zalloc(passwd_len)) == NULL)\n        goto err;\n    for (cp = p_bytes, n = passwd_len; n > buf_size; n -= buf_size, cp += buf_size)\n        memcpy(cp, temp_buf, buf_size);\n    memcpy(cp, temp_buf, n);\n    if (!EVP_DigestInit_ex(md2, sha, NULL))\n        goto err;\n    for (n = 16 + buf[0]; n > 0; n--)\n        if (!EVP_DigestUpdate(md2, ascii_salt, salt_len))\n            goto err;\n    if (!EVP_DigestFinal_ex(md2, temp_buf, NULL))\n        return NULL;\n    if ((s_bytes = OPENSSL_zalloc(salt_len)) == NULL)\n        goto err;\n    for (cp = s_bytes, n = salt_len; n > buf_size; n -= buf_size, cp += buf_size)\n        memcpy(cp, temp_buf, buf_size);\n    memcpy(cp, temp_buf, n);\n    for (n = 0; n < rounds; n++) {\n        if (!EVP_DigestInit_ex(md2, sha, NULL))\n            goto err;\n        if (!EVP_DigestUpdate(md2,\n                              (n & 1) ? (unsigned const char *)p_bytes : buf,\n                              (n & 1) ? passwd_len : buf_size))\n            goto err;\n        if (n % 3) {\n            if (!EVP_DigestUpdate(md2, s_bytes, salt_len))\n                goto err;\n        }\n        if (n % 7) {\n            if (!EVP_DigestUpdate(md2, p_bytes, passwd_len))\n                goto err;\n        }\n        if (!EVP_DigestUpdate(md2,\n                              (n & 1) ? buf : (unsigned const char *)p_bytes,\n                              (n & 1) ? buf_size : passwd_len))\n                goto err;\n        if (!EVP_DigestFinal_ex(md2, buf, NULL))\n                goto err;\n    }\n    EVP_MD_CTX_free(md2);\n    EVP_MD_CTX_free(md);\n    md2 = NULL;\n    md = NULL;\n    OPENSSL_free(p_bytes);\n    OPENSSL_free(s_bytes);\n    p_bytes = NULL;\n    s_bytes = NULL;\n    cp = out_buf + strlen(out_buf);\n    *cp++ = ascii_dollar[0];\n# define b64_from_24bit(B2, B1, B0, N)                                   \\\n    do {                                                                \\\n        unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0);             \\\n        int i = (N);                                                    \\\n        while (i-- > 0)                                                 \\\n            {                                                           \\\n                *cp++ = cov_2char[w & 0x3f];                            \\\n                w >>= 6;                                                \\\n            }                                                           \\\n    } while (0)\n    switch (magic[0]) {\n    case \'5\':\n        b64_from_24bit (buf[0], buf[10], buf[20], 4);\n        b64_from_24bit (buf[21], buf[1], buf[11], 4);\n        b64_from_24bit (buf[12], buf[22], buf[2], 4);\n        b64_from_24bit (buf[3], buf[13], buf[23], 4);\n        b64_from_24bit (buf[24], buf[4], buf[14], 4);\n        b64_from_24bit (buf[15], buf[25], buf[5], 4);\n        b64_from_24bit (buf[6], buf[16], buf[26], 4);\n        b64_from_24bit (buf[27], buf[7], buf[17], 4);\n        b64_from_24bit (buf[18], buf[28], buf[8], 4);\n        b64_from_24bit (buf[9], buf[19], buf[29], 4);\n        b64_from_24bit (0, buf[31], buf[30], 3);\n        break;\n    case \'6\':\n        b64_from_24bit (buf[0], buf[21], buf[42], 4);\n        b64_from_24bit (buf[22], buf[43], buf[1], 4);\n        b64_from_24bit (buf[44], buf[2], buf[23], 4);\n        b64_from_24bit (buf[3], buf[24], buf[45], 4);\n        b64_from_24bit (buf[25], buf[46], buf[4], 4);\n        b64_from_24bit (buf[47], buf[5], buf[26], 4);\n        b64_from_24bit (buf[6], buf[27], buf[48], 4);\n        b64_from_24bit (buf[28], buf[49], buf[7], 4);\n        b64_from_24bit (buf[50], buf[8], buf[29], 4);\n        b64_from_24bit (buf[9], buf[30], buf[51], 4);\n        b64_from_24bit (buf[31], buf[52], buf[10], 4);\n        b64_from_24bit (buf[53], buf[11], buf[32], 4);\n        b64_from_24bit (buf[12], buf[33], buf[54], 4);\n        b64_from_24bit (buf[34], buf[55], buf[13], 4);\n        b64_from_24bit (buf[56], buf[14], buf[35], 4);\n        b64_from_24bit (buf[15], buf[36], buf[57], 4);\n        b64_from_24bit (buf[37], buf[58], buf[16], 4);\n        b64_from_24bit (buf[59], buf[17], buf[38], 4);\n        b64_from_24bit (buf[18], buf[39], buf[60], 4);\n        b64_from_24bit (buf[40], buf[61], buf[19], 4);\n        b64_from_24bit (buf[62], buf[20], buf[41], 4);\n        b64_from_24bit (0, 0, buf[63], 2);\n        break;\n    default:\n        goto err;\n    }\n    *cp = \'\\0\';\n#ifdef CHARSET_EBCDIC\n    ascii2ebcdic(out_buf, out_buf, strlen(out_buf));\n#endif\n    return out_buf;\n err:\n    EVP_MD_CTX_free(md2);\n    EVP_MD_CTX_free(md);\n    OPENSSL_free(p_bytes);\n    OPENSSL_free(s_bytes);\n    OPENSSL_free(ascii_passwd);\n    return NULL;\n}']