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 = ""; int rv = 1; EVP_KDF_CTX *kctx; /* Keep documented behaviour. */ if (pass == NULL) { pass = empty; passlen = 0; } else if (passlen == -1) { passlen = strlen(pass); } if (salt == NULL && saltlen == 0) salt = (unsigned char *)empty; kctx = EVP_KDF_CTX_new_id(EVP_KDF_PBKDF2); if (kctx == NULL) return 0; if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_PASS, pass, (size_t)passlen) != 1 || EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SALT, salt, (size_t)saltlen) != 1 || EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_ITER, iter) != 1 || EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_MD, digest) != 1 || EVP_KDF_derive(kctx, out, keylen) != 1) rv = 0; EVP_KDF_CTX_free(kctx); # 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 rv; }
int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt, int saltlen, int id, int iter, int n, unsigned char *out, const EVP_MD *md_type) { unsigned char *B = NULL, *D = NULL, *I = NULL, *p = NULL, *Ai = NULL; int Slen, Plen, Ilen, Ijlen; int i, j, u, v; int ret = 0; BIGNUM *Ij = NULL, *Bpl1 = NULL; /* These hold Ij and B + 1 */ EVP_MD_CTX *ctx = NULL; #ifdef OPENSSL_DEBUG_KEYGEN unsigned char *tmpout = out; int tmpn = n; #endif ctx = EVP_MD_CTX_new(); if (ctx == NULL) goto err; #ifdef OPENSSL_DEBUG_KEYGEN fprintf(stderr, "KEYGEN DEBUG\n"); fprintf(stderr, "ID %d, ITER %d\n", id, iter); fprintf(stderr, "Password (length %d):\n", passlen); h__dump(pass, passlen); fprintf(stderr, "Salt (length %d):\n", saltlen); h__dump(salt, saltlen); #endif v = EVP_MD_block_size(md_type); u = EVP_MD_size(md_type); if (u < 0 || v <= 0) goto err; D = OPENSSL_malloc(v); Ai = OPENSSL_malloc(u); B = OPENSSL_malloc(v + 1); Slen = v * ((saltlen + v - 1) / v); if (passlen) Plen = v * ((passlen + v - 1) / v); else Plen = 0; Ilen = Slen + Plen; I = OPENSSL_malloc(Ilen); Ij = BN_new(); Bpl1 = BN_new(); if (D == NULL || Ai == NULL || B == NULL || I == NULL || Ij == NULL || Bpl1 == NULL) goto err; for (i = 0; i < v; i++) D[i] = id; p = I; for (i = 0; i < Slen; i++) *p++ = salt[i % saltlen]; for (i = 0; i < Plen; i++) *p++ = pass[i % passlen]; for (;;) { if (!EVP_DigestInit_ex(ctx, md_type, NULL) || !EVP_DigestUpdate(ctx, D, v) || !EVP_DigestUpdate(ctx, I, Ilen) || !EVP_DigestFinal_ex(ctx, Ai, NULL)) goto err; for (j = 1; j < iter; j++) { if (!EVP_DigestInit_ex(ctx, md_type, NULL) || !EVP_DigestUpdate(ctx, Ai, u) || !EVP_DigestFinal_ex(ctx, Ai, NULL)) goto err; } memcpy(out, Ai, min(n, u)); if (u >= n) { #ifdef OPENSSL_DEBUG_KEYGEN fprintf(stderr, "Output KEY (length %d)\n", tmpn); h__dump(tmpout, tmpn); #endif ret = 1; goto end; } n -= u; out += u; for (j = 0; j < v; j++) B[j] = Ai[j % u]; /* Work out B + 1 first then can use B as tmp space */ if (!BN_bin2bn(B, v, Bpl1)) goto err; if (!BN_add_word(Bpl1, 1)) goto err; for (j = 0; j < Ilen; j += v) { if (!BN_bin2bn(I + j, v, Ij)) goto err; if (!BN_add(Ij, Ij, Bpl1)) goto err; if (!BN_bn2bin(Ij, B)) goto err; Ijlen = BN_num_bytes(Ij); /* If more than 2^(v*8) - 1 cut off MSB */ if (Ijlen > v) { if (!BN_bn2bin(Ij, B)) goto err; memcpy(I + j, B + 1, v); #ifndef PKCS12_BROKEN_KEYGEN /* If less than v bytes pad with zeroes */ } else if (Ijlen < v) { memset(I + j, 0, v - Ijlen); if (!BN_bn2bin(Ij, I + j + v - Ijlen)) goto err; #endif } else if (!BN_bn2bin(Ij, I + j)) goto err; } } err: PKCS12err(PKCS12_F_PKCS12_KEY_GEN_UNI, ERR_R_MALLOC_FAILURE); end: OPENSSL_free(Ai); OPENSSL_free(B); OPENSSL_free(D); OPENSSL_free(I); BN_free(Ij); BN_free(Bpl1); EVP_MD_CTX_free(ctx); return ret; }
int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt, int saltlen, int id, int iter, int n, unsigned char *out, const EVP_MD *md_type) { unsigned char *B, *D, *I, *p, *Ai; int Slen, Plen, Ilen, Ijlen; int i, j, u, v; int ret = 0; BIGNUM *Ij, *Bpl1; /* These hold Ij and B + 1 */ EVP_MD_CTX ctx; #ifdef DEBUG_KEYGEN unsigned char *tmpout = out; int tmpn = n; #endif #if 0 if (!pass) { PKCS12err(PKCS12_F_PKCS12_KEY_GEN_UNI,ERR_R_PASSED_NULL_PARAMETER); return 0; } #endif EVP_MD_CTX_init(&ctx); #ifdef DEBUG_KEYGEN TINYCLR_SSL_FPRINTF(OPENSSL_TYPE__FILE_STDERR, "KEYGEN DEBUG\n"); TINYCLR_SSL_FPRINTF(OPENSSL_TYPE__FILE_STDERR, "ID %d, ITER %d\n", id, iter); TINYCLR_SSL_FPRINTF(OPENSSL_TYPE__FILE_STDERR, "Password (length %d):\n", passlen); h__dump(pass, passlen); TINYCLR_SSL_FPRINTF(OPENSSL_TYPE__FILE_STDERR, "Salt (length %d):\n", saltlen); h__dump(salt, saltlen); #endif v = EVP_MD_block_size (md_type); u = EVP_MD_size (md_type); if (u < 0) return 0; D = (unsigned char*)OPENSSL_malloc (v); Ai = (unsigned char*)OPENSSL_malloc (u); B = (unsigned char*)OPENSSL_malloc (v + 1); Slen = v * ((saltlen+v-1)/v); if(passlen) Plen = v * ((passlen+v-1)/v); else Plen = 0; Ilen = Slen + Plen; I = (unsigned char*)OPENSSL_malloc (Ilen); Ij = BN_new(); Bpl1 = BN_new(); if (!D || !Ai || !B || !I || !Ij || !Bpl1) goto err; for (i = 0; i < v; i++) D[i] = id; p = I; for (i = 0; i < Slen; i++) *p++ = salt[i % saltlen]; for (i = 0; i < Plen; i++) *p++ = pass[i % passlen]; for (;;) { EVP_DigestInit_ex(&ctx, md_type, NULL); EVP_DigestUpdate(&ctx, D, v); EVP_DigestUpdate(&ctx, I, Ilen); EVP_DigestFinal_ex(&ctx, Ai, NULL); for (j = 1; j < iter; j++) { EVP_DigestInit_ex(&ctx, md_type, NULL); EVP_DigestUpdate(&ctx, Ai, u); EVP_DigestFinal_ex(&ctx, Ai, NULL); } TINYCLR_SSL_MEMCPY (out, Ai, min (n, u)); if (u >= n) { #ifdef DEBUG_KEYGEN TINYCLR_SSL_FPRINTF(OPENSSL_TYPE__FILE_STDERR, "Output KEY (length %d)\n", tmpn); h__dump(tmpout, tmpn); #endif ret = 1; goto end; } n -= u; out += u; for (j = 0; j < v; j++) B[j] = Ai[j % u]; /* Work out B + 1 first then can use B as tmp space */ if (!BN_bin2bn (B, v, Bpl1)) goto err; if (!BN_add_word (Bpl1, 1)) goto err; for (j = 0; j < Ilen ; j+=v) { if (!BN_bin2bn (I + j, v, Ij)) goto err; if (!BN_add (Ij, Ij, Bpl1)) goto err; BN_bn2bin (Ij, B); Ijlen = BN_num_bytes (Ij); /* If more than 2^(v*8) - 1 cut off MSB */ if (Ijlen > v) { BN_bn2bin (Ij, B); TINYCLR_SSL_MEMCPY (I + j, B + 1, v); #ifndef PKCS12_BROKEN_KEYGEN /* If less than v bytes pad with zeroes */ } else if (Ijlen < v) { TINYCLR_SSL_MEMSET(I + j, 0, v - Ijlen); BN_bn2bin(Ij, I + j + v - Ijlen); #endif } else BN_bn2bin (Ij, I + j); } } err: PKCS12err(PKCS12_F_PKCS12_KEY_GEN_UNI,ERR_R_MALLOC_FAILURE); end: OPENSSL_free (Ai); OPENSSL_free (B); OPENSSL_free (D); OPENSSL_free (I); BN_free (Ij); BN_free (Bpl1); EVP_MD_CTX_cleanup(&ctx); return ret; }