static SECItem * crmf_get_iv(CK_MECHANISM_TYPE mechType) { int iv_size = PK11_GetIVLength(mechType); SECItem *iv; SECStatus rv; iv = PORT_ZNew(SECItem); if (iv == NULL) { return NULL; } if (iv_size == 0) { iv->data = NULL; iv->len = 0; return iv; } iv->data = PORT_NewArray(unsigned char, iv_size); if (iv->data == NULL) { iv->len = 0; return iv; } iv->len = iv_size; rv = PK11_GenerateRandom(iv->data, iv->len); if (rv != SECSuccess) { PORT_Free(iv->data); iv->data = NULL; iv->len = 0; } return iv; }
/* * Generate an IV for the given mechanism */ static SECStatus pk11_GenIV(CK_MECHANISM_TYPE type, SECItem *iv) { int iv_size = PK11_GetIVLength(type); SECStatus rv; iv->len = iv_size; if (iv_size == 0) { iv->data = NULL; return SECSuccess; } iv->data = (unsigned char *) PORT_Alloc(iv_size); if (iv->data == NULL) { iv->len = 0; return SECFailure; } rv = PK11_GenerateRandom(iv->data,iv->len); if (rv != SECSuccess) { PORT_Free(iv->data); iv->data = NULL; iv->len = 0; return SECFailure; } return SECSuccess; }
CK_RV PK11_MapPBEMechanismToCryptoMechanism(CK_MECHANISM_PTR pPBEMechanism, CK_MECHANISM_PTR pCryptoMechanism, SECItem *pbe_pwd, PRBool faulty3DES) { int iv_len = 0; CK_PBE_PARAMS_PTR pPBEparams; CK_RC2_CBC_PARAMS_PTR rc2_params; CK_ULONG rc2_key_len; if((pPBEMechanism == CK_NULL_PTR) || (pCryptoMechanism == CK_NULL_PTR)) { return CKR_HOST_MEMORY; } /* pkcs5 v2 cannot be supported by this interface. * use PK11_GetPBECryptoMechanism instead. */ if ((pPBEMechanism->mechanism == CKM_INVALID_MECHANISM) || (pPBEMechanism->mechanism == CKM_PKCS5_PBKD2)) { return CKR_MECHANISM_INVALID; } pPBEparams = (CK_PBE_PARAMS_PTR)pPBEMechanism->pParameter; iv_len = PK11_GetIVLength(pPBEMechanism->mechanism); if (iv_len) { if (pk11_isAllZero(pPBEparams->pInitVector,iv_len)) { SECItem param; PK11SymKey *symKey; PK11SlotInfo *intSlot = PK11_GetInternalSlot(); if (intSlot == NULL) { return CKR_DEVICE_ERROR; } param.data = pPBEMechanism->pParameter; param.len = pPBEMechanism->ulParameterLen; symKey = PK11_RawPBEKeyGen(intSlot, pPBEMechanism->mechanism, ¶m, pbe_pwd, faulty3DES, NULL); PK11_FreeSlot(intSlot); if (symKey== NULL) { return CKR_DEVICE_ERROR; /* sigh */ } PK11_FreeSymKey(symKey); } } switch(pPBEMechanism->mechanism) { case CKM_PBE_MD2_DES_CBC: case CKM_PBE_MD5_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_DES_CBC: pCryptoMechanism->mechanism = CKM_DES_CBC; goto have_crypto_mechanism; case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: case CKM_PBE_SHA1_DES3_EDE_CBC: case CKM_PBE_SHA1_DES2_EDE_CBC: pCryptoMechanism->mechanism = CKM_DES3_CBC; have_crypto_mechanism: pCryptoMechanism->pParameter = PORT_Alloc(iv_len); pCryptoMechanism->ulParameterLen = (CK_ULONG)iv_len; if(pCryptoMechanism->pParameter == NULL) { return CKR_HOST_MEMORY; } PORT_Memcpy((unsigned char *)(pCryptoMechanism->pParameter), (unsigned char *)(pPBEparams->pInitVector), iv_len); break; case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: case CKM_PBE_SHA1_RC4_40: case CKM_PBE_SHA1_RC4_128: pCryptoMechanism->mechanism = CKM_RC4; pCryptoMechanism->ulParameterLen = 0; pCryptoMechanism->pParameter = CK_NULL_PTR; break; case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: case CKM_PBE_SHA1_RC2_40_CBC: rc2_key_len = 40; goto have_key_len; case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: rc2_key_len = 128; have_key_len: pCryptoMechanism->mechanism = CKM_RC2_CBC; pCryptoMechanism->ulParameterLen = (CK_ULONG) sizeof(CK_RC2_CBC_PARAMS); pCryptoMechanism->pParameter = (CK_RC2_CBC_PARAMS_PTR) PORT_ZAlloc(sizeof(CK_RC2_CBC_PARAMS)); if(pCryptoMechanism->pParameter == NULL) { return CKR_HOST_MEMORY; } rc2_params = (CK_RC2_CBC_PARAMS_PTR)pCryptoMechanism->pParameter; PORT_Memcpy((unsigned char *)rc2_params->iv, (unsigned char *)pPBEparams->pInitVector, iv_len); rc2_params->ulEffectiveBits = rc2_key_len; break; default: return CKR_MECHANISM_INVALID; } return CKR_OK; }
/** * @brief Create a key from the given passphrase. By default, the PBKDF2 * algorithm is used to generate the key from the passphrase. It is expected * that the same pass phrase will generate the same key, regardless of the * backend crypto platform used. The key is cleaned up when the context * is cleaned, and may be reused with multiple encryption or decryption * operations. * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If * *key is not NULL, *key must point at a previously created structure. * @param key The key returned, see note. * @param ivSize The size of the initialisation vector will be returned, based * on whether an IV is relevant for this type of crypto. * @param pass The passphrase to use. * @param passLen The passphrase length in bytes * @param salt The salt to use. * @param saltLen The salt length in bytes * @param type 3DES_192, AES_128, AES_192, AES_256. * @param mode Electronic Code Book / Cipher Block Chaining. * @param doPad Pad if necessary. * @param iterations Iteration count * @param f The context to use. * @param p The pool to use. * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend * error occurred while generating the key. APR_ENOCIPHER if the type or mode * is not supported by the particular backend. APR_EKEYTYPE if the key type is * not known. APR_EPADDING if padding was requested but is not supported. * APR_ENOTIMPL if not implemented. */ static apr_status_t crypto_passphrase(apr_crypto_key_t **k, apr_size_t *ivSize, const char *pass, apr_size_t passLen, const unsigned char * salt, apr_size_t saltLen, const apr_crypto_block_key_type_e type, const apr_crypto_block_key_mode_e mode, const int doPad, const int iterations, const apr_crypto_t *f, apr_pool_t *p) { apr_status_t rv = APR_SUCCESS; PK11SlotInfo * slot; SECItem passItem; SECItem saltItem; SECAlgorithmID *algid; void *wincx = NULL; /* what is wincx? */ apr_crypto_key_t *key = *k; if (!key) { *k = key = apr_array_push(f->keys); } if (!key) { return APR_ENOMEM; } key->f = f; key->provider = f->provider; /* decide on what cipher mechanism we will be using */ switch (type) { case (APR_KEY_3DES_192): if (APR_MODE_CBC == mode) { key->cipherOid = SEC_OID_DES_EDE3_CBC; } else if (APR_MODE_ECB == mode) { return APR_ENOCIPHER; /* No OID for CKM_DES3_ECB; */ } break; case (APR_KEY_AES_128): if (APR_MODE_CBC == mode) { key->cipherOid = SEC_OID_AES_128_CBC; } else { key->cipherOid = SEC_OID_AES_128_ECB; } break; case (APR_KEY_AES_192): if (APR_MODE_CBC == mode) { key->cipherOid = SEC_OID_AES_192_CBC; } else { key->cipherOid = SEC_OID_AES_192_ECB; } break; case (APR_KEY_AES_256): if (APR_MODE_CBC == mode) { key->cipherOid = SEC_OID_AES_256_CBC; } else { key->cipherOid = SEC_OID_AES_256_ECB; } break; default: /* unknown key type, give up */ return APR_EKEYTYPE; } /* AES_128_CBC --> CKM_AES_CBC --> CKM_AES_CBC_PAD */ key->cipherMech = PK11_AlgtagToMechanism(key->cipherOid); if (key->cipherMech == CKM_INVALID_MECHANISM) { return APR_ENOCIPHER; } if (doPad) { CK_MECHANISM_TYPE paddedMech; paddedMech = PK11_GetPadMechanism(key->cipherMech); if (CKM_INVALID_MECHANISM == paddedMech || key->cipherMech == paddedMech) { return APR_EPADDING; } key->cipherMech = paddedMech; } /* Turn the raw passphrase and salt into SECItems */ passItem.data = (unsigned char*) pass; passItem.len = passLen; saltItem.data = (unsigned char*) salt; saltItem.len = saltLen; /* generate the key */ /* pbeAlg and cipherAlg are the same. NSS decides the keylength. */ algid = PK11_CreatePBEV2AlgorithmID(key->cipherOid, key->cipherOid, SEC_OID_HMAC_SHA1, 0, iterations, &saltItem); if (algid) { slot = PK11_GetBestSlot(key->cipherMech, wincx); if (slot) { key->symKey = PK11_PBEKeyGen(slot, algid, &passItem, PR_FALSE, wincx); PK11_FreeSlot(slot); } SECOID_DestroyAlgorithmID(algid, PR_TRUE); } /* sanity check? */ if (!key->symKey) { PRErrorCode perr = PORT_GetError(); if (perr) { f->result->rc = perr; f->result->msg = PR_ErrorToName(perr); rv = APR_ENOKEY; } } key->ivSize = PK11_GetIVLength(key->cipherMech); if (ivSize) { *ivSize = key->ivSize; } return rv; }