secpkcs5.c

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

C
1,828
字号
{    if(pbe_param != NULL)	PORT_FreeArena(pbe_param->poolp, PR_TRUE);}/* crypto routines *//* function pointer template for crypto functions */typedef SECItem *(* pkcs5_crypto_func)(SECItem *key, SECItem *iv, 					 SECItem *src, PRBool op1, PRBool op2);/* map PBE algorithm to crypto algorithm */static SECOidTag sec_pkcs5_encryption_algorithm(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_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 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;	default:	    break;    }    return SEC_OID_UNKNOWN;}/* perform DES encryption and decryption.  these routines are called * by SEC_PKCS5CipherData.  In the case of an error, NULL is returned. */static SECItem *sec_pkcs5_des(SECItem *key, 	      SECItem *iv, 	      SECItem *src,	      PRBool triple_des, 	      PRBool encrypt){    SECItem *dest;    SECItem *dup_src;    SECStatus rv = SECFailure;    int pad;    if((src == NULL) || (key == NULL) || (iv == NULL))	return NULL;    dup_src = SECITEM_DupItem(src);    if(dup_src == NULL) {	return NULL;    }    if(encrypt != PR_FALSE) {	void *dummy;	dummy = DES_PadBuffer(NULL, dup_src->data, 	    dup_src->len, &dup_src->len);	if(dummy == NULL) {	    SECITEM_FreeItem(dup_src, PR_TRUE);	    return NULL;	}	dup_src->data = (unsigned char*)dummy;    }    dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    if(dest != NULL) {	/* allocate with over flow */	dest->data = (unsigned char *)PORT_ZAlloc(dup_src->len + 64);	if(dest->data != NULL) {	    DESContext *ctxt;	    ctxt = DES_CreateContext(key->data, iv->data, 			(triple_des ? NSS_DES_EDE3_CBC : NSS_DES_CBC), 			encrypt);		    if(ctxt != NULL) {		rv = ((encrypt != PR_TRUE) ? DES_Decrypt : DES_Encrypt)(			ctxt, dest->data, &dest->len,			dup_src->len + 64, dup_src->data, dup_src->len);		/* remove padding -- assumes 64 bit blocks */		if((encrypt == PR_FALSE) && (rv == SECSuccess)) {		    pad = dest->data[dest->len-1];		    if((pad > 0) && (pad <= 8)) {			if(dest->data[dest->len-pad] != pad) {			    rv = SECFailure;			    PORT_SetError(SEC_ERROR_BAD_PASSWORD);			} else {			    dest->len -= pad;			}		    } else {			rv = SECFailure;			PORT_SetError(SEC_ERROR_BAD_PASSWORD);		    }		}		DES_DestroyContext(ctxt, PR_TRUE);	    }	}    }    if(rv == SECFailure) {	if(dest != NULL) {	    SECITEM_FreeItem(dest, PR_TRUE);	}	dest = NULL;    }    if(dup_src != NULL) {	SECITEM_FreeItem(dup_src, PR_TRUE);    }    return dest;}/* perform rc2 encryption/decryption if an error occurs, NULL is returned */static SECItem *sec_pkcs5_rc2(SECItem *key, 	      SECItem *iv, 	      SECItem *src,	      PRBool cbc_mode, 	      PRBool encrypt){    SECItem *dest;    SECItem *dup_src;    SECStatus rv = SECFailure;    int pad;    if((src == NULL) || (key == NULL) || (iv == NULL)) {	return NULL;    }    dup_src = SECITEM_DupItem(src);    if(dup_src == NULL) {	return NULL;    }    if(encrypt != PR_FALSE) {	void *dummy;	dummy = DES_PadBuffer(NULL, dup_src->data, 			      dup_src->len, &dup_src->len);	if(dummy == NULL) {	    SECITEM_FreeItem(dup_src, PR_TRUE);	    return NULL;	}	dup_src->data = (unsigned char*)dummy;    }    dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    if(dest != NULL) {	dest->data = (unsigned char *)PORT_ZAlloc(dup_src->len + 64);	if(dest->data != NULL) {	    RC2Context *ctxt;	    ctxt = RC2_CreateContext(key->data, key->len, iv->data, 			((cbc_mode != PR_TRUE) ? NSS_RC2 : NSS_RC2_CBC), 			key->len);	    if(ctxt != NULL) {		rv = ((encrypt != PR_TRUE) ? RC2_Decrypt : RC2_Encrypt)(			ctxt, dest->data, &dest->len,			dup_src->len + 64, dup_src->data, dup_src->len);		/* assumes 8 byte blocks  -- remove padding */			if((rv == SECSuccess) && (encrypt != PR_TRUE) && 			(cbc_mode == PR_TRUE)) {		    pad = dest->data[dest->len-1];		    if((pad > 0) && (pad <= 8)) {			if(dest->data[dest->len-pad] != pad) {			    PORT_SetError(SEC_ERROR_BAD_PASSWORD);			    rv = SECFailure;			} else {			    dest->len -= pad;			}		    } else {			PORT_SetError(SEC_ERROR_BAD_PASSWORD);			rv = SECFailure;		    }		}	    }	}    }    if((rv != SECSuccess) && (dest != NULL)) {	SECITEM_FreeItem(dest, PR_TRUE);	dest = NULL;    }    if(dup_src != NULL) {	SECITEM_FreeItem(dup_src, PR_TRUE);    }    return dest;}/* perform rc4 encryption and decryption */static SECItem *sec_pkcs5_rc4(SECItem *key, 	      SECItem *iv, 	      SECItem *src, 	      PRBool dummy_op,	      PRBool encrypt){    SECItem *dest;    SECStatus rv = SECFailure;    if((src == NULL) || (key == NULL) || (iv == NULL)) {	return NULL;    }    dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    if(dest != NULL) {	dest->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) *	    (src->len + 64));	if(dest->data != NULL) {	    RC4Context *ctxt;	    ctxt = RC4_CreateContext(key->data, key->len);	    if(ctxt) { 		rv = ((encrypt != PR_FALSE) ? RC4_Decrypt : RC4_Encrypt)(				ctxt, dest->data, &dest->len,				src->len + 64, src->data, src->len);		RC4_DestroyContext(ctxt, PR_TRUE);	    }	}    }    if((rv != SECSuccess) && (dest)) {	SECITEM_FreeItem(dest, PR_TRUE);	dest = NULL;    }    return dest;}/* performs the cipher operation on the src and returns the result. * if an error occurs, NULL is returned.  * * a null length password is allowed.  this corresponds to encrypting * the data with ust the salt. *//* change this to use PKCS 11? */SECItem *SEC_PKCS5CipherData(SECAlgorithmID *algid, 		    SECItem *pwitem,		    SECItem *src, 		    PRBool encrypt, PRBool *update){    SEC_PKCS5PBEParameter *pbe_param;    SECOidTag enc_alg;    SECItem *key = NULL, *iv = NULL;    SECItem *dest = NULL;    int iv_len;    if (update) {         *update = PR_FALSE;    }    if((algid == NULL) || (pwitem == NULL) || (src == NULL)) {	return NULL;    }    /* convert algid to pbe parameter */    pbe_param = sec_pkcs5_convert_algid(algid);    if(pbe_param == NULL) {	return NULL;    }    /* get algorithm, key, and iv */    enc_alg = sec_pkcs5_encryption_algorithm(pbe_param->algorithm);    key = sec_pkcs5_compute_key(pbe_param, pwitem, PR_FALSE);    if(key != NULL) {	iv_len = sec_pkcs5_iv_length(pbe_param->algorithm);    	iv = sec_pkcs5_compute_iv(pbe_param, pwitem, PR_FALSE);	if((iv != NULL) || (iv_len == 0)) {	    /*perform encryption / decryption */	    PRBool op1 = PR_TRUE;	    pkcs5_crypto_func cryptof;	    switch(enc_alg) {		case SEC_OID_DES_EDE3_CBC:		    cryptof = sec_pkcs5_des;		    break;		case SEC_OID_DES_CBC:		    cryptof = sec_pkcs5_des;		    op1 = PR_FALSE;		    break;		case SEC_OID_RC2_CBC:		    cryptof = sec_pkcs5_rc2;		    break;		case SEC_OID_RC4:		    cryptof = sec_pkcs5_rc4;		    break;		default:		    cryptof = NULL;		    break;	    }	    if(cryptof) {		dest = (*cryptof)(key, iv, src, op1, encrypt);		/* 		 * it's possible for some keys and keydb's to claim to		 * be triple des when they're really des. In this case		 * we simply try des. If des works we set the update flag		 * so the key db knows it needs to update all it's entries.		 *  The case can only happen on decrypted of a 		 *  SEC_OID_DES_EDE3_CBD.		 */		if ((dest == NULL) && (encrypt == PR_FALSE) && 					(enc_alg == SEC_OID_DES_EDE3_CBC)) {		    dest = (*cryptof)(key, iv, src, PR_FALSE, encrypt);		    if (update && (dest != NULL)) *update = PR_TRUE;		}	    }	}    }    sec_pkcs5_destroy_pbe_param(pbe_param);    if(key != NULL) {	SECITEM_ZfreeItem(key, PR_TRUE);    }    if(iv != NULL) {	SECITEM_ZfreeItem(iv, PR_TRUE);    }    return dest;}/* 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.  if IV is specified, it overrides * the PKCS 5 generation of the IV.   * * the returned SECAlgorithmID should be destroyed using  * SECOID_DestroyAlgorithmID */SECAlgorithmID *SEC_PKCS5CreateAlgorithmID(SECOidTag algorithm, 			   SECItem *salt, 			   int iteration){    PRArenaPool *poolp = NULL;    SECAlgorithmID *algid, *ret_algid;    SECItem der_param;    SECStatus rv = SECFailure;    SEC_PKCS5PBEParameter *pbe_param;    if(sec_pkcs5_hash_algorithm(algorithm) == SEC_OID_UNKNOWN)	return NULL;    if(iteration <= 0) {	return NULL;    }    der_param.data = NULL;    der_param.len = 0;    /* generate the parameter */    pbe_param = sec_pkcs5_create_pbe_parameter(algorithm, salt, iteration);    if(!pbe_param) {	return NULL;    }    poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);    if(!poolp) {	sec_pkcs5_destroy_pbe_param(pbe_param);	return NULL;    }    /* generate the algorithm id */    algid = (SECAlgorithmID *)PORT_ArenaZAlloc(poolp, sizeof(SECAlgorithmID));    if(algid != NULL) {	void *dummy;	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) {	    rv = SECOID_SetAlgorithmID(poolp, algid, algorithm, &der_param);	}    }    ret_algid = NULL;    if(algid != NULL) {	ret_algid = (SECAlgorithmID *)PORT_ZAlloc(sizeof(SECAlgorithmID));	if(ret_algid != NULL) {	    rv = SECOID_CopyAlgorithmID(NULL, ret_algid, algid);	    if(rv != SECSuccess) {		SECOID_DestroyAlgorithmID(ret_algid, PR_TRUE);		ret_algid = NULL;	    }	}    }	    if(poolp != NULL) {	PORT_FreeArena(poolp, PR_TRUE);	algid = NULL;    }    sec_pkcs5_destroy_pbe_param(pbe_param);    return ret_algid;}/* wrapper for converting the algid to a pbe parameter.  */SEC_PKCS5PBEParameter *SEC_PKCS5GetPBEParameter(SECAlgorithmID *algid){    if(algid) {	return sec_pkcs5_convert_algid(algid);    }    return NULL;}/* destroy a pbe parameter */voidSEC_PKCS5DestroyPBEParameter(SEC_PKCS5PBEParameter *pbe_param){    sec_pkcs5_destroy_pbe_param(pbe_param);}/* return the initialization vector either the preset one if it  * exists or generated based on pkcs 5. * * a null length password is allowed...but not a null password * secitem. */SECItem *SEC_PKCS5GetIV(SECAlgorithmID *algid, SECItem *pwitem, PRBool faulty3DES){    SECItem *iv;    SEC_PKCS5PBEParameter *pbe_param;    if((algid == NULL) || (pwitem == NULL)) {	return NULL;

⌨️ 快捷键说明

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