secpkcs5.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,828 行 · 第 1/4 页

C
1,828
字号
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape security libraries. *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#include "plarena.h"#include "seccomon.h"#include "secitem.h"#include "secport.h"#include "hasht.h"#include "pkcs11t.h"#include "blapi.h"#include "sechash.h"#include "secasn1.h"#include "secder.h"#include "secpkcs5.h"#include "secoid.h"#include "alghmac.h"#include "softoken.h"#include "secerr.h"#define DES_IV_LENGTH		8#define RC2_IV_LENGTH		8#define MD2_LENGTH		16#define MD5_LENGTH		16#define SHA1_LENGTH		20#define SEED_LENGTH 		16#define SALT_LENGTH		8#define PBE_SALT_LENGTH		16/* 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 }};pbeBitGenParameters pbeHashAlgorithmParams[] = {    {   0,   0, SEC_OID_UNKNOWN },    { 128, 512, SEC_OID_MD2 },    { 128, 512, SEC_OID_MD5 },    { 160, 512, SEC_OID_SHA1 },};/* generate some random bytes.  this is used to generate the  * salt if it is not specified. */static SECStatus sec_pkcs5_generate_random_bytes(PRArenaPool *poolp, 				SECItem *dest, int len){    SECStatus rv = SECFailure;    if(dest != NULL)    {	void *mark = PORT_ArenaMark(poolp);	dest->data = (unsigned char *)PORT_ArenaZAlloc(poolp, len);	if(dest->data != NULL)	{	    dest->len = len;	    RNG_GenerateGlobalRandomBytes(dest->data, dest->len);	    PORT_ArenaUnmark(poolp, mark);	    rv = SECSuccess;	} else	    PORT_ArenaRelease(poolp, mark);    }    return rv;}/* maps hash algorithm from PBE algorithm. */static SECOidTag sec_pkcs5_hash_algorithm(SECOidTag algorithm){    switch(algorithm)    {	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC:	case SEC_OID_PKCS5_PBE_WITH_SHA1_AND_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_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:	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 SEC_OID_SHA1;	case SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC:	    return SEC_OID_MD5;	case SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC:	    return SEC_OID_MD2;	default:	    break;    }    return SEC_OID_UNKNOWN;}/* get the iv length needed for the PBE algorithm  */static int sec_pkcs5_iv_length(SECOidTag algorithm){    switch(algorithm)    {	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC:	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:	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:	    return DES_IV_LENGTH;	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_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:	case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:	    return RC2_IV_LENGTH;	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 0;	default:	    break;    }    return -1;}/* get the key length needed for the PBE algorithm */static int sec_pkcs5_key_length(SECOidTag algorithm){    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;	default:	    break;    }    return -1;}/* the V2 algorithms only encode the salt, there is no iteration * count so we need a check for V2 algorithm parameters. */static PRBoolsec_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;}/* 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 keyLen 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. *   keyLen - only used in variable key length algorithms *   iv - if null, the IV will be generated based on PKCS 5 when needed. *   params - optional, currently unsupported additional parameters. * once a parameter is allocated, it should be destroyed calling  * sec_pkcs5_destroy_pbe_parameter or SEC_PKCS5DestroyPBEParameter. */static SEC_PKCS5PBEParameter *sec_pkcs5_create_pbe_parameter(SECOidTag algorithm, 			SECItem *salt, 			int iteration){    PRArenaPool *poolp = NULL;    SEC_PKCS5PBEParameter *pbe_param = NULL;    SECStatus rv;     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;    pbe_param->algorithm = algorithm;    /* should we generate the salt? */    if(!salt || !salt->data) {	rv = sec_pkcs5_generate_random_bytes(poolp, &pbe_param->salt, 						SALT_LENGTH);    } else {	rv = SECITEM_CopyItem(poolp, &pbe_param->salt, salt);    }    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;    }    return pbe_param;}/* generate bits for key and iv using MD5 hashing  */static SECItem *sec_pkcs5_compute_md5_hash(SECItem *salt, SECItem *pwd, int iter,			   PRBool dummy){    SECItem *hash = NULL, *pre_hash = NULL;    SECStatus rv = SECFailure;    if((salt == NULL) || (pwd == NULL) || (iter < 0)) {	return NULL;    }	    hash = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    pre_hash = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    if((hash != NULL) && (pre_hash != NULL)) {	unsigned int i, ph_len;	ph_len = MD5_LENGTH;	if(ph_len < (salt->len + pwd->len)) {	    ph_len = salt->len + pwd->len;	}	rv = SECFailure;	hash->data = (unsigned char *)PORT_ZAlloc(MD5_LENGTH);	hash->len = MD5_LENGTH;	pre_hash->data = (unsigned char *)PORT_ZAlloc(ph_len);	pre_hash->len = salt->len + pwd->len;	if((hash->data != NULL) && (pre_hash->data != NULL)) {	    rv = SECSuccess;	    /* handle 0 length password */	    if(pwd->len > 0) {		PORT_Memcpy(pre_hash->data, pwd->data, pwd->len);	    }	    if(salt->len > 0) {	 	PORT_Memcpy((pre_hash->data+pwd->len), salt->data, salt->len);	    }	    for(i = 0; ((i < (unsigned int)iter) && (rv == SECSuccess)); i++) {		rv = MD5_HashBuf(hash->data, pre_hash->data, pre_hash->len);		if(rv != SECFailure) {		    PORT_Memcpy(pre_hash->data, hash->data, MD5_LENGTH);		    pre_hash->len = MD5_LENGTH;		}	    }	}    }    if(pre_hash != NULL)	SECITEM_FreeItem(pre_hash, PR_TRUE);    if((rv == SECFailure) && (hash)) {	SECITEM_FreeItem(hash, PR_TRUE);	hash = NULL;    }    return hash;}/* generate bits for key and iv using MD2 hashing  */static SECItem *sec_pkcs5_compute_md2_hash(SECItem *salt, SECItem *pwd, int iter,			   PRBool dummy){    SECItem *hash = NULL, *pre_hash = NULL;    SECStatus rv = SECFailure;    if((salt == NULL) || (pwd == NULL) || (iter < 0))	return NULL;    hash = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    pre_hash = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    if((hash != NULL) && (pre_hash != NULL))    {	int i, ph_len;	ph_len = MD2_LENGTH;	if((salt->len + pwd->len) > MD2_LENGTH)	    ph_len = salt->len+pwd->len;	rv = SECFailure;	hash->data = (unsigned char *)PORT_ZAlloc(MD2_LENGTH);	hash->len = MD2_LENGTH;	pre_hash->data = (unsigned char *)PORT_ZAlloc(ph_len);	pre_hash->len = salt->len + pwd->len;	if((hash->data != NULL) && (pre_hash->data != NULL))	{	    MD2Context *ctxt;	    rv = SECSuccess;	    if(pwd->len > 0) {		PORT_Memcpy(pre_hash->data, pwd->data, pwd->len);	    }	    if(salt->len > 0) {		PORT_Memcpy((pre_hash->data+pwd->len), salt->data, salt->len);	    }	    for(i = 0; ((i < iter) && (rv == SECSuccess)); i++)	    {		ctxt = MD2_NewContext();		if(ctxt == NULL)		    rv = SECFailure;				else		{		    MD2_Update(ctxt, pre_hash->data, pre_hash->len);		    MD2_End(ctxt, hash->data, &hash->len, hash->len);		    PORT_Memcpy(pre_hash->data, hash->data, MD2_LENGTH);		    pre_hash->len = MD2_LENGTH;		    MD2_DestroyContext(ctxt, PR_TRUE);		}	    }			}    }    if(pre_hash != NULL)	SECITEM_FreeItem(pre_hash, PR_TRUE);    if(rv != SECSuccess)	if(hash != NULL)	{	    SECITEM_FreeItem(hash, PR_TRUE);	    hash = NULL;	}    return hash;}/* generate bits using SHA1 hash  */static SECItem *sec_pkcs5_compute_sha1_hash(SECItem *salt, SECItem *pwd, int iter, 			    PRBool faulty3DES) {    SECItem *hash = NULL, *pre_hash = NULL;    SECStatus rv = SECFailure;    if((salt == NULL) || (pwd == NULL) || (iter < 0)) {	return NULL;    }	    hash = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    pre_hash = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    if((hash != NULL) && (pre_hash != NULL)) {	int i, ph_len;	ph_len = SHA1_LENGTH;	if((salt->len + pwd->len) > SHA1_LENGTH) {	    ph_len = salt->len + pwd->len;	}	rv = SECFailure;	/* allocate buffers */	hash->data = (unsigned char *)PORT_ZAlloc(SHA1_LENGTH);	hash->len = SHA1_LENGTH;	pre_hash->data = (unsigned char *)PORT_ZAlloc(ph_len);	/* in pbeSHA1TripleDESCBC there was an allocation error that made	 * it into the caller.  We do not want to propagate those errors

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?