int PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
                      const unsigned char *salt, int saltlen, int iter,
                      const EVP_MD *digest, int keylen, unsigned char *out)
{
    const char *empty = "";
    unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4];
    int cplen, j, k, tkeylen, mdlen;
    unsigned long i = 1;
    HMAC_CTX *hctx_tpl = NULL, *hctx = NULL;
    mdlen = EVP_MD_size(digest);
    if (mdlen < 0)
        return 0;
    hctx_tpl = HMAC_CTX_new();
    if (hctx_tpl == NULL)
        return 0;
    p = out;
    tkeylen = keylen;
    if (pass == NULL) {
        pass = empty;
        passlen = 0;
    } else if (passlen == -1) {
        passlen = strlen(pass);
    }
    if (!HMAC_Init_ex(hctx_tpl, pass, passlen, digest, NULL)) {
        HMAC_CTX_free(hctx_tpl);
        return 0;
    }
    hctx = HMAC_CTX_new();
    if (hctx == NULL) {
        HMAC_CTX_free(hctx_tpl);
        return 0;
    }
    while (tkeylen) {
        if (tkeylen > mdlen)
            cplen = mdlen;
        else
            cplen = tkeylen;
        itmp[0] = (unsigned char)((i >> 24) & 0xff);
        itmp[1] = (unsigned char)((i >> 16) & 0xff);
        itmp[2] = (unsigned char)((i >> 8) & 0xff);
        itmp[3] = (unsigned char)(i & 0xff);
        if (!HMAC_CTX_copy(hctx, hctx_tpl)) {
            HMAC_CTX_free(hctx);
            HMAC_CTX_free(hctx_tpl);
            return 0;
        }
        if (!HMAC_Update(hctx, salt, saltlen)
            || !HMAC_Update(hctx, itmp, 4)
            || !HMAC_Final(hctx, digtmp, NULL)) {
            HMAC_CTX_free(hctx);
            HMAC_CTX_free(hctx_tpl);
            return 0;
        }
        memcpy(p, digtmp, cplen);
        for (j = 1; j < iter; j++) {
            if (!HMAC_CTX_copy(hctx, hctx_tpl)) {
                HMAC_CTX_free(hctx);
                HMAC_CTX_free(hctx_tpl);
                return 0;
            }
            if (!HMAC_Update(hctx, digtmp, mdlen)
                || !HMAC_Final(hctx, digtmp, NULL)) {
                HMAC_CTX_free(hctx);
                HMAC_CTX_free(hctx_tpl);
                return 0;
            }
            for (k = 0; k < cplen; k++)
                p[k] ^= digtmp[k];
        }
        tkeylen -= cplen;
        i++;
        p += cplen;
    }
    HMAC_CTX_free(hctx);
    HMAC_CTX_free(hctx_tpl);
# ifdef OPENSSL_DEBUG_PKCS5V2
    fprintf(stderr, "Password:\n");
    h__dump(pass, passlen);
    fprintf(stderr, "Salt:\n");
    h__dump(salt, saltlen);
    fprintf(stderr, "Iteration count %d\n", iter);
    fprintf(stderr, "Key:\n");
    h__dump(out, keylen);
