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