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 + -
显示快捷键?