+ ASN1_TYPE *param, const EVP_CIPHER *c,
+ const EVP_MD *md, int en_de)
+{
+ const unsigned char *pbuf;
+ int plen;
+ PBE2PARAM *pbe2 = NULL;
+ const EVP_CIPHER *cipher;
+ EVP_PBE_KEYGEN *kdf;
+
+ int rv = 0;
+
+ if (param == NULL || param->type != V_ASN1_SEQUENCE ||
+ param->value.sequence == NULL) {
+ EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_DECODE_ERROR);
+ goto err;
+ }
+
+ pbuf = param->value.sequence->data;
+ plen = param->value.sequence->length;
+ if (!(pbe2 = d2i_PBE2PARAM(NULL, &pbuf, plen))) {
+ EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_DECODE_ERROR);
+ goto err;
+ }
+
+ /* See if we recognise the key derivation function */
+ if (!EVP_PBE_find(EVP_PBE_TYPE_KDF, OBJ_obj2nid(pbe2->keyfunc->algorithm),
+ NULL, NULL, &kdf)) {
+ EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
+ EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION);
+ goto err;
+ }
+
+ /*
+ * lets see if we recognise the encryption algorithm.
+ */
+
+ cipher = EVP_get_cipherbyobj(pbe2->encryption->algorithm);
+
+ if (!cipher) {
+ EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_UNSUPPORTED_CIPHER);
+ goto err;
+ }
+
+ /* Fixup cipher based on AlgorithmIdentifier */
+ if (!EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, en_de))
+ goto err;
+ if (EVP_CIPHER_asn1_to_param(ctx, pbe2->encryption->parameter) < 0) {
+ EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_CIPHER_PARAMETER_ERROR);
+ goto err;
+ }
+ rv = kdf(ctx, pass, passlen, pbe2->keyfunc->parameter, NULL, NULL, en_de);
+ err:
+ PBE2PARAM_free(pbe2);
+ return rv;
+}
+
+int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass,
+ int passlen, ASN1_TYPE *param,
+ const EVP_CIPHER *c, const EVP_MD *md, int en_de)
+{
+ unsigned char *salt, key[EVP_MAX_KEY_LENGTH];
+ const unsigned char *pbuf;
+ int saltlen, iter, plen;
+ int rv = 0;
+ unsigned int keylen = 0;
+ int prf_nid, hmac_md_nid;
+ PBKDF2PARAM *kdf = NULL;
+ const EVP_MD *prfmd;
+
+ if (EVP_CIPHER_CTX_cipher(ctx) == NULL) {
+ EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_NO_CIPHER_SET);
+ goto err;
+ }
+ keylen = EVP_CIPHER_CTX_key_length(ctx);
+ OPENSSL_assert(keylen <= sizeof key);
+
+ /* Decode parameter */
+
+ if (!param || (param->type != V_ASN1_SEQUENCE)) {
+ EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_DECODE_ERROR);
+ goto err;
+ }
+
+ pbuf = param->value.sequence->data;
+ plen = param->value.sequence->length;
+
+ if (!(kdf = d2i_PBKDF2PARAM(NULL, &pbuf, plen))) {
+ EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_DECODE_ERROR);
+ goto err;
+ }
+
+ keylen = EVP_CIPHER_CTX_key_length(ctx);
+
+ /* Now check the parameters of the kdf */
+
+ if (kdf->keylength && (ASN1_INTEGER_get(kdf->keylength) != (int)keylen)) {
+ EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_KEYLENGTH);
+ goto err;
+ }
+
+ if (kdf->prf)
+ prf_nid = OBJ_obj2nid(kdf->prf->algorithm);
+ else
+ prf_nid = NID_hmacWithSHA1;
+
+ if (!EVP_PBE_find(EVP_PBE_TYPE_PRF, prf_nid, NULL, &hmac_md_nid, 0)) {
+ EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_PRF);
+ goto err;
+ }
+
+ prfmd = EVP_get_digestbynid(hmac_md_nid);
+ if (prfmd == NULL) {
+ EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_PRF);
+ goto err;
+ }
+
+ if (kdf->salt->type != V_ASN1_OCTET_STRING) {
+ EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_SALT_TYPE);
+ goto err;
+ }
+
+ /* it seems that its all OK */
+ salt = kdf->salt->value.octet_string->data;
+ saltlen = kdf->salt->value.octet_string->length;
+ iter = ASN1_INTEGER_get(kdf->iter);
+ if (!PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, prfmd,
+ keylen, key))
+ goto err;
+ rv = EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de);
+ err:
+ OPENSSL_cleanse(key, keylen);
+ PBKDF2PARAM_free(kdf);
+ return rv;
+}
+
+# ifdef DEBUG_PKCS5V2
+static void h__dump(const unsigned char *p, int len)