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