# endif
    return 1;
}
['static int pkcs12_gen_mac(PKCS12 *p12, const char *pass, int passlen,\n                          unsigned char *mac, unsigned int *maclen,\n                          int (*pkcs12_key_gen)(const char *pass, int passlen,\n                                                unsigned char *salt, int slen,\n                                                int id, int iter, int n,\n                                                unsigned char *out,\n                                                const EVP_MD *md_type))\n{\n    const EVP_MD *md_type;\n    HMAC_CTX *hmac = NULL;\n    unsigned char key[EVP_MAX_MD_SIZE], *salt;\n    int saltlen, iter;\n    int md_size = 0;\n    int md_type_nid;\n    const X509_ALGOR *macalg;\n    const ASN1_OBJECT *macoid;\n    if (pkcs12_key_gen == NULL)\n        pkcs12_key_gen = PKCS12_key_gen_utf8;\n    if (!PKCS7_type_is_data(p12->authsafes)) {\n        PKCS12err(PKCS12_F_PKCS12_GEN_MAC, PKCS12_R_CONTENT_TYPE_NOT_DATA);\n        return 0;\n    }\n    salt = p12->mac->salt->data;\n    saltlen = p12->mac->salt->length;\n    if (!p12->mac->iter)\n        iter = 1;\n    else\n        iter = ASN1_INTEGER_get(p12->mac->iter);\n    X509_SIG_get0(p12->mac->dinfo, &macalg, NULL);\n    X509_ALGOR_get0(&macoid, NULL, NULL, macalg);\n    if ((md_type = EVP_get_digestbyobj(macoid)) == NULL) {\n        PKCS12err(PKCS12_F_PKCS12_GEN_MAC, PKCS12_R_UNKNOWN_DIGEST_ALGORITHM);\n        return 0;\n    }\n    md_size = EVP_MD_size(md_type);\n    md_type_nid = EVP_MD_type(md_type);\n    if (md_size < 0)\n        return 0;\n    if ((md_type_nid == NID_id_GostR3411_94\n         || md_type_nid == NID_id_GostR3411_2012_256\n         || md_type_nid == NID_id_GostR3411_2012_512)\n        && !getenv("LEGACY_GOST_PKCS12")) {\n        md_size = TK26_MAC_KEY_LEN;\n        if (!pkcs12_gen_gost_mac_key(pass, passlen, salt, saltlen, iter,\n                                     md_size, key, md_type)) {\n            PKCS12err(PKCS12_F_PKCS12_GEN_MAC, PKCS12_R_KEY_GEN_ERROR);\n            return 0;\n        }\n    } else\n        if (!(*pkcs12_key_gen)(pass, passlen, salt, saltlen, PKCS12_MAC_ID,\n                               iter, md_size, key, md_type)) {\n        PKCS12err(PKCS12_F_PKCS12_GEN_MAC, PKCS12_R_KEY_GEN_ERROR);\n        return 0;\n    }\n    hmac = HMAC_CTX_new();\n    if (!HMAC_Init_ex(hmac, key, md_size, md_type, NULL)\n        || !HMAC_Update(hmac, p12->authsafes->d.data->data,\n                        p12->authsafes->d.data->length)\n        || !HMAC_Final(hmac, mac, maclen)) {\n        HMAC_CTX_free(hmac);\n        return 0;\n    }\n    HMAC_CTX_free(hmac);\n    return 1;\n}', 'static int pkcs12_gen_gost_mac_key(const char *pass, int passlen,\n                                   const unsigned char *salt, int saltlen,\n                                   int iter, int keylen, unsigned char *key,\n                                   const EVP_MD *digest)\n{\n    unsigned char out[96];\n    if (keylen != TK26_MAC_KEY_LEN) {\n        return 0;\n    }\n    if (!PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter,\n                           digest, sizeof(out), out)) {\n        return 0;\n    }\n    memcpy(key, out + sizeof(out) - TK26_MAC_KEY_LEN, TK26_MAC_KEY_LEN);\n    OPENSSL_cleanse(out, sizeof(out));\n    return 1;\n}', 'int PKCS5_PBKDF2_HMAC(const char *pass, int passlen,\n                      const unsigned char *salt, int saltlen, int iter,\n                      const EVP_MD *digest, int keylen, unsigned char *out)\n{\n    const char *empty = "";\n    unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4];\n    int cplen, j, k, tkeylen, mdlen;\n    unsigned long i = 1;\n    HMAC_CTX *hctx_tpl = NULL, *hctx = NULL;\n    mdlen = EVP_MD_size(digest);\n    if (mdlen < 0)\n        return 0;\n    hctx_tpl = HMAC_CTX_new();\n    if (hctx_tpl == NULL)\n        return 0;\n    p = out;\n    tkeylen = keylen;\n    if (pass == NULL) {\n        pass = empty;\n        passlen = 0;\n    } else if (passlen == -1) {\n        passlen = strlen(pass);\n    }\n    if (!HMAC_Init_ex(hctx_tpl, pass, passlen, digest, NULL)) {\n        HMAC_CTX_free(hctx_tpl);\n        return 0;\n    }\n    hctx = HMAC_CTX_new();\n    if (hctx == NULL) {\n        HMAC_CTX_free(hctx_tpl);\n        return 0;\n    }\n    while (tkeylen) {\n        if (tkeylen > mdlen)\n            cplen = mdlen;\n        else\n            cplen = tkeylen;\n        itmp[0] = (unsigned char)((i >> 24) & 0xff);\n        itmp[1] = (unsigned char)((i >> 16) & 0xff);\n        itmp[2] = (unsigned char)((i >> 8) & 0xff);\n        itmp[3] = (unsigned char)(i & 0xff);\n        if (!HMAC_CTX_copy(hctx, hctx_tpl)) {\n            HMAC_CTX_free(hctx);\n            HMAC_CTX_free(hctx_tpl);\n            return 0;\n        }\n        if (!HMAC_Update(hctx, salt, saltlen)\n            || !HMAC_Update(hctx, itmp, 4)\n            || !HMAC_Final(hctx, digtmp, NULL)) {\n            HMAC_CTX_free(hctx);\n            HMAC_CTX_free(hctx_tpl);\n            return 0;\n        }\n        memcpy(p, digtmp, cplen);\n        for (j = 1; j < iter; j++) {\n            if (!HMAC_CTX_copy(hctx, hctx_tpl)) {\n                HMAC_CTX_free(hctx);\n                HMAC_CTX_free(hctx_tpl);\n                return 0;\n            }\n            if (!HMAC_Update(hctx, digtmp, mdlen)\n                || !HMAC_Final(hctx, digtmp, NULL)) {\n                HMAC_CTX_free(hctx);\n                HMAC_CTX_free(hctx_tpl);\n                return 0;\n            }\n            for (k = 0; k < cplen; k++)\n                p[k] ^= digtmp[k];\n        }\n        tkeylen -= cplen;\n        i++;\n        p += cplen;\n    }\n    HMAC_CTX_free(hctx);\n    HMAC_CTX_free(hctx_tpl);\n# ifdef OPENSSL_DEBUG_PKCS5V2\n    fprintf(stderr, "Password:\\n");\n    h__dump(pass, passlen);\n    fprintf(stderr, "Salt:\\n");\n    h__dump(salt, saltlen);\n    fprintf(stderr, "Iteration count %d\\n", iter);\n    fprintf(stderr, "Key:\\n");\n    h__dump(out, keylen);\n# endif\n    return 1;\n}']