diff nss/lib/pk11wrap/pk11pbe.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nss/lib/pk11wrap/pk11pbe.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,1432 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "plarena.h"
+
+#include "seccomon.h"
+#include "secitem.h"
+#include "secport.h"
+#include "hasht.h"
+#include "pkcs11t.h"
+#include "sechash.h"
+#include "secasn1.h"
+#include "secder.h"
+#include "secoid.h"
+#include "secerr.h"
+#include "secmod.h"
+#include "pk11func.h"
+#include "secpkcs5.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "pkcs11.h"
+#include "pk11func.h"
+#include "secitem.h"
+#include "key.h"
+
+typedef struct SEC_PKCS5PBEParameterStr SEC_PKCS5PBEParameter;
+struct SEC_PKCS5PBEParameterStr {
+    PLArenaPool     *poolp;
+    SECItem         salt;           /* octet string */
+    SECItem         iteration;      /* integer */
+    SECItem         keyLength;	/* PKCS5v2 only */
+    SECAlgorithmID  *pPrfAlgId;	/* PKCS5v2 only */
+    SECAlgorithmID  prfAlgId;	/* PKCS5v2 only */
+};
+
+/* PKCS5 V2 has an algorithm ID for the encryption and for 
+ * the key generation. This is valid for SEC_OID_PKCS5_PBES2 
+ * and SEC_OID_PKCS5_PBMAC1
+ */
+struct sec_pkcs5V2ParameterStr {
+    PLArenaPool    *poolp;
+    SECAlgorithmID pbeAlgId;   /* real pbe algorithms */
+    SECAlgorithmID cipherAlgId; /* encryption/mac */
+};
+
+typedef struct sec_pkcs5V2ParameterStr sec_pkcs5V2Parameter;
+
+
+/* template for PKCS 5 PBE Parameter.  This template has been expanded
+ * based upon the additions in PKCS 12.  This should eventually be moved
+ * if RSA updates PKCS 5.
+ */
+const SEC_ASN1Template SEC_PKCS5PBEParameterTemplate[] =
+{
+    { SEC_ASN1_SEQUENCE, 
+	0, NULL, sizeof(SEC_PKCS5PBEParameter) },
+    { SEC_ASN1_OCTET_STRING, 
+	offsetof(SEC_PKCS5PBEParameter, salt) },
+    { SEC_ASN1_INTEGER,
+	offsetof(SEC_PKCS5PBEParameter, iteration) },
+    { 0 }
+};
+
+const SEC_ASN1Template SEC_V2PKCS12PBEParameterTemplate[] =
+{   
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS5PBEParameter) },
+    { SEC_ASN1_OCTET_STRING, offsetof(SEC_PKCS5PBEParameter, salt) },
+    { SEC_ASN1_INTEGER, offsetof(SEC_PKCS5PBEParameter, iteration) },
+    { 0 }
+};
+
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+
+/* SECOID_PKCS5_PBKDF2 */
+const SEC_ASN1Template SEC_PKCS5V2PBEParameterTemplate[] =
+{   
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS5PBEParameter) },
+    /* This is really a choice, but since we only understand this
+     * choice, just inline it */
+    { SEC_ASN1_OCTET_STRING, offsetof(SEC_PKCS5PBEParameter, salt) },
+    { SEC_ASN1_INTEGER, offsetof(SEC_PKCS5PBEParameter, iteration) },
+    { SEC_ASN1_INTEGER|SEC_ASN1_OPTIONAL, 
+		      offsetof(SEC_PKCS5PBEParameter, keyLength) },
+    { SEC_ASN1_POINTER | SEC_ASN1_XTRN | SEC_ASN1_OPTIONAL, 
+	offsetof(SEC_PKCS5PBEParameter, pPrfAlgId),
+	SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { 0 }
+};
+
+/* SEC_OID_PKCS5_PBES2, SEC_OID_PKCS5_PBMAC1 */
+const SEC_ASN1Template SEC_PKCS5V2ParameterTemplate[] =
+{   
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS5PBEParameter) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(sec_pkcs5V2Parameter, pbeAlgId),
+	SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
+	offsetof(sec_pkcs5V2Parameter, cipherAlgId),
+	SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+    { 0 }
+};
+
+
+/*
+ * maps a PBE algorithm to a crypto algorithm. for PKCS12 and PKCS5v1
+ * for PKCS5v2 it returns SEC_OID_PKCS5_PBKDF2.
+ */
+SECOidTag
+sec_pkcs5GetCryptoFromAlgTag(SECOidTag algorithm)
+{
+    switch(algorithm)
+    {
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC:
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC:
+	    return SEC_OID_DES_EDE3_CBC;
+	case SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC:
+	case SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC:
+	case SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC:
+	    return SEC_OID_DES_CBC;
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
+	    return SEC_OID_RC2_CBC;
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4:
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4:
+	    return SEC_OID_RC4;
+	case SEC_OID_PKCS5_PBKDF2:
+	case SEC_OID_PKCS5_PBES2:
+	case SEC_OID_PKCS5_PBMAC1:
+	    return SEC_OID_PKCS5_PBKDF2;
+	default:
+	    break;
+    }
+
+    return SEC_OID_UNKNOWN;
+}
+
+/*
+ * get a new PKCS5 V2 Parameter from the algorithm id.
+ *  if arena is passed in, use it, otherwise create a new arena.
+ */
+sec_pkcs5V2Parameter *
+sec_pkcs5_v2_get_v2_param(PLArenaPool *arena, SECAlgorithmID *algid)
+{
+    PLArenaPool *localArena = NULL;
+    sec_pkcs5V2Parameter *pbeV2_param;
+    SECStatus rv;
+
+    if (arena == NULL) {
+	localArena = arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+	if (arena == NULL) {
+	    return NULL;
+	}
+    }
+    pbeV2_param = PORT_ArenaZNew(arena, sec_pkcs5V2Parameter);
+    if (pbeV2_param == NULL) {
+	goto loser;
+    }
+	
+    rv = SEC_ASN1DecodeItem(arena, pbeV2_param,
+		SEC_PKCS5V2ParameterTemplate, &algid->parameters);
+    if (rv == SECFailure) {
+	goto loser;
+    }
+
+    pbeV2_param->poolp = arena;
+    return pbeV2_param;
+loser:
+    if (localArena) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    return NULL;
+}
+
+void
+sec_pkcs5_v2_destroy_v2_param(sec_pkcs5V2Parameter *param)
+{
+   if (param && param->poolp) {
+	PORT_FreeArena(param->poolp, PR_TRUE);
+   }
+}
+	
+
+/* maps crypto algorithm from PBE algorithm.
+ */
+SECOidTag 
+SEC_PKCS5GetCryptoAlgorithm(SECAlgorithmID *algid)
+{
+
+    SECOidTag pbeAlg;
+    SECOidTag cipherAlg;
+
+    if(algid == NULL)
+	return SEC_OID_UNKNOWN;
+
+    pbeAlg = SECOID_GetAlgorithmTag(algid);
+    cipherAlg = sec_pkcs5GetCryptoFromAlgTag(pbeAlg);
+    if ((cipherAlg == SEC_OID_PKCS5_PBKDF2)  &&
+	 (pbeAlg != SEC_OID_PKCS5_PBKDF2)) {
+	sec_pkcs5V2Parameter *pbeV2_param;
+	cipherAlg = SEC_OID_UNKNOWN;
+
+	pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid);
+	if (pbeV2_param != NULL) {
+	    cipherAlg = SECOID_GetAlgorithmTag(&pbeV2_param->cipherAlgId);
+	    sec_pkcs5_v2_destroy_v2_param(pbeV2_param);
+	}
+    }
+
+    return cipherAlg;
+}
+
+/* check to see if an oid is a pbe algorithm
+ */ 
+PRBool 
+SEC_PKCS5IsAlgorithmPBEAlg(SECAlgorithmID *algid)
+{
+    return (PRBool)(SEC_PKCS5GetCryptoAlgorithm(algid) != SEC_OID_UNKNOWN);
+}
+
+PRBool 
+SEC_PKCS5IsAlgorithmPBEAlgTag(SECOidTag algtag)
+{
+    return (PRBool)(sec_pkcs5GetCryptoFromAlgTag(algtag) != SEC_OID_UNKNOWN);
+}
+
+/*
+ * find the most appropriate PKCS5v2 overall oid tag from a regular
+ * cipher/hash algorithm tag.
+ */
+static SECOidTag
+sec_pkcs5v2_get_pbe(SECOidTag algTag)
+{
+    /* if it's a valid hash oid... */
+    if (HASH_GetHashOidTagByHMACOidTag(algTag) != SEC_OID_UNKNOWN) {
+	/* use the MAC tag */
+	return SEC_OID_PKCS5_PBMAC1;
+    }
+    if (HASH_GetHashTypeByOidTag(algTag) != HASH_AlgNULL) {
+	/* eliminate Hash algorithms */
+	return SEC_OID_UNKNOWN;
+    }
+    if (PK11_AlgtagToMechanism(algTag) != CKM_INVALID_MECHANISM) {
+	/* it's not a hash, if it has a PKCS #11 mechanism associated
+	 * with it, assume it's a cipher. (NOTE this will generate
+	 * some false positives). */
+	return SEC_OID_PKCS5_PBES2;
+    }
+    return SEC_OID_UNKNOWN;
+}
+
+/* 
+ * maps PBE algorithm from crypto algorithm, assumes SHA1 hashing.
+ *  input keyLen in bits.
+ */
+SECOidTag 
+SEC_PKCS5GetPBEAlgorithm(SECOidTag algTag, int keyLen)
+{
+    switch(algTag)
+    {
+	case SEC_OID_DES_EDE3_CBC:
+	    switch(keyLen) {
+		case 168:
+		case 192:
+		case 0:
+		    return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC;
+		case 128:
+		case 92:
+		    return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC;
+		default:
+		    break;
+	    }
+	    break;
+	case SEC_OID_DES_CBC:
+	    return SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC;
+	case SEC_OID_RC2_CBC:
+	    switch(keyLen) {
+		case 40:
+		    return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
+		case 128:
+		case 0:
+		    return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC;
+		default:
+		    break;
+	    }
+	    break;
+	case SEC_OID_RC4:
+	    switch(keyLen) {
+		case 40:
+		    return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4;
+		case 128:
+		case 0:
+		    return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4;
+		default:
+		    break;
+	    }
+	    break;
+	default:
+	    return sec_pkcs5v2_get_pbe(algTag);
+    }
+
+    return SEC_OID_UNKNOWN;
+}
+
+/*
+ * get the key length in bytes from a PKCS5 PBE
+ */
+int
+sec_pkcs5v2_key_length(SECAlgorithmID *algid)
+{
+    SECOidTag algorithm;
+    PLArenaPool *arena = NULL;
+    SEC_PKCS5PBEParameter p5_param;
+    SECStatus rv;
+    int length = -1;
+
+    algorithm = SECOID_GetAlgorithmTag(algid);
+    /* sanity check, they should all be PBKDF2 here */
+    if (algorithm != SEC_OID_PKCS5_PBKDF2) {
+	return -1;
+    }
+
+    arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+    if (arena == NULL) {
+	goto loser;
+    }
+    PORT_Memset(&p5_param, 0, sizeof(p5_param));
+    rv = SEC_ASN1DecodeItem(arena,&p5_param,
+			 SEC_PKCS5V2PBEParameterTemplate, &algid->parameters);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    if (p5_param.keyLength.data != NULL) {
+        length = DER_GetInteger(&p5_param.keyLength);
+    }
+
+loser:
+    if (arena) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    return length;
+}
+
+/*
+ *  get the key length in bytes needed for the PBE algorithm
+ */
+int 
+SEC_PKCS5GetKeyLength(SECAlgorithmID *algid)
+{
+
+    SECOidTag algorithm;
+
+    if(algid == NULL)
+	return SEC_OID_UNKNOWN;
+
+    algorithm = SECOID_GetAlgorithmTag(algid);
+
+    switch(algorithm)
+    {
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC:
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC:
+	    return 24;
+	case SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC:
+	case SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC:
+	case SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC:
+	    return 8;
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
+	    return 5;
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
+	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4:
+	    return 16;
+	case SEC_OID_PKCS5_PBKDF2:
+	    return sec_pkcs5v2_key_length(algid);
+	case SEC_OID_PKCS5_PBES2:
+	case SEC_OID_PKCS5_PBMAC1:
+	    {
+		sec_pkcs5V2Parameter *pbeV2_param;
+		int length = -1;
+		pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid);
+		if (pbeV2_param != NULL) {
+	    	    length = sec_pkcs5v2_key_length(&pbeV2_param->pbeAlgId);
+		    sec_pkcs5_v2_destroy_v2_param(pbeV2_param);
+		}
+		return length;
+	    }
+	
+	default:
+	    break;
+    }
+    return -1;
+}
+
+
+/* the PKCS12 V2 algorithms only encode the salt, there is no iteration
+ * count so we need a check for V2 algorithm parameters.
+ */
+static PRBool
+sec_pkcs5_is_algorithm_v2_pkcs12_algorithm(SECOidTag algorithm)
+{
+    switch(algorithm) 
+    {
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
+	case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
+	    return PR_TRUE;
+	default:
+	    break;
+    }
+
+    return PR_FALSE;
+}
+
+static PRBool
+sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(SECOidTag algorithm)
+{
+    switch(algorithm) 
+    {
+	case SEC_OID_PKCS5_PBES2:
+	case SEC_OID_PKCS5_PBMAC1:
+	case SEC_OID_PKCS5_PBKDF2:
+	    return PR_TRUE;
+	default:
+	    break;
+    }
+
+    return PR_FALSE;
+}
+
+/* destroy a pbe parameter.  it assumes that the parameter was 
+ * generated using the appropriate create function and therefor
+ * contains an arena pool.
+ */
+static void 
+sec_pkcs5_destroy_pbe_param(SEC_PKCS5PBEParameter *pbe_param)
+{
+    if(pbe_param != NULL)
+	PORT_FreeArena(pbe_param->poolp, PR_TRUE);
+}
+
+/* creates a PBE parameter based on the PBE algorithm.  the only required
+ * parameters are algorithm and interation.  the return is a PBE parameter
+ * which conforms to PKCS 5 parameter unless an extended parameter is needed.
+ * this is primarily if keyLength and a variable key length algorithm are
+ * specified.
+ *   salt -  if null, a salt will be generated from random bytes.
+ *   iteration - number of iterations to perform hashing.
+ *   keyLength - only used in variable key length algorithms. if specified,
+ *            should be in bytes.
+ * once a parameter is allocated, it should be destroyed calling 
+ * sec_pkcs5_destroy_pbe_parameter or SEC_PKCS5DestroyPBEParameter.
+ */
+#define DEFAULT_SALT_LENGTH 16
+static SEC_PKCS5PBEParameter *
+sec_pkcs5_create_pbe_parameter(SECOidTag algorithm, 
+			SECItem *salt, 
+			int iteration,
+			int keyLength,
+			SECOidTag prfAlg)
+{
+    PLArenaPool *poolp = NULL;
+    SEC_PKCS5PBEParameter *pbe_param = NULL;
+    SECStatus rv= SECSuccess; 
+    void *dummy = NULL;
+
+    if(iteration < 0) {
+	return NULL;
+    }
+
+    poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+    if(poolp == NULL)
+	return NULL;
+
+    pbe_param = (SEC_PKCS5PBEParameter *)PORT_ArenaZAlloc(poolp,
+	sizeof(SEC_PKCS5PBEParameter));
+    if(!pbe_param) {
+	PORT_FreeArena(poolp, PR_TRUE);
+	return NULL;
+    }
+
+    pbe_param->poolp = poolp;
+
+    rv = SECFailure;
+    if (salt && salt->data) {
+    	rv = SECITEM_CopyItem(poolp, &pbe_param->salt, salt);
+    } else {
+	/* sigh, the old interface generated salt on the fly, so we have to
+	 * preserve the semantics */
+	pbe_param->salt.len = DEFAULT_SALT_LENGTH;
+	pbe_param->salt.data = PORT_ArenaZAlloc(poolp,DEFAULT_SALT_LENGTH);
+	if (pbe_param->salt.data) {
+	   rv = PK11_GenerateRandom(pbe_param->salt.data,DEFAULT_SALT_LENGTH);
+	}
+    }
+
+    if(rv != SECSuccess) {
+	PORT_FreeArena(poolp, PR_TRUE);
+	return NULL;
+    }
+
+    /* encode the integer */
+    dummy = SEC_ASN1EncodeInteger(poolp, &pbe_param->iteration, 
+		iteration);
+    rv = (dummy) ? SECSuccess : SECFailure;
+
+    if(rv != SECSuccess) {
+	PORT_FreeArena(poolp, PR_FALSE);
+	return NULL;
+    }
+
+    /*
+     * for PKCS5 v2 Add the keylength and the prf
+     */
+    if (algorithm == SEC_OID_PKCS5_PBKDF2) {
+	dummy = SEC_ASN1EncodeInteger(poolp, &pbe_param->keyLength, 
+		keyLength);
+	rv = (dummy) ? SECSuccess : SECFailure;
+	if (rv != SECSuccess) {
+	    PORT_FreeArena(poolp, PR_FALSE);
+	    return NULL;
+	}
+	rv = SECOID_SetAlgorithmID(poolp, &pbe_param->prfAlgId, prfAlg, NULL);
+	if (rv != SECSuccess) {
+	    PORT_FreeArena(poolp, PR_FALSE);
+	    return NULL;
+	}
+	pbe_param->pPrfAlgId = &pbe_param->prfAlgId;
+    }
+
+    return pbe_param;
+}
+
+/* creates a algorithm ID containing the PBE algorithm and appropriate
+ * parameters.  the required parameter is the algorithm.  if salt is
+ * not specified, it is generated randomly.  
+ *
+ * the returned SECAlgorithmID should be destroyed using 
+ * SECOID_DestroyAlgorithmID
+ */
+SECAlgorithmID *
+sec_pkcs5CreateAlgorithmID(SECOidTag algorithm, 
+			   SECOidTag cipherAlgorithm,
+			   SECOidTag prfAlg,
+			   SECOidTag *pPbeAlgorithm,
+			   int keyLength,
+			   SECItem *salt, 
+			   int iteration)
+{
+    PLArenaPool *poolp = NULL;
+    SECAlgorithmID *algid, *ret_algid = NULL;
+    SECOidTag pbeAlgorithm = algorithm;
+    SECItem der_param;
+    void *dummy;
+    SECStatus rv = SECFailure;
+    SEC_PKCS5PBEParameter *pbe_param = NULL;
+    sec_pkcs5V2Parameter pbeV2_param;
+
+    if(iteration <= 0) {
+	return NULL;
+    }
+
+    poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+    if(!poolp) {
+	goto loser;
+    }
+
+    if (!SEC_PKCS5IsAlgorithmPBEAlgTag(algorithm) ||
+    	 	sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(algorithm)) {
+	/* use PKCS 5 v2 */
+	SECItem *cipherParams;
+
+	/*
+	 * if we ask for pkcs5 Algorithms directly, then the
+	 * application needs to supply the cipher algorithm,
+	 * otherwise we are implicitly using pkcs5 v2 and the
+	 * passed in algorithm is the encryption algorithm.
+	 */
+	if (sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(algorithm)) {
+	    if (cipherAlgorithm == SEC_OID_UNKNOWN) {
+		goto loser;
+	    }
+	} else {
+	    cipherAlgorithm = algorithm;
+	    /* force algorithm to be chosen below */
+	    algorithm = SEC_OID_PKCS5_PBKDF2;
+	}
+	
+	pbeAlgorithm = SEC_OID_PKCS5_PBKDF2;
+	/*
+	 * 'algorithm' is the overall algorithm oid tag used to wrap the 
+	 * entire algoithm ID block. For PKCS5v1 and PKCS12, this 
+	 * algorithm OID has encoded in it both the PBE KDF function 
+	 * and the encryption algorithm. For PKCS 5v2, PBE KDF and
+	 * encryption/macing oids are encoded as parameters in
+	 * the algorithm ID block. 
+	 *
+	 * Thus in PKCS5 v1 and PKCS12, this algorithm maps to a pkcs #11
+	 * mechanism, where as in PKCS 5v2, this alogithm tag does not map
+	 * directly to a PKCS #11 mechanim, instead the 2 oids in the 
+	 * algorithm ID block map the the actual PKCS #11 mechanism.
+	 * gorithm is). We use choose this algorithm oid based on the 
+	 * cipherAlgorithm to determine what this should be (MAC1 or PBES2).
+	 */
+	if (algorithm == SEC_OID_PKCS5_PBKDF2) {
+	     /* choose mac or pbes */
+	     algorithm = sec_pkcs5v2_get_pbe(cipherAlgorithm);
+	}
+
+	/* set the PKCS5v2 specific parameters */
+	if (keyLength == 0) {
+	    SECOidTag hashAlg = HASH_GetHashOidTagByHMACOidTag(cipherAlgorithm);
+    	    if (hashAlg != SEC_OID_UNKNOWN) {
+	        keyLength = HASH_ResultLenByOidTag(hashAlg);
+	    } else {
+		CK_MECHANISM_TYPE cryptoMech;
+		cryptoMech = PK11_AlgtagToMechanism(cipherAlgorithm);
+		if (cryptoMech == CKM_INVALID_MECHANISM) {
+		    goto loser;
+		}
+	        keyLength = PK11_GetMaxKeyLength(cryptoMech);
+	    }
+	    if (keyLength == 0) {
+		goto loser;
+	    }
+	}
+	/* currently only SEC_OID_HMAC_SHA1 is defined */
+	if (prfAlg == SEC_OID_UNKNOWN) {
+	    prfAlg = SEC_OID_HMAC_SHA1;
+	}
+
+	/* build the PKCS5v2 cipher algorithm id */
+	cipherParams = pk11_GenerateNewParamWithKeyLen(	
+			PK11_AlgtagToMechanism(cipherAlgorithm), keyLength);
+	if (!cipherParams) {
+	    goto loser;
+	}
+
+	PORT_Memset(&pbeV2_param, 0, sizeof (pbeV2_param));
+
+	rv = PK11_ParamToAlgid(cipherAlgorithm, cipherParams, 
+				poolp, &pbeV2_param.cipherAlgId);
+	SECITEM_FreeItem(cipherParams, PR_TRUE);
+	if (rv != SECSuccess) {
+	    goto loser;
+	}
+    }
+	
+
+    /* generate the parameter */
+    pbe_param = sec_pkcs5_create_pbe_parameter(pbeAlgorithm, salt, iteration,
+			keyLength, prfAlg);
+    if(!pbe_param) {
+	goto loser;
+    }
+
+    /* generate the algorithm id */
+    algid = (SECAlgorithmID *)PORT_ArenaZAlloc(poolp, sizeof(SECAlgorithmID));
+    if(algid == NULL) {
+	goto loser;
+    }
+
+    der_param.data = NULL;
+    der_param.len = 0;
+    if (sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(algorithm)) {
+	/* first encode the PBE algorithm ID */
+	dummy = SEC_ASN1EncodeItem(poolp, &der_param, pbe_param,
+					SEC_PKCS5V2PBEParameterTemplate);
+	if (dummy == NULL) {
+	    goto loser;
+	}
+	rv = SECOID_SetAlgorithmID(poolp, &pbeV2_param.pbeAlgId, 
+				   pbeAlgorithm, &der_param);
+	if (rv != SECSuccess) {
+	    goto loser;
+	}
+
+	/* now encode the Full PKCS 5 parameter */
+	der_param.data = NULL;
+	der_param.len = 0;
+	dummy = SEC_ASN1EncodeItem(poolp, &der_param, &pbeV2_param,
+					SEC_PKCS5V2ParameterTemplate);
+    } else if(!sec_pkcs5_is_algorithm_v2_pkcs12_algorithm(algorithm)) {
+	dummy = SEC_ASN1EncodeItem(poolp, &der_param, pbe_param,
+					SEC_PKCS5PBEParameterTemplate);
+    } else {
+	dummy = SEC_ASN1EncodeItem(poolp, &der_param, pbe_param,
+	    				SEC_V2PKCS12PBEParameterTemplate);
+    }
+    if (dummy == NULL) {
+	goto loser;
+    }
+
+    rv = SECOID_SetAlgorithmID(poolp, algid, algorithm, &der_param);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+
+    ret_algid = (SECAlgorithmID *)PORT_ZAlloc(sizeof(SECAlgorithmID));
+    if (ret_algid == NULL) {
+	goto loser;
+    }
+
+    rv = SECOID_CopyAlgorithmID(NULL, ret_algid, algid);
+    if (rv != SECSuccess) {
+	SECOID_DestroyAlgorithmID(ret_algid, PR_TRUE);
+	ret_algid = NULL;
+    } else if (pPbeAlgorithm) {
+	*pPbeAlgorithm = pbeAlgorithm;
+    }
+
+loser:
+    if (poolp != NULL) {
+	PORT_FreeArena(poolp, PR_TRUE);
+	algid = NULL;
+    }
+
+    if (pbe_param) {
+	sec_pkcs5_destroy_pbe_param(pbe_param);
+    }
+
+    return ret_algid;
+}
+
+SECStatus
+pbe_PK11AlgidToParam(SECAlgorithmID *algid,SECItem *mech)
+{
+    SEC_PKCS5PBEParameter p5_param;
+    SECItem *salt = NULL;
+    SECOidTag algorithm = SECOID_GetAlgorithmTag(algid);
+    PLArenaPool *arena = NULL;
+    SECStatus rv = SECFailure;
+    unsigned char *paramData = NULL;
+    unsigned char *pSalt = NULL;
+    CK_ULONG iterations;
+    int paramLen = 0;
+    int iv_len;
+    
+
+    arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+    if (arena == NULL) {
+	goto loser;
+    }
+
+
+    /*
+     * decode the algid based on the pbe type
+     */
+    PORT_Memset(&p5_param, 0, sizeof(p5_param));
+    if (sec_pkcs5_is_algorithm_v2_pkcs12_algorithm(algorithm)) {
+        iv_len = PK11_GetIVLength(PK11_AlgtagToMechanism(algorithm));
+        rv = SEC_ASN1DecodeItem(arena, &p5_param,
+			 SEC_V2PKCS12PBEParameterTemplate, &algid->parameters);
+    } else if (algorithm == SEC_OID_PKCS5_PBKDF2) {
+	iv_len = 0;
+        rv = SEC_ASN1DecodeItem(arena,&p5_param,
+			 SEC_PKCS5V2PBEParameterTemplate, &algid->parameters);
+    } else {
+        iv_len = PK11_GetIVLength(PK11_AlgtagToMechanism(algorithm));
+        rv = SEC_ASN1DecodeItem(arena,&p5_param,SEC_PKCS5PBEParameterTemplate, 
+						&algid->parameters);
+    }
+
+    if (iv_len < 0) {
+	goto loser;
+    }
+
+    if (rv != SECSuccess) {
+	goto loser;
+    }
+        
+    /* get salt */
+    salt = &p5_param.salt;
+    iterations = (CK_ULONG) DER_GetInteger(&p5_param.iteration);
+
+    /* allocate and fill in the PKCS #11 parameters
+     * based on the algorithm. */
+    if (algorithm == SEC_OID_PKCS5_PBKDF2) {
+	SECOidTag prfAlgTag;
+    	CK_PKCS5_PBKD2_PARAMS *pbeV2_params = 
+		(CK_PKCS5_PBKD2_PARAMS *)PORT_ZAlloc(
+			sizeof(CK_PKCS5_PBKD2_PARAMS)+ salt->len);
+
+	if (pbeV2_params == NULL) {
+	    goto loser;
+	}
+	paramData = (unsigned char *)pbeV2_params;
+	paramLen = sizeof(CK_PKCS5_PBKD2_PARAMS);
+
+	/* set the prf */
+	prfAlgTag = SEC_OID_HMAC_SHA1;
+ 	if (p5_param.pPrfAlgId &&
+ 	    p5_param.pPrfAlgId->algorithm.data != 0) {
+ 	    prfAlgTag = SECOID_GetAlgorithmTag(p5_param.pPrfAlgId);
+	}
+	if (prfAlgTag == SEC_OID_HMAC_SHA1) {
+	    pbeV2_params->prf = CKP_PKCS5_PBKD2_HMAC_SHA1;
+	} else {
+	    /* only SHA1_HMAC is currently supported by PKCS #11 */
+	    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	    goto loser;
+	}
+	
+	/* probably should fetch these from the prfAlgid */
+	pbeV2_params->pPrfData = NULL;
+	pbeV2_params->ulPrfDataLen = 0;
+	pbeV2_params->saltSource = CKZ_SALT_SPECIFIED;
+	pSalt = ((CK_CHAR_PTR) pbeV2_params)+sizeof(CK_PKCS5_PBKD2_PARAMS);
+        PORT_Memcpy(pSalt, salt->data, salt->len);
+	pbeV2_params->pSaltSourceData = pSalt;
+	pbeV2_params->ulSaltSourceDataLen = salt->len;
+	pbeV2_params->iterations = iterations;
+    } else {
+	CK_PBE_PARAMS *pbe_params = NULL;
+    	pbe_params = (CK_PBE_PARAMS *)PORT_ZAlloc(sizeof(CK_PBE_PARAMS)+
+						salt->len+iv_len);
+	if (pbe_params == NULL) {
+	    goto loser;
+	}
+	paramData = (unsigned char *)pbe_params;
+	paramLen = sizeof(CK_PBE_PARAMS);
+
+	pSalt = ((CK_CHAR_PTR) pbe_params)+sizeof(CK_PBE_PARAMS);
+    	pbe_params->pSalt = pSalt;
+        PORT_Memcpy(pSalt, salt->data, salt->len);
+	pbe_params->ulSaltLen = salt->len;
+	if (iv_len) {
+	    pbe_params->pInitVector = 
+		((CK_CHAR_PTR) pbe_params)+ sizeof(CK_PBE_PARAMS)+salt->len;
+	}
+	pbe_params->ulIteration = iterations;
+    }
+
+    /* copy into the mechanism sec item */
+    mech->data = paramData;
+    mech->len = paramLen;
+    if (arena) {
+	PORT_FreeArena(arena,PR_TRUE);
+    }
+    return SECSuccess;
+
+loser:
+    if (paramData) {
+	PORT_Free(paramData);
+    }
+    if (arena) {
+	PORT_FreeArena(arena,PR_TRUE);
+    }
+    return SECFailure;
+}
+
+/*
+ * public, deprecated, not valid for pkcs5 v2 
+ * 
+ * use PK11_CreatePBEV2AlgorithmID or PK11_CreatePBEAlgorithmID to create
+ * PBE algorithmID's directly.
+ */
+SECStatus
+PBE_PK11ParamToAlgid(SECOidTag algTag, SECItem *param, PLArenaPool *arena,
+		     SECAlgorithmID *algId)
+{
+    CK_PBE_PARAMS *pbe_param;
+    SECItem pbeSalt;
+    SECAlgorithmID *pbeAlgID = NULL;
+    SECStatus rv;
+
+    if(!param || !algId) {
+	return SECFailure;
+    }
+
+    pbe_param = (CK_PBE_PARAMS *)param->data;
+    pbeSalt.data = (unsigned char *)pbe_param->pSalt;
+    pbeSalt.len = pbe_param->ulSaltLen;
+    pbeAlgID = sec_pkcs5CreateAlgorithmID(algTag, SEC_OID_UNKNOWN, 
+	SEC_OID_UNKNOWN, NULL, 0, &pbeSalt, (int)pbe_param->ulIteration);
+    if(!pbeAlgID) {
+	return SECFailure;
+    }
+
+    rv = SECOID_CopyAlgorithmID(arena, algId, pbeAlgID);
+    SECOID_DestroyAlgorithmID(pbeAlgID, PR_TRUE);
+    return rv;
+}
+
+/*
+ * public, Deprecated, This function is only for binary compatibility with 
+ * older applications. Does not support PKCS5v2.
+ *
+ * Applications should use PK11_PBEKeyGen() for keys and PK11_GetPBEIV() for
+ * iv values rather than generating PBE bits directly.
+ */
+PBEBitGenContext *
+PBE_CreateContext(SECOidTag hashAlgorithm, PBEBitGenID bitGenPurpose,
+	SECItem *pwitem, SECItem *salt, unsigned int bitsNeeded,
+	unsigned int iterations)
+{
+    SECItem *context = NULL;
+    SECItem mechItem;
+    CK_PBE_PARAMS pbe_params;
+    CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
+    PK11SlotInfo *slot;
+    PK11SymKey *symKey = NULL;
+    unsigned char ivData[8];
+    
+
+    /* use the purpose to select the low level keygen algorithm */
+    switch (bitGenPurpose) {
+    case pbeBitGenIntegrityKey:
+	switch (hashAlgorithm) {
+	case SEC_OID_SHA1:
+	    mechanism = CKM_PBA_SHA1_WITH_SHA1_HMAC;
+	    break;
+	case SEC_OID_MD2:
+	    mechanism = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN;
+	    break;
+	case SEC_OID_MD5:
+	    mechanism = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN;
+	    break;
+	default:
+	    break;
+	}
+	break;
+    case pbeBitGenCipherIV:
+	if (bitsNeeded > 64) {
+	    break;
+	}
+	if (hashAlgorithm != SEC_OID_SHA1) {
+	    break;
+	}
+	mechanism = CKM_PBE_SHA1_DES3_EDE_CBC;
+	break;
+    case pbeBitGenCipherKey:
+	if (hashAlgorithm != SEC_OID_SHA1) {
+	    break;
+	}
+	switch (bitsNeeded) {
+	case 40:
+	    mechanism = CKM_PBE_SHA1_RC4_40;
+	    break;
+	case 128:
+	    mechanism = CKM_PBE_SHA1_RC4_128;
+	    break;
+	default:
+	    break;
+	}
+    case pbeBitGenIDNull:
+	break;
+    }
+
+    if (mechanism == CKM_INVALID_MECHANISM) {
+	/* we should set an error, but this is a deprecated function, and
+	 * we are keeping bug for bug compatibility;)... */
+	    return NULL;
+    } 
+
+    pbe_params.pInitVector = ivData;
+    pbe_params.pPassword = pwitem->data;
+    pbe_params.ulPasswordLen = pwitem->len;
+    pbe_params.pSalt = salt->data;
+    pbe_params.ulSaltLen = salt->len;
+    pbe_params.ulIteration = iterations;
+    mechItem.data = (unsigned char *) &pbe_params;
+    mechItem.len = sizeof(pbe_params);
+
+
+    slot = PK11_GetInternalSlot();
+    symKey = PK11_RawPBEKeyGen(slot,mechanism,
+					&mechItem, pwitem, PR_FALSE, NULL);
+    PK11_FreeSlot(slot);
+    if (symKey != NULL) {
+	if (bitGenPurpose == pbeBitGenCipherIV) {
+	    /* NOTE: this assumes that bitsNeeded is a multiple of 8! */
+	    SECItem ivItem;
+
+	    ivItem.data = ivData;
+	    ivItem.len = bitsNeeded/8;
+	    context = SECITEM_DupItem(&ivItem);
+	} else {
+	    SECItem *keyData;
+	    PK11_ExtractKeyValue(symKey);
+	    keyData = PK11_GetKeyData(symKey);
+
+	    /* assert bitsNeeded with length? */
+	    if (keyData) {
+	    	context = SECITEM_DupItem(keyData);
+	    }
+	}
+	PK11_FreeSymKey(symKey);
+    }
+
+    return (PBEBitGenContext *)context;
+}
+
+/*
+ * public, Deprecated, This function is only for binary compatibility with 
+ * older applications. Does not support PKCS5v2.
+ * 
+ * Applications should use PK11_PBEKeyGen() for keys and PK11_GetIV() for
+ * iv values rather than generating PBE bits directly.
+ */
+SECItem *
+PBE_GenerateBits(PBEBitGenContext *context)
+{
+    return (SECItem *)context;
+}
+
+/*
+ * public, Deprecated, This function is only for binary compatibility with 
+ * older applications. Does not support PKCS5v2.
+ * 
+ * Applications should use PK11_PBEKeyGen() for keys and PK11_GetPBEIV() for
+ * iv values rather than generating PBE bits directly.
+ */
+void
+PBE_DestroyContext(PBEBitGenContext *context)
+{
+    SECITEM_FreeItem((SECItem *)context,PR_TRUE);
+}
+
+/*
+ * public, deprecated. Replaced with PK11_GetPBEIV().
+ */
+SECItem *
+SEC_PKCS5GetIV(SECAlgorithmID *algid, SECItem *pwitem, PRBool faulty3DES)
+{
+    /* pbe stuff */
+    CK_MECHANISM_TYPE type;
+    SECItem *param = NULL;
+    SECItem *iv = NULL;
+    SECItem src;
+    int iv_len = 0;
+    PK11SymKey *symKey;
+    PK11SlotInfo *slot;
+    CK_PBE_PARAMS_PTR pPBEparams;
+    SECOidTag	pbeAlg;
+
+    pbeAlg = SECOID_GetAlgorithmTag(algid);
+    if (sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(pbeAlg)) {
+	unsigned char *ivData;
+	sec_pkcs5V2Parameter *pbeV2_param = NULL;
+
+	/* can only return the IV if the crypto Algorithm exists */
+	if (pbeAlg == SEC_OID_PKCS5_PBKDF2) {
+	    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	    goto loser;
+	}
+	pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid);
+	if (pbeV2_param == NULL) {
+	    goto loser;
+	}
+	/* extract the IV from the cipher algid portion of our pkcs 5 v2
+	 * algorithm id */
+    	type = PK11_AlgtagToMechanism(
+    		SECOID_GetAlgorithmTag(&pbeV2_param->cipherAlgId));
+	param = PK11_ParamFromAlgid(&pbeV2_param->cipherAlgId);
+	sec_pkcs5_v2_destroy_v2_param(pbeV2_param);
+	if (!param) {
+	    goto loser;
+	}
+	/* NOTE: NULL is a permissible return here */
+	ivData = PK11_IVFromParam(type, param, &iv_len);
+	src.data = ivData;
+	src.len = iv_len;
+	goto done;
+    }
+
+    type = PK11_AlgtagToMechanism(pbeAlg);
+    param = PK11_ParamFromAlgid(algid);
+    if (param == NULL) {
+	goto done;
+    }
+    slot = PK11_GetInternalSlot();
+    symKey = PK11_RawPBEKeyGen(slot, type, param, pwitem, faulty3DES, NULL);
+    PK11_FreeSlot(slot);
+    if (symKey == NULL) {
+	goto loser;
+    }
+    PK11_FreeSymKey(symKey);
+    pPBEparams = (CK_PBE_PARAMS_PTR)param->data;
+    iv_len = PK11_GetIVLength(type);
+
+    src.data = (unsigned char *)pPBEparams->pInitVector;
+    src.len = iv_len;
+
+done:
+    iv = SECITEM_DupItem(&src);
+
+loser:
+    if (param) {
+	SECITEM_ZfreeItem(param, PR_TRUE);
+    }
+    return iv;
+}
+
+/*
+ * Subs from nss 3.x that are deprecated
+ */
+PBEBitGenContext *
+__PBE_CreateContext(SECOidTag hashAlgorithm, PBEBitGenID bitGenPurpose,
+	SECItem *pwitem, SECItem *salt, unsigned int bitsNeeded,
+	unsigned int iterations)
+{
+    PORT_Assert("__PBE_CreateContext is Deprecated" == NULL);
+    return NULL;
+}
+
+SECItem *
+__PBE_GenerateBits(PBEBitGenContext *context)
+{
+    PORT_Assert("__PBE_GenerateBits is Deprecated" == NULL);
+    return NULL;
+}
+
+void
+__PBE_DestroyContext(PBEBitGenContext *context)
+{
+    PORT_Assert("__PBE_DestroyContext is Deprecated" == NULL);
+}
+
+SECStatus
+RSA_FormatBlock(SECItem *result, unsigned modulusLen,
+                int blockType, SECItem *data)
+{
+    PORT_Assert("RSA_FormatBlock is Deprecated" == NULL);
+    return SECFailure;
+}
+
+/****************************************************************************
+ *
+ * Now Do The PBE Functions Here...
+ *
+ ****************************************************************************/
+
+static void
+pk11_destroy_ck_pbe_params(CK_PBE_PARAMS *pbe_params)
+{
+    if (pbe_params) {
+	if (pbe_params->pPassword)
+	    PORT_ZFree(pbe_params->pPassword, pbe_params->ulPasswordLen);
+	if (pbe_params->pSalt)
+	    PORT_ZFree(pbe_params->pSalt, pbe_params->ulSaltLen);
+	PORT_ZFree(pbe_params, sizeof(CK_PBE_PARAMS));
+    }
+}
+
+/*
+ * public, deprecated.  use PK11_CreatePBEAlgorithmID or 
+ * PK11_CreatePBEV2AlgorithmID instead. If you needthe pkcs #11 parameters, 
+ * use PK11_ParamFromAlgid from the algorithm id you created using 
+ * PK11_CreatePBEAlgorithmID or PK11_CreatePBEV2AlgorithmID.
+ */
+SECItem * 
+PK11_CreatePBEParams(SECItem *salt, SECItem *pwd, unsigned int iterations)
+{
+    CK_PBE_PARAMS *pbe_params = NULL;
+    SECItem *paramRV = NULL;
+
+    paramRV = SECITEM_AllocItem(NULL, NULL, sizeof(CK_PBE_PARAMS));
+    if (!paramRV ) {
+	goto loser;
+    }
+    /* init paramRV->data with zeros. SECITEM_AllocItem does not do it */
+    PORT_Memset(paramRV->data, 0, sizeof(CK_PBE_PARAMS));
+
+    pbe_params = (CK_PBE_PARAMS *)paramRV->data;
+    pbe_params->pPassword = (CK_CHAR_PTR)PORT_ZAlloc(pwd->len);
+    if (!pbe_params->pPassword) {
+        goto loser;
+    }
+    PORT_Memcpy(pbe_params->pPassword, pwd->data, pwd->len);
+    pbe_params->ulPasswordLen = pwd->len;
+
+    pbe_params->pSalt = (CK_CHAR_PTR)PORT_ZAlloc(salt->len);
+    if (!pbe_params->pSalt) {
+	goto loser;
+    }
+    PORT_Memcpy(pbe_params->pSalt, salt->data, salt->len);
+    pbe_params->ulSaltLen = salt->len;
+
+    pbe_params->ulIteration = (CK_ULONG)iterations;
+    return paramRV;
+
+loser:
+    if (pbe_params)
+        pk11_destroy_ck_pbe_params(pbe_params);
+    if (paramRV) 
+    	PORT_ZFree(paramRV, sizeof(SECItem));
+    return NULL;
+}
+
+/*
+ * public, deprecated.
+ */
+void
+PK11_DestroyPBEParams(SECItem *pItem)
+{
+    if (pItem) {
+	CK_PBE_PARAMS * params = (CK_PBE_PARAMS *)(pItem->data);
+	if (params)
+	    pk11_destroy_ck_pbe_params(params);
+	PORT_ZFree(pItem, sizeof(SECItem));
+    }
+}
+
+/*
+ * public, Partially supports PKCS5 V2 (some parameters are not controllable
+ * through this interface). Use PK11_CreatePBEV2AlgorithmID() if you need
+ * finer control these.
+ */
+SECAlgorithmID *
+PK11_CreatePBEAlgorithmID(SECOidTag algorithm, int iteration, SECItem *salt)
+{
+    SECAlgorithmID *algid = NULL;
+    algid = sec_pkcs5CreateAlgorithmID(algorithm,
+		 SEC_OID_UNKNOWN, SEC_OID_UNKNOWN, NULL, 0, salt, iteration);
+    return algid;
+}
+
+/*
+ * public, fully support pkcs5v2.
+ */
+SECAlgorithmID *
+PK11_CreatePBEV2AlgorithmID(SECOidTag pbeAlgTag, SECOidTag cipherAlgTag,
+			    SECOidTag prfAlgTag, int keyLength, int iteration, 
+			    SECItem *salt)
+{
+    SECAlgorithmID *algid = NULL;
+    algid = sec_pkcs5CreateAlgorithmID(pbeAlgTag, cipherAlgTag, prfAlgTag,
+					NULL, keyLength, salt, iteration);
+    return algid;
+}
+
+/*
+ * private.
+ */
+PK11SymKey *
+pk11_RawPBEKeyGenWithKeyType(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, 
+			SECItem *params, CK_KEY_TYPE keyType, int keyLen,
+			SECItem *pwitem, void *wincx)
+{
+    CK_ULONG pwLen;
+    /* do some sanity checks */
+    if ((params == NULL) || (params->data == NULL)) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return NULL;
+    }
+
+    if (type == CKM_INVALID_MECHANISM) {
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	return NULL;
+    }
+
+    /* set the password pointer in the parameters... */
+    if (type == CKM_PKCS5_PBKD2) {
+    	CK_PKCS5_PBKD2_PARAMS *pbev2_params;
+	if (params->len < sizeof(CK_PKCS5_PBKD2_PARAMS)) {
+	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	    return NULL;
+	}
+	pbev2_params = (CK_PKCS5_PBKD2_PARAMS *)params->data;
+	pbev2_params->pPassword = pwitem->data;
+	pwLen = pwitem->len;
+	pbev2_params->ulPasswordLen = &pwLen;
+    } else {
+    	CK_PBE_PARAMS *pbe_params;
+	if (params->len < sizeof(CK_PBE_PARAMS)) {
+	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	    return NULL;
+	}
+	pbe_params = (CK_PBE_PARAMS *)params->data;
+	pbe_params->pPassword = pwitem->data;
+	pbe_params->ulPasswordLen = pwitem->len;
+    }
+
+    /* generate the key (and sometimes the IV as a side effect...) */
+    return pk11_TokenKeyGenWithFlagsAndKeyType(slot, type, params, keyType, 
+	   keyLen, NULL, CKF_SIGN|CKF_ENCRYPT|CKF_DECRYPT|CKF_UNWRAP|CKF_WRAP, 
+	   0, wincx);
+}
+
+/*
+ * public, deprecated. use PK11_PBEKeyGen instead.
+ */
+PK11SymKey *
+PK11_RawPBEKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *mech,
+			 SECItem *pwitem, PRBool faulty3DES, void *wincx)
+{
+    if(faulty3DES && (type == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC)) {
+	type = CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC;
+    }
+    return pk11_RawPBEKeyGenWithKeyType(slot, type, mech, -1, 0, pwitem, wincx);
+}
+
+/*
+ * pubic, supports pkcs5 v2.
+ *
+ * Create symkey from a PBE key. The algid can be created with
+ *  PK11_CreatePBEV2AlgorithmID and PK11_CreatePBEAlgorithmID, or by
+ *  extraction of der data.
+ */
+PK11SymKey *
+PK11_PBEKeyGen(PK11SlotInfo *slot, SECAlgorithmID *algid, SECItem *pwitem,
+	       					PRBool faulty3DES, void *wincx)
+{
+    CK_MECHANISM_TYPE type;
+    SECItem *param = NULL;
+    PK11SymKey *symKey = NULL;
+    SECOidTag	pbeAlg;
+    CK_KEY_TYPE keyType = -1;
+    int keyLen = 0;
+
+    pbeAlg = SECOID_GetAlgorithmTag(algid);
+    /* if we're using PKCS5v2, extract the additional information we need
+     * (key length, key type, and pbeAlg). */
+    if (sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(pbeAlg)) {
+	CK_MECHANISM_TYPE cipherMech;
+	sec_pkcs5V2Parameter *pbeV2_param;
+
+	pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid);
+	if (pbeV2_param == NULL) {
+	    return NULL;
+	}
+	cipherMech = PK11_AlgtagToMechanism(
+		SECOID_GetAlgorithmTag(&pbeV2_param->cipherAlgId));
+	pbeAlg = SECOID_GetAlgorithmTag(&pbeV2_param->pbeAlgId);
+	param = PK11_ParamFromAlgid(&pbeV2_param->pbeAlgId);
+	sec_pkcs5_v2_destroy_v2_param(pbeV2_param);
+	keyLen = SEC_PKCS5GetKeyLength(algid);
+	if (keyLen == -1) {
+	    keyLen = 0;
+	}
+	keyType = PK11_GetKeyType(cipherMech, keyLen);
+    } else {
+	param = PK11_ParamFromAlgid(algid);
+    }
+
+    if(param == NULL) {
+	goto loser;
+    }
+
+    type = PK11_AlgtagToMechanism(pbeAlg);	
+    if (type == CKM_INVALID_MECHANISM) {
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	goto loser;
+    }
+    if(faulty3DES && (type == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC)) {
+	type = CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC;
+    }
+    symKey = pk11_RawPBEKeyGenWithKeyType(slot, type, param, keyType, keyLen, 
+					pwitem, wincx);
+
+loser:
+    if (param) {
+	SECITEM_ZfreeItem(param, PR_TRUE);
+    }
+    return symKey;
+}
+
+/*
+ * public, supports pkcs5v2
+ */
+SECItem *
+PK11_GetPBEIV(SECAlgorithmID *algid, SECItem *pwitem)
+{
+    return SEC_PKCS5GetIV(algid, pwitem, PR_FALSE);
+}
+
+CK_MECHANISM_TYPE
+pk11_GetPBECryptoMechanism(SECAlgorithmID *algid, SECItem **param, 
+			   SECItem *pbe_pwd, PRBool faulty3DES)
+{
+    int keyLen = 0;
+    SECOidTag algTag = SEC_PKCS5GetCryptoAlgorithm(algid);
+    CK_MECHANISM_TYPE mech = PK11_AlgtagToMechanism(algTag);
+    CK_MECHANISM_TYPE returnedMechanism = CKM_INVALID_MECHANISM;
+    SECItem *iv = NULL;
+
+    if (mech == CKM_INVALID_MECHANISM) {
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	goto loser;
+    }
+    if (PK11_GetIVLength(mech)) {
+	iv = SEC_PKCS5GetIV(algid, pbe_pwd, faulty3DES);
+	if (iv == NULL) {
+	    goto loser;
+	}
+    }
+
+    keyLen = SEC_PKCS5GetKeyLength(algid);
+
+    *param = pk11_ParamFromIVWithLen(mech, iv, keyLen);
+    if (*param == NULL) {
+	goto loser;
+    }
+    returnedMechanism = mech;
+
+loser:
+    if (iv) {
+	SECITEM_FreeItem(iv,PR_TRUE);
+    }
+    return returnedMechanism;
+}
+
+/*
+ * Public, supports pkcs5 v2
+ *
+ * Get the crypto mechanism directly from the pbe algorithmid.
+ *
+ * It's important to go directly from the algorithm id so that we can
+ * handle both the PKCS #5 v1, PKCS #12, and PKCS #5 v2 cases.
+ *
+ * This function returns both the mechanism and the parameter for the mechanism.
+ * The caller is responsible for freeing the parameter.
+ */
+CK_MECHANISM_TYPE
+PK11_GetPBECryptoMechanism(SECAlgorithmID *algid, SECItem **param, 
+			   SECItem *pbe_pwd)
+{
+    return pk11_GetPBECryptoMechanism(algid, param, pbe_pwd, PR_FALSE);
+}
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)