| Index: openssl/crypto/evp/p5_crpt2.c
|
| ===================================================================
|
| --- openssl/crypto/evp/p5_crpt2.c (revision 105093)
|
| +++ openssl/crypto/evp/p5_crpt2.c (working copy)
|
| @@ -3,7 +3,7 @@
|
| * project 1999.
|
| */
|
| /* ====================================================================
|
| - * Copyright (c) 1999 The OpenSSL Project. All rights reserved.
|
| + * Copyright (c) 1999-2006 The OpenSSL Project. All rights reserved.
|
| *
|
| * Redistribution and use in source and binary forms, with or without
|
| * modification, are permitted provided that the following conditions
|
| @@ -71,28 +71,38 @@
|
| #endif
|
|
|
| /* This is an implementation of PKCS#5 v2.0 password based encryption key
|
| - * derivation function PBKDF2 using the only currently defined function HMAC
|
| - * with SHA1. Verified against test vectors posted by Peter Gutmann
|
| + * derivation function PBKDF2.
|
| + * SHA1 version verified against test vectors posted by Peter Gutmann
|
| * <pgut001@cs.auckland.ac.nz> to the PKCS-TNG <pkcs-tng@rsa.com> mailing list.
|
| */
|
|
|
| -int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
|
| +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)
|
| -{
|
| - unsigned char digtmp[SHA_DIGEST_LENGTH], *p, itmp[4];
|
| - int cplen, j, k, tkeylen;
|
| + {
|
| + unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4];
|
| + int cplen, j, k, tkeylen, mdlen;
|
| unsigned long i = 1;
|
| HMAC_CTX hctx;
|
|
|
| + mdlen = EVP_MD_size(digest);
|
| + if (mdlen < 0)
|
| + return 0;
|
| +
|
| HMAC_CTX_init(&hctx);
|
| p = out;
|
| tkeylen = keylen;
|
| - if(!pass) passlen = 0;
|
| - else if(passlen == -1) passlen = strlen(pass);
|
| - while(tkeylen) {
|
| - if(tkeylen > SHA_DIGEST_LENGTH) cplen = SHA_DIGEST_LENGTH;
|
| - else cplen = tkeylen;
|
| + if(!pass)
|
| + passlen = 0;
|
| + else if(passlen == -1)
|
| + passlen = strlen(pass);
|
| + while(tkeylen)
|
| + {
|
| + if(tkeylen > mdlen)
|
| + cplen = mdlen;
|
| + else
|
| + cplen = tkeylen;
|
| /* We are unlikely to ever use more than 256 blocks (5120 bits!)
|
| * but just in case...
|
| */
|
| @@ -100,20 +110,22 @@
|
| itmp[1] = (unsigned char)((i >> 16) & 0xff);
|
| itmp[2] = (unsigned char)((i >> 8) & 0xff);
|
| itmp[3] = (unsigned char)(i & 0xff);
|
| - HMAC_Init_ex(&hctx, pass, passlen, EVP_sha1(), NULL);
|
| + HMAC_Init_ex(&hctx, pass, passlen, digest, NULL);
|
| HMAC_Update(&hctx, salt, saltlen);
|
| HMAC_Update(&hctx, itmp, 4);
|
| HMAC_Final(&hctx, digtmp, NULL);
|
| memcpy(p, digtmp, cplen);
|
| - for(j = 1; j < iter; j++) {
|
| - HMAC(EVP_sha1(), pass, passlen,
|
| - digtmp, SHA_DIGEST_LENGTH, digtmp, NULL);
|
| - for(k = 0; k < cplen; k++) p[k] ^= digtmp[k];
|
| - }
|
| + for(j = 1; j < iter; j++)
|
| + {
|
| + HMAC(digest, pass, passlen,
|
| + digtmp, mdlen, digtmp, NULL);
|
| + for(k = 0; k < cplen; k++)
|
| + p[k] ^= digtmp[k];
|
| + }
|
| tkeylen-= cplen;
|
| i++;
|
| p+= cplen;
|
| - }
|
| + }
|
| HMAC_CTX_cleanup(&hctx);
|
| #ifdef DEBUG_PKCS5V2
|
| fprintf(stderr, "Password:\n");
|
| @@ -125,8 +137,16 @@
|
| h__dump (out, keylen);
|
| #endif
|
| return 1;
|
| -}
|
| + }
|
|
|
| +int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
|
| + const unsigned char *salt, int saltlen, int iter,
|
| + int keylen, unsigned char *out)
|
| + {
|
| + return PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, EVP_sha1(),
|
| + keylen, out);
|
| + }
|
| +
|
| #ifdef DO_TEST
|
| main()
|
| {
|
| @@ -155,6 +175,8 @@
|
| PBE2PARAM *pbe2 = NULL;
|
| const EVP_CIPHER *cipher;
|
| PBKDF2PARAM *kdf = NULL;
|
| + const EVP_MD *prfmd;
|
| + int prf_nid, hmac_md_nid;
|
|
|
| if (param == NULL || param->type != V_ASN1_SEQUENCE ||
|
| param->value.sequence == NULL) {
|
| @@ -180,8 +202,7 @@
|
| /* lets see if we recognise the encryption algorithm.
|
| */
|
|
|
| - cipher = EVP_get_cipherbyname(
|
| - OBJ_nid2sn(OBJ_obj2nid(pbe2->encryption->algorithm)));
|
| + cipher = EVP_get_cipherbyobj(pbe2->encryption->algorithm);
|
|
|
| if(!cipher) {
|
| EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
|
| @@ -226,11 +247,24 @@
|
| goto err;
|
| }
|
|
|
| - if(kdf->prf && (OBJ_obj2nid(kdf->prf->algorithm) != NID_hmacWithSHA1)) {
|
| + 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_PBE_KEYIVGEN, EVP_R_UNSUPPORTED_PRF);
|
| goto err;
|
| - }
|
| + }
|
|
|
| + prfmd = EVP_get_digestbynid(hmac_md_nid);
|
| + if (prfmd == NULL)
|
| + {
|
| + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_UNSUPPORTED_PRF);
|
| + goto err;
|
| + }
|
| +
|
| if(kdf->salt->type != V_ASN1_OCTET_STRING) {
|
| EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
|
| EVP_R_UNSUPPORTED_SALT_TYPE);
|
| @@ -241,7 +275,9 @@
|
| salt = kdf->salt->value.octet_string->data;
|
| saltlen = kdf->salt->value.octet_string->length;
|
| iter = ASN1_INTEGER_get(kdf->iter);
|
| - PKCS5_PBKDF2_HMAC_SHA1(pass, passlen, salt, saltlen, iter, keylen, key);
|
| + if(!PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, prfmd,
|
| + keylen, key))
|
| + goto err;
|
| EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de);
|
| OPENSSL_cleanse(key, keylen);
|
| PBKDF2PARAM_free(kdf);
|
|
|