secpkcs5.c

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

C
1,828
字号
	 * further, so we are doing it correctly, but reading the old method.	 */	if(faulty3DES) {	    pre_hash->len = ph_len;	} else {	    pre_hash->len = salt->len + pwd->len;	}	/* preform hash */	if((hash->data != NULL) && (pre_hash->data != NULL)) {	    rv = SECSuccess;	    /* check for 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 < iter) && (rv == SECSuccess)); i++) {		rv = SHA1_HashBuf(hash->data, pre_hash->data, pre_hash->len);		if(rv != SECFailure) {		    pre_hash->len = SHA1_LENGTH;		    PORT_Memcpy(pre_hash->data, hash->data, SHA1_LENGTH);		}	    }	}    }    if(pre_hash != NULL) {	SECITEM_FreeItem(pre_hash, PR_TRUE);    }    if((rv != SECSuccess) && (hash != NULL)) {	SECITEM_FreeItem(hash, PR_TRUE);	hash = NULL;    }    return hash;}/* bit generation/key and iv generation routines. */typedef SECItem *(* sec_pkcs5_hash_func)(SECItem *s, SECItem *p, 					 int iter, PRBool faulty3DES);/* generates bits needed for the key and iv based on PKCS 5, * be concatenating the password and salt and using the appropriate * hash algorithm.  This function serves as a front end to the  * specific hash functions above.  a return of NULL indicates an * error. */static SECItem *sec_pkcs5_compute_hash(SEC_PKCS5PBEParameter *pbe_param, SECItem *pwitem,		       PRBool faulty3DES){    sec_pkcs5_hash_func hash_func;    SECOidTag hash_alg;    SECItem *hash = NULL;    SECItem *salt = NULL;	    hash_alg = sec_pkcs5_hash_algorithm(pbe_param->algorithm);    salt = &(pbe_param->salt);    switch(hash_alg)    {	case SEC_OID_SHA1:	    hash_func = sec_pkcs5_compute_sha1_hash;	    break;	case SEC_OID_MD2:	    hash_func = sec_pkcs5_compute_md2_hash;	    break;	case SEC_OID_MD5:	    hash_func = sec_pkcs5_compute_md5_hash;	    break;	default:	    hash_func = NULL;    }    if(hash_func) {	hash = (* hash_func)(salt, pwitem, pbe_param->iter, faulty3DES);    }    return hash;}/* determines the number of bits needed for key and iv generation * based upon the algorithm identifier.  if a number of * bits greater than the hash algorithm can produce are needed, * the bits will be generated based upon the extended PKCS 5  * described in PKCS 12. * * a return of -1 indicates an error. */static int sec_pkcs5_bits_needed(SEC_PKCS5PBEParameter *pbe_param){    int iv_bits;    int key_bits;        if(pbe_param == NULL) {	return -1;    }    iv_bits = sec_pkcs5_iv_length(pbe_param->algorithm) * 8;    key_bits = sec_pkcs5_key_length(pbe_param->algorithm) * 8;    if(key_bits != 0) {	return iv_bits + key_bits;    }    return -1;}/* determines the number of bits generated by each hash algorithm. * in case of an error, -1 is returned.  */static intsec_pkcs5_hash_bits_generated(SEC_PKCS5PBEParameter *pbe_param){    if(pbe_param == NULL) {	return -1;    }    switch(sec_pkcs5_hash_algorithm(pbe_param->algorithm)) {	case SEC_OID_SHA1:	    return SHA1_LENGTH * 8;	case SEC_OID_MD2:	    return MD2_LENGTH * 8;	case SEC_OID_MD5:	    return MD5_LENGTH * 8;	default:	    break;    }    return -1;}/* this bit generation routine is described in PKCS 12 and the proposed * extensions to PKCS 5.  an initial hash is generated following the * instructions laid out in PKCS 5.  If the number of bits generated is * insufficient, then the method discussed in the proposed extensions to * PKCS 5 in PKCS 12 are used.  This extension makes use of the HMAC * function.  And the P_Hash function from the TLS standard. */static SECItem *sec_pkcs5_bit_generator(SEC_PKCS5PBEParameter *pbe_param,			SECItem *init_hash, 			unsigned int bits_needed){    SECItem *ret_bits = NULL;    int hash_size = 0;    unsigned int i;    unsigned int hash_iter;    unsigned int dig_len;    SECStatus rv = SECFailure;    unsigned char *state = NULL;    unsigned int state_len;    HMACContext *cx = NULL;    hash_size = sec_pkcs5_hash_bits_generated(pbe_param);    if(hash_size == -1)	return NULL;    hash_iter = (bits_needed + (unsigned int)hash_size - 1) / hash_size;    hash_size /= 8;    /* allocate return buffer */    ret_bits = (SECItem  *)PORT_ZAlloc(sizeof(SECItem));    if(ret_bits == NULL)	return NULL;    ret_bits->data = (unsigned char *)PORT_ZAlloc((hash_iter * hash_size) + 1);    ret_bits->len = (hash_iter * hash_size);    if(ret_bits->data == NULL) {	PORT_Free(ret_bits);	return NULL;    }    /* allocate intermediate hash buffer.  8 is for the 8 bytes of     * data which are added based on iteration number      */    if ((unsigned int)hash_size > pbe_param->salt.len) {	state_len = hash_size;    } else {	state_len = pbe_param->salt.len;    }    state = (unsigned char *)PORT_ZAlloc(state_len);    if(state == NULL) {	rv = SECFailure;	goto loser;    }    if(pbe_param->salt.len > 0) {	PORT_Memcpy(state, pbe_param->salt.data, pbe_param->salt.len);    }    cx = HMAC_Create(sec_pkcs5_hash_algorithm(pbe_param->algorithm),		     init_hash->data, init_hash->len);    if (cx == NULL) {	rv = SECFailure;	goto loser;    }    for(i = 0; i < hash_iter; i++) { 	/* generate output bits */	HMAC_Begin(cx);	HMAC_Update(cx, state, state_len);	HMAC_Update(cx, pbe_param->salt.data, pbe_param->salt.len);	rv = HMAC_Finish(cx, ret_bits->data + (i * hash_size),			 &dig_len, hash_size);	if (rv != SECSuccess)	    goto loser;	PORT_Assert((unsigned int)hash_size == dig_len);	/* generate new state */	HMAC_Begin(cx);	HMAC_Update(cx, state, state_len);	rv = HMAC_Finish(cx, state, &state_len, state_len);	if (rv != SECSuccess)	    goto loser;	PORT_Assert(state_len == dig_len);    }loser:    if (state != NULL)	PORT_ZFree(state, state_len);    HMAC_Destroy(cx);    if(rv != SECSuccess) {	SECITEM_ZfreeItem(ret_bits, PR_TRUE);	ret_bits = NULL;    }    return ret_bits;}/* generate bits for the key and iv determination.  if enough bits * are not generated using PKCS 5, then we need to generate more bits * based on the extension proposed in PKCS 12 */static SECItem *sec_pkcs5_generate_bits(SEC_PKCS5PBEParameter *pbe_param, SECItem *pwitem, 			PRBool faulty3DES){    SECItem * hash 		= NULL;    SECItem * newHash 		= NULL;    int       bits_needed;    int       bits_available;        bits_needed = sec_pkcs5_bits_needed(pbe_param);    bits_available = sec_pkcs5_hash_bits_generated(pbe_param);    if((bits_needed == -1) || (bits_available == -1)) {	return NULL;    }    hash = sec_pkcs5_compute_hash(pbe_param, pwitem, faulty3DES);    if(hash == NULL) {	return NULL;    }    if(bits_needed <= bits_available) {	return hash;    }     newHash = sec_pkcs5_bit_generator(pbe_param, hash, bits_needed);    if (hash != newHash)	SECITEM_FreeItem(hash, PR_TRUE);    return newHash;}/* compute the IV as per PKCS 5 */static SECItem *sec_pkcs5_compute_iv(SEC_PKCS5PBEParameter *pbe_param, SECItem *pwitem,		     PRBool faulty3DES){    SECItem *hash = NULL, *iv = NULL;    if((pbe_param == NULL) || (pwitem == NULL)) {	return NULL;    }    /* generate iv */    iv = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    if(!iv) {	return NULL;    }    iv->len = sec_pkcs5_iv_length(pbe_param->algorithm);    if(iv->len == -1) {	PORT_Free(iv);	return NULL;    }    iv->data = (unsigned char *)PORT_ZAlloc(iv->len);    if(iv->data == NULL) {	PORT_Free(iv);	return NULL;    }    if(sec_pkcs5_is_algorithm_v2_pkcs12_algorithm(pbe_param->algorithm)) {	SECOidTag hashAlg;	PBEBitGenContext *ctxt;	hashAlg = sec_pkcs5_hash_algorithm(pbe_param->algorithm);	ctxt = PBE_CreateContext(hashAlg, pbeBitGenCipherIV,				 pwitem, &pbe_param->salt,				 iv->len * 8, pbe_param->iter);	if(!ctxt) {	    SECITEM_FreeItem(iv, PR_TRUE);	    return NULL;	}	hash = PBE_GenerateBits(ctxt);	PBE_DestroyContext(ctxt);    } else {	hash = sec_pkcs5_generate_bits(pbe_param, pwitem, faulty3DES);    }    if(!hash) {	SECITEM_FreeItem(iv, PR_TRUE);	return NULL;    }    PORT_Memcpy(iv->data, (hash->data+(hash->len - iv->len)), iv->len);    SECITEM_FreeItem(hash, PR_TRUE);    return iv;}/* generate key as per PKCS 5 */static SECItem *sec_pkcs5_compute_key(SEC_PKCS5PBEParameter *pbe_param, SECItem *pwitem,		      PRBool faulty3DES){    SECItem *hash = NULL, *key = NULL;    if((pbe_param == NULL) || (pwitem == NULL)) {	return NULL;    }    key = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    if(!key) {	return NULL;    }    key->len = sec_pkcs5_key_length(pbe_param->algorithm);    if(key->len == -1) {	PORT_Free(key);	return NULL;    }	    key->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) *					     key->len);    if(!key->data) {	PORT_Free(key);	return NULL;    }    if(sec_pkcs5_is_algorithm_v2_pkcs12_algorithm(pbe_param->algorithm)) {	SECOidTag hashAlg;	PBEBitGenContext *ctxt;	hashAlg = sec_pkcs5_hash_algorithm(pbe_param->algorithm);	ctxt = PBE_CreateContext(hashAlg, pbeBitGenCipherKey,				 pwitem, &pbe_param->salt,				 key->len * 8, pbe_param->iter);	if(!ctxt) {	    SECITEM_FreeItem(key, PR_TRUE);	    return NULL;	}	hash = PBE_GenerateBits(ctxt);	PBE_DestroyContext(ctxt);    } else {	hash = sec_pkcs5_generate_bits(pbe_param, pwitem, faulty3DES);    }       if(!hash) {	SECITEM_FreeItem(key, PR_TRUE);	return NULL;    }    if(pbe_param->algorithm ==		   SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC) {	PORT_Memcpy(key->data, hash->data, (key->len * 2) / 3);	PORT_Memcpy(&(key->data[(key->len  * 2) / 3]), key->data,		    key->len / 3);    } else {	PORT_Memcpy(key->data, hash->data, key->len);    }    SECITEM_FreeItem(hash, PR_TRUE);    return key;}/* decode the algid and generate a PKCS 5 parameter from it */static SEC_PKCS5PBEParameter *sec_pkcs5_convert_algid(SECAlgorithmID *algid){    PRArenaPool *poolp;    SEC_PKCS5PBEParameter *pbe_param = NULL;    SECOidTag algorithm;    SECStatus rv = SECFailure;    if(algid == NULL)	return NULL;    algorithm = SECOID_GetAlgorithmTag(algid);       if(sec_pkcs5_hash_algorithm(algorithm) == SEC_OID_UNKNOWN)	return NULL;    poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);    if(poolp == NULL)	return NULL;    /* allocate memory for the parameter */    pbe_param = (SEC_PKCS5PBEParameter *)PORT_ArenaZAlloc(poolp, 	sizeof(SEC_PKCS5PBEParameter));    /* decode parameter */    if(pbe_param && !sec_pkcs5_is_algorithm_v2_pkcs12_algorithm(algorithm)) {	pbe_param->poolp = poolp;	rv = SEC_ASN1DecodeItem(poolp, pbe_param, 	    SEC_PKCS5PBEParameterTemplate, &algid->parameters);	if(rv != SECSuccess) {	    goto loser;	}	pbe_param->algorithm = algorithm;	pbe_param->iter = DER_GetInteger(&pbe_param->iteration);    } else if(sec_pkcs5_is_algorithm_v2_pkcs12_algorithm(algorithm)) {	pbe_param->algorithm = algorithm;	pbe_param->poolp = poolp;	rv = SEC_ASN1DecodeItem(poolp, pbe_param, SEC_V2PKCS12PBEParameterTemplate,				&algid->parameters);	if(rv != SECSuccess) {	    goto loser;	}	pbe_param->iter = DER_GetInteger(&pbe_param->iteration);    }loser:    if((pbe_param == NULL) || (rv != SECSuccess)) {	PORT_FreeArena(poolp, PR_TRUE);	pbe_param = NULL;    }    return pbe_param;}/* 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)

⌨️ 快捷键说明

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