static PK11Context* sipe_crypt_ctx_create(CK_MECHANISM_TYPE cipherMech, const guchar *key, gsize key_length) { PK11SlotInfo* slot; SECItem keyItem; SECItem ivItem; PK11SymKey* SymKey; SECItem *SecParam; PK11Context* EncContext; /* For key */ slot = PK11_GetBestSlot(cipherMech, NULL); keyItem.type = siBuffer; keyItem.data = (unsigned char *)key; keyItem.len = key_length; SymKey = PK11_ImportSymKey(slot, cipherMech, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, NULL); /* Parameter for crypto context */ ivItem.type = siBuffer; ivItem.data = NULL; ivItem.len = 0; SecParam = PK11_ParamFromIV(cipherMech, &ivItem); EncContext = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT, SymKey, SecParam); PK11_FreeSymKey(SymKey); SECITEM_FreeItem(SecParam, PR_TRUE); PK11_FreeSlot(slot); return EncContext; }
CryptoRc4 crypto_rc4_init(uint8 * key, uint32 len) { CryptoRc4 rc4 = xmalloc(sizeof(*rc4)); CK_MECHANISM_TYPE cipherMech = CKM_RC4; PK11SlotInfo* slot = PK11_GetInternalKeySlot(); ASSERT(slot); SECItem keyItem; keyItem.type = siBuffer; keyItem.data = key; keyItem.len = len; PK11SymKey* symKey = PK11_ImportSymKey(slot, cipherMech, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, NULL); ASSERT(symKey); SECItem* secParam = PK11_ParamFromIV(cipherMech, NULL); ASSERT(secParam); rc4->context = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT, symKey, secParam); ASSERT(rc4->context); PK11_FreeSymKey(symKey); SECITEM_FreeItem(secParam, PR_TRUE); PK11_FreeSlot(slot); return rc4; }
/** * @brief Initialise a context for decrypting arbitrary data using the given key. * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If * *ctx is not NULL, *ctx must point at a previously created structure. * @param ctx The block context returned, see note. * @param blockSize The block size of the cipher. * @param iv Optional initialisation vector. If the buffer pointed to is NULL, * an IV will be created at random, in space allocated from the pool. * If the buffer is not NULL, the IV in the buffer will be used. * @param key The key structure. * @param p The pool to use. * @return Returns APR_ENOIV if an initialisation vector is required but not specified. * Returns APR_EINIT if the backend failed to initialise the context. Returns * APR_ENOTIMPL if not implemented. */ static apr_status_t crypto_block_decrypt_init(apr_crypto_block_t **ctx, apr_size_t *blockSize, const unsigned char *iv, const apr_crypto_key_t *key, apr_pool_t *p) { PRErrorCode perr; SECItem * secParam; apr_crypto_block_t *block = *ctx; if (!block) { *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t)); } if (!block) { return APR_ENOMEM; } block->f = key->f; block->pool = p; block->provider = key->provider; apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper, apr_pool_cleanup_null); if (key->ivSize) { SECItem ivItem; if (iv == NULL) { return APR_ENOIV; /* Cannot initialise without an IV */ } ivItem.data = (unsigned char*) iv; ivItem.len = key->ivSize; secParam = PK11_ParamFromIV(key->cipherMech, &ivItem); } else { secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey); } block->blockSize = PK11_GetBlockSize(key->cipherMech, secParam); block->ctx = PK11_CreateContextBySymKey(key->cipherMech, CKA_DECRYPT, key->symKey, secParam); /* did an error occur? */ perr = PORT_GetError(); if (perr || !block->ctx) { key->f->result->rc = perr; key->f->result->msg = PR_ErrorToName(perr); return APR_EINIT; } if (blockSize) { *blockSize = PK11_GetBlockSize(key->cipherMech, secParam); } return APR_SUCCESS; }
nsresult nsStreamCipher::InitWithIV_(nsIKeyObject *aKey, SECItem* aIV) { NS_ENSURE_ARG_POINTER(aKey); // Make sure we have a SYM_KEY. PRInt16 keyType; nsresult rv = aKey->GetType(&keyType); NS_ENSURE_SUCCESS(rv, rv); if (keyType != nsIKeyObject::SYM_KEY) return NS_ERROR_INVALID_ARG; if (mContext) PK11_DestroyContext(mContext, true /* free sub-objects */); // Get the PK11SymKey out of the key object and create the PK11Context. void* keyObj; rv = aKey->GetKeyObj(&keyObj); NS_ENSURE_SUCCESS(rv, rv); PK11SymKey *symkey = reinterpret_cast<PK11SymKey*>(keyObj); if (!symkey) return NS_ERROR_FAILURE; CK_MECHANISM_TYPE cipherMech = PK11_GetMechanism(symkey); SECItem *param = nullptr; // aIV may be null param = PK11_ParamFromIV(cipherMech, aIV); if (!param) return NS_ERROR_FAILURE; mContext = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT, symkey, param); SECITEM_FreeItem(param, true); // Something went wrong if mContext doesn't exist. if (!mContext) return NS_ERROR_FAILURE; // Everything went ok. mValue.Truncate(); return NS_OK; }
static int nss_encrypt_decrypt_init(struct crypto_mech_data *mech_props, bool do_encrypt, struct sss_nss_crypto_ctx *cctx) { CK_ATTRIBUTE_TYPE op; int ret; op = do_encrypt ? CKA_ENCRYPT : CKA_DECRYPT; /* turn the raw key into a key object */ cctx->keyobj = PK11_ImportSymKey(cctx->slot, mech_props->cipher, PK11_OriginUnwrap, op, cctx->key, NULL); if (cctx->keyobj == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Failure to import key into NSS (err %d)\n", PR_GetError()); ret = EIO; goto done; } /* turn the raw IV into a initialization vector object */ cctx->sparam = PK11_ParamFromIV(mech_props->cipher, cctx->iv); if (cctx->sparam == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Failure to set up PKCS11 param (err %d)\n", PR_GetError()); ret = EIO; goto done; } /* Create cipher context */ cctx->ectx = PK11_CreateContextBySymKey(mech_props->cipher, op, cctx->keyobj, cctx->sparam); if (cctx->ectx == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create cipher context (err %d)\n", PORT_GetError()); ret = EIO; goto done; } ret = EOK; done: return ret; }
char * crypto_encrypt (const char *cipher, const guint8 *data, gsize data_len, const char *iv, gsize iv_len, const char *key, gsize key_len, gsize *out_len, GError **error) { SECStatus ret; CK_MECHANISM_TYPE cipher_mech = CKM_DES3_CBC_PAD; PK11SlotInfo *slot = NULL; SECItem key_item = { .data = (unsigned char *) key, .len = key_len }; SECItem iv_item = { .data = (unsigned char *) iv, .len = iv_len }; PK11SymKey *sym_key = NULL; SECItem *sec_param = NULL; PK11Context *ctx = NULL; unsigned char *output, *padded_buf; gsize output_len; int encrypted_len = 0, i; gboolean success = FALSE; gsize padded_buf_len, pad_len; if (!crypto_init (error)) return NULL; if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) cipher_mech = CKM_DES3_CBC_PAD; else if (!strcmp (cipher, CIPHER_AES_CBC)) cipher_mech = CKM_AES_CBC_PAD; else { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_UNKNOWN_CIPHER, _("Private key cipher '%s' was unknown."), cipher); return NULL; } /* If data->len % ivlen == 0, then we add another complete block * onto the end so that the decrypter knows there's padding. */ pad_len = iv_len - (data_len % iv_len); output_len = padded_buf_len = data_len + pad_len; padded_buf = g_malloc0 (padded_buf_len); memcpy (padded_buf, data, data_len); for (i = 0; i < pad_len; i++) padded_buf[data_len + i] = (guint8) (pad_len & 0xFF); output = g_malloc0 (output_len); slot = PK11_GetBestSlot (cipher_mech, NULL); if (!slot) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_FAILED, _("Failed to initialize the encryption cipher slot.")); goto out; } sym_key = PK11_ImportSymKey (slot, cipher_mech, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL); if (!sym_key) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_ENCRYPTION_FAILED, _("Failed to set symmetric key for encryption.")); goto out; } sec_param = PK11_ParamFromIV (cipher_mech, &iv_item); if (!sec_param) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_ENCRYPTION_FAILED, _("Failed to set IV for encryption.")); goto out; } ctx = PK11_CreateContextBySymKey (cipher_mech, CKA_ENCRYPT, sym_key, sec_param); if (!ctx) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_ENCRYPTION_FAILED, _("Failed to initialize the encryption context.")); goto out; } ret = PK11_CipherOp (ctx, output, &encrypted_len, output_len, padded_buf, padded_buf_len); if (ret != SECSuccess) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_ENCRYPTION_FAILED, _("Failed to encrypt: %d."), PORT_GetError ()); goto out; } if (encrypted_len != output_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_ENCRYPTION_FAILED, _("Unexpected amount of data after encrypting.")); goto out; } *out_len = encrypted_len; success = TRUE; out: if (ctx) PK11_DestroyContext (ctx, PR_TRUE); if (sym_key) PK11_FreeSymKey (sym_key); if (sec_param) SECITEM_FreeItem (sec_param, PR_TRUE); if (slot) PK11_FreeSlot (slot); memset (padded_buf, 0, padded_buf_len); g_free (padded_buf); if (!success) { memset (output, 0, output_len); g_free (output); output = NULL; } return (char *) output; } NMCryptoFileFormat crypto_verify_cert (const unsigned char *data, gsize len, GError **error) { CERTCertificate *cert; if (!crypto_init (error)) return NM_CRYPTO_FILE_FORMAT_UNKNOWN; /* Try DER/PEM first */ cert = CERT_DecodeCertFromPackage ((char *) data, len); if (!cert) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_INVALID_DATA, _("Couldn't decode certificate: %d"), PORT_GetError()); return NM_CRYPTO_FILE_FORMAT_UNKNOWN; } CERT_DestroyCertificate (cert); return NM_CRYPTO_FILE_FORMAT_X509; } gboolean crypto_verify_pkcs12 (const guint8 *data, gsize data_len, const char *password, GError **error) { SEC_PKCS12DecoderContext *p12ctx = NULL; SECItem pw = { 0 }; PK11SlotInfo *slot = NULL; SECStatus s; gunichar2 *ucs2_password; glong ucs2_chars = 0; #ifndef WORDS_BIGENDIAN guint16 *p; #endif /* WORDS_BIGENDIAN */ if (error) g_return_val_if_fail (*error == NULL, FALSE); if (!crypto_init (error)) return FALSE; /* PKCS#12 passwords are apparently UCS2 BIG ENDIAN, and NSS doesn't do * any conversions for us. */ if (password && *password) { if (!g_utf8_validate (password, -1, NULL)) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_INVALID_PASSWORD, _("Password must be UTF-8")); return FALSE; } ucs2_password = g_utf8_to_utf16 (password, strlen (password), NULL, &ucs2_chars, NULL); /* Can't fail if g_utf8_validate() succeeded */ g_return_val_if_fail (ucs2_password != NULL && ucs2_chars != 0, FALSE); ucs2_chars *= 2; /* convert # UCS2 characters -> bytes */ pw.data = PORT_ZAlloc(ucs2_chars + 2); memcpy (pw.data, ucs2_password, ucs2_chars); pw.len = ucs2_chars + 2; /* include terminating NULL */ memset (ucs2_password, 0, ucs2_chars); g_free (ucs2_password); #ifndef WORDS_BIGENDIAN for (p = (guint16 *) pw.data; p < (guint16 *) (pw.data + pw.len); p++) *p = GUINT16_SWAP_LE_BE (*p); #endif /* WORDS_BIGENDIAN */ } else { /* NULL password */ pw.data = NULL; pw.len = 0; } slot = PK11_GetInternalKeySlot(); p12ctx = SEC_PKCS12DecoderStart (&pw, slot, NULL, NULL, NULL, NULL, NULL, NULL); if (!p12ctx) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_FAILED, _("Couldn't initialize PKCS#12 decoder: %d"), PORT_GetError()); goto error; } s = SEC_PKCS12DecoderUpdate (p12ctx, (guint8 *)data, data_len); if (s != SECSuccess) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_INVALID_DATA, _("Couldn't decode PKCS#12 file: %d"), PORT_GetError()); goto error; } s = SEC_PKCS12DecoderVerify (p12ctx); if (s != SECSuccess) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Couldn't verify PKCS#12 file: %d"), PORT_GetError()); goto error; } SEC_PKCS12DecoderFinish (p12ctx); SECITEM_ZfreeItem (&pw, PR_FALSE); return TRUE; error: if (p12ctx) SEC_PKCS12DecoderFinish (p12ctx); if (slot) PK11_FreeSlot(slot); SECITEM_ZfreeItem (&pw, PR_FALSE); return FALSE; }
// Convert an opaque key handle aKeyHandle back into a Private Key object, using // the long-lived aPersistentKey mixed with aAppParam and the AES Key Wrap // algorithm. static UniqueSECKEYPrivateKey PrivateKeyFromKeyHandle(const UniquePK11SlotInfo& aSlot, const UniquePK11SymKey& aPersistentKey, uint8_t* aKeyHandle, uint32_t aKeyHandleLen, uint8_t* aAppParam, uint32_t aAppParamLen, const nsNSSShutDownPreventionLock&) { MOZ_ASSERT(aSlot); MOZ_ASSERT(aPersistentKey); MOZ_ASSERT(aKeyHandle); MOZ_ASSERT(aAppParam); MOZ_ASSERT(aAppParamLen == SHA256_LENGTH); if (NS_WARN_IF(!aSlot || !aPersistentKey || !aKeyHandle || !aAppParam || aAppParamLen != SHA256_LENGTH)) { return nullptr; } // As we only support one key format ourselves (right now), fail early if // we aren't that length if (NS_WARN_IF(aKeyHandleLen != kVersion1KeyHandleLen)) { return nullptr; } if (NS_WARN_IF(aKeyHandle[0] != SoftTokenHandle::Version1)) { // Unrecognized version return nullptr; } uint8_t saltLen = aKeyHandle[1]; uint8_t* saltPtr = aKeyHandle + 2; if (NS_WARN_IF(saltLen != kSaltByteLen)) { return nullptr; } // Prepare the HKDF (https://tools.ietf.org/html/rfc5869) CK_NSS_HKDFParams hkdfParams = { true, saltPtr, saltLen, true, aAppParam, aAppParamLen }; SECItem kdfParams = { siBuffer, (unsigned char*)&hkdfParams, sizeof(hkdfParams) }; // Derive a wrapping key from aPersistentKey, the salt, and the aAppParam. // CKM_AES_KEY_GEN and CKA_WRAP are key type and usage attributes of the // derived symmetric key and don't matter because we ignore them anyway. UniquePK11SymKey wrapKey(PK11_Derive(aPersistentKey.get(), CKM_NSS_HKDF_SHA256, &kdfParams, CKM_AES_KEY_GEN, CKA_WRAP, kWrappingKeyByteLen)); if (NS_WARN_IF(!wrapKey.get())) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to derive a wrapping key, NSS error #%d", PORT_GetError())); return nullptr; } uint8_t wrappedLen = aKeyHandleLen - saltLen - 2; uint8_t* wrappedPtr = aKeyHandle + saltLen + 2; ScopedAutoSECItem wrappedKeyItem(wrappedLen); memcpy(wrappedKeyItem.data, wrappedPtr, wrappedKeyItem.len); ScopedAutoSECItem pubKey(kPublicKeyLen); UniqueSECItem param(PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP_PAD, /* default IV */ nullptr )); CK_ATTRIBUTE_TYPE usages[] = { CKA_SIGN }; int usageCount = 1; UniqueSECKEYPrivateKey unwrappedKey( PK11_UnwrapPrivKey(aSlot.get(), wrapKey.get(), CKM_NSS_AES_KEY_WRAP_PAD, param.get(), &wrappedKeyItem, /* no nickname */ nullptr, /* discard pubkey */ &pubKey, /* not permanent */ false, /* non-exportable */ true, CKK_EC, usages, usageCount, /* wincx */ nullptr)); if (NS_WARN_IF(!unwrappedKey)) { // Not our key. MOZ_LOG(gNSSTokenLog, LogLevel::Debug, ("Could not unwrap key handle, NSS Error #%d", PORT_GetError())); return nullptr; } return unwrappedKey; }
// Convert a Private Key object into an opaque key handle, using AES Key Wrap // with the long-lived aPersistentKey mixed with aAppParam to convert aPrivKey. // The key handle's format is version || saltLen || salt || wrappedPrivateKey static UniqueSECItem KeyHandleFromPrivateKey(const UniquePK11SlotInfo& aSlot, const UniquePK11SymKey& aPersistentKey, uint8_t* aAppParam, uint32_t aAppParamLen, const UniqueSECKEYPrivateKey& aPrivKey, const nsNSSShutDownPreventionLock&) { MOZ_ASSERT(aSlot); MOZ_ASSERT(aPersistentKey); MOZ_ASSERT(aAppParam); MOZ_ASSERT(aPrivKey); if (NS_WARN_IF(!aSlot || !aPersistentKey || !aPrivKey || !aAppParam)) { return nullptr; } // Generate a random salt uint8_t saltParam[kSaltByteLen]; SECStatus srv = PK11_GenerateRandomOnSlot(aSlot.get(), saltParam, sizeof(saltParam)); if (NS_WARN_IF(srv != SECSuccess)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to generate a salt, NSS error #%d", PORT_GetError())); return nullptr; } // Prepare the HKDF (https://tools.ietf.org/html/rfc5869) CK_NSS_HKDFParams hkdfParams = { true, saltParam, sizeof(saltParam), true, aAppParam, aAppParamLen }; SECItem kdfParams = { siBuffer, (unsigned char*)&hkdfParams, sizeof(hkdfParams) }; // Derive a wrapping key from aPersistentKey, the salt, and the aAppParam. // CKM_AES_KEY_GEN and CKA_WRAP are key type and usage attributes of the // derived symmetric key and don't matter because we ignore them anyway. UniquePK11SymKey wrapKey(PK11_Derive(aPersistentKey.get(), CKM_NSS_HKDF_SHA256, &kdfParams, CKM_AES_KEY_GEN, CKA_WRAP, kWrappingKeyByteLen)); if (NS_WARN_IF(!wrapKey.get())) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to derive a wrapping key, NSS error #%d", PORT_GetError())); return nullptr; } UniqueSECItem wrappedKey(::SECITEM_AllocItem(/* default arena */ nullptr, /* no buffer */ nullptr, kWrappedKeyBufLen)); if (NS_WARN_IF(!wrappedKey)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to allocate memory")); return nullptr; } UniqueSECItem param(PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP_PAD, /* default IV */ nullptr )); srv = PK11_WrapPrivKey(aSlot.get(), wrapKey.get(), aPrivKey.get(), CKM_NSS_AES_KEY_WRAP_PAD, param.get(), wrappedKey.get(), /* wincx */ nullptr); if (NS_WARN_IF(srv != SECSuccess)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to wrap U2F key, NSS error #%d", PORT_GetError())); return nullptr; } // Concatenate the salt and the wrapped Private Key together mozilla::dom::CryptoBuffer keyHandleBuf; if (NS_WARN_IF(!keyHandleBuf.SetCapacity(wrappedKey.get()->len + sizeof(saltParam) + 2, mozilla::fallible))) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to allocate memory")); return nullptr; } // It's OK to ignore the return values here because we're writing into // pre-allocated space keyHandleBuf.AppendElement(SoftTokenHandle::Version1, mozilla::fallible); keyHandleBuf.AppendElement(sizeof(saltParam), mozilla::fallible); keyHandleBuf.AppendElements(saltParam, sizeof(saltParam), mozilla::fallible); keyHandleBuf.AppendSECItem(wrappedKey.get()); UniqueSECItem keyHandle(::SECITEM_AllocItem(nullptr, nullptr, 0)); if (NS_WARN_IF(!keyHandle)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to allocate memory")); return nullptr; } if (NS_WARN_IF(!keyHandleBuf.ToSECItem(/* default arena */ nullptr, keyHandle.get()))) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to allocate memory")); return nullptr; } return keyHandle; }
size_t ssl_des3_encrypt(const unsigned char *key, size_t key_len, const unsigned char *input, size_t input_len, const unsigned char *iv, unsigned char **res) { #define CIPHER_MECH CKM_DES3_CBC #define MAX_OUTPUT_LEN 72 int len1; unsigned int len2; PK11Context *ctx = NULL; PK11SlotInfo *slot = NULL; SECItem keyItem; SECItem ivItem; SECItem *secParam = NULL; PK11SymKey *symKey = NULL; size_t rc; SECStatus rv; if (!initialized) { ssl_init(); } keyItem.data = (unsigned char *)key; keyItem.len = key_len; slot = PK11_GetBestSlot(CIPHER_MECH, NULL); if (slot == NULL) { fprintf(stderr, "PK11_GetBestSlot failed (err %d)\n", PR_GetError()); rc = 0; goto out; } symKey = PK11_ImportSymKey(slot, CIPHER_MECH, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, NULL); if (symKey == NULL) { fprintf(stderr, "PK11_ImportSymKey failed (err %d)\n", PR_GetError()); rc = 0; goto out; } ivItem.data = (unsigned char *)iv; /* See msn_soap_passport_sso_handle_response in protocols/msn/soap.c */ ivItem.len = 8; secParam = PK11_ParamFromIV(CIPHER_MECH, &ivItem); if (secParam == NULL) { fprintf(stderr, "PK11_ParamFromIV failed (err %d)\n", PR_GetError()); rc = 0; goto out; } ctx = PK11_CreateContextBySymKey(CIPHER_MECH, CKA_ENCRYPT, symKey, secParam); if (ctx == NULL) { fprintf(stderr, "PK11_CreateContextBySymKey failed (err %d)\n", PR_GetError()); rc = 0; goto out; } *res = g_new0(unsigned char, MAX_OUTPUT_LEN); rv = PK11_CipherOp(ctx, *res, &len1, MAX_OUTPUT_LEN, (unsigned char *)input, input_len); if (rv != SECSuccess) { fprintf(stderr, "PK11_CipherOp failed (err %d)\n", PR_GetError()); rc = 0; goto out; } assert(len1 <= MAX_OUTPUT_LEN); rv = PK11_DigestFinal(ctx, *res + len1, &len2, (unsigned int)MAX_OUTPUT_LEN - len1); if (rv != SECSuccess) { fprintf(stderr, "PK11_DigestFinal failed (err %d)\n", PR_GetError()); rc = 0; goto out; } rc = len1 + len2; out: if (ctx) PK11_DestroyContext(ctx, PR_TRUE); if (symKey) PK11_FreeSymKey(symKey); if (secParam) SECITEM_FreeItem(secParam, PR_TRUE); if (slot) PK11_FreeSlot(slot); return rc; }
/* * create a new parameter block from the passed in MECHANISM and the * key. Use Netscape's S/MIME Rules for the New param block. */ SECItem * pk11_GenerateNewParamWithKeyLen(CK_MECHANISM_TYPE type, int keyLen) { CK_RC2_CBC_PARAMS *rc2_params; CK_RC2_PARAMS *rc2_ecb_params; SECItem *mech; SECItem iv; SECStatus rv; mech = (SECItem *) PORT_Alloc(sizeof(SECItem)); if (mech == NULL) return NULL; rv = SECSuccess; mech->type = siBuffer; switch (type) { case CKM_RC4: case CKM_SEED_ECB: case CKM_CAMELLIA_ECB: case CKM_AES_ECB: case CKM_DES_ECB: case CKM_DES3_ECB: case CKM_IDEA_ECB: case CKM_CDMF_ECB: case CKM_CAST_ECB: case CKM_CAST3_ECB: case CKM_CAST5_ECB: mech->data = NULL; mech->len = 0; break; case CKM_RC2_ECB: rc2_ecb_params = (CK_RC2_PARAMS *)PORT_Alloc(sizeof(CK_RC2_PARAMS)); if (rc2_ecb_params == NULL) { rv = SECFailure; break; } /* NOTE PK11_GetKeyLength can return -1 if the key isn't and RC2, RC5, * or RC4 key. Of course that wouldn't happen here doing RC2:).*/ *rc2_ecb_params = keyLen ? keyLen*8 : 128; mech->data = (unsigned char *) rc2_ecb_params; mech->len = sizeof(CK_RC2_PARAMS); break; case CKM_RC2_CBC: case CKM_RC2_CBC_PAD: rv = pk11_GenIV(type,&iv); if (rv != SECSuccess) { break; } rc2_params = (CK_RC2_CBC_PARAMS *)PORT_Alloc(sizeof(CK_RC2_CBC_PARAMS)); if (rc2_params == NULL) { PORT_Free(iv.data); rv = SECFailure; break; } /* NOTE PK11_GetKeyLength can return -1 if the key isn't and RC2, RC5, * or RC4 key. Of course that wouldn't happen here doing RC2:).*/ rc2_params->ulEffectiveBits = keyLen ? keyLen*8 : 128; if (iv.data) PORT_Memcpy(rc2_params->iv,iv.data,sizeof(rc2_params->iv)); mech->data = (unsigned char *) rc2_params; mech->len = sizeof(CK_RC2_CBC_PARAMS); PORT_Free(iv.data); break; case CKM_RC5_ECB: PORT_Free(mech); return PK11_ParamFromIV(type,NULL); case CKM_RC5_CBC: case CKM_RC5_CBC_PAD: rv = pk11_GenIV(type,&iv); if (rv != SECSuccess) { break; } PORT_Free(mech); return PK11_ParamFromIV(type,&iv); default: if (pk11_lookup(type)->iv == 0) { mech->data = NULL; mech->len = 0; break; } case CKM_SEED_CBC: case CKM_CAMELLIA_CBC: case CKM_AES_CBC: case CKM_DES_CBC: case CKM_DES3_CBC: case CKM_IDEA_CBC: case CKM_CDMF_CBC: case CKM_CAST_CBC: case CKM_CAST3_CBC: case CKM_CAST5_CBC: case CKM_DES_CBC_PAD: case CKM_DES3_CBC_PAD: case CKM_IDEA_CBC_PAD: case CKM_CDMF_CBC_PAD: case CKM_CAST_CBC_PAD: case CKM_CAST3_CBC_PAD: case CKM_CAST5_CBC_PAD: case CKM_SKIPJACK_CBC64: case CKM_SKIPJACK_ECB64: case CKM_SKIPJACK_OFB64: case CKM_SKIPJACK_CFB64: case CKM_SKIPJACK_CFB32: case CKM_SKIPJACK_CFB16: case CKM_SKIPJACK_CFB8: case CKM_BATON_ECB128: case CKM_BATON_ECB96: case CKM_BATON_CBC128: case CKM_BATON_COUNTER: case CKM_BATON_SHUFFLE: case CKM_JUNIPER_ECB128: case CKM_JUNIPER_CBC128: case CKM_JUNIPER_COUNTER: case CKM_JUNIPER_SHUFFLE: rv = pk11_GenIV(type,&iv); if (rv != SECSuccess) { break; } mech->data = (unsigned char*)PORT_Alloc(iv.len); if (mech->data == NULL) { PORT_Free(iv.data); rv = SECFailure; break; } PORT_Memcpy(mech->data,iv.data,iv.len); mech->len = iv.len; PORT_Free(iv.data); break; } if (rv != SECSuccess) { SECITEM_FreeItem(mech,PR_TRUE); return NULL; } return mech; }
static int xmlSecNssKWAesOp(const xmlSecByte *key, xmlSecSize keySize, const xmlSecByte *in, xmlSecSize inSize, xmlSecByte *out, xmlSecSize outSize, int enc) { CK_MECHANISM_TYPE cipherMech; PK11SlotInfo* slot = NULL; PK11SymKey* aeskey = NULL; SECItem* SecParam = NULL; PK11Context* EncContext = NULL; SECItem keyItem; SECStatus rv; int result_len = -1; int tmp1_outlen; unsigned int tmp2_outlen; xmlSecAssert2(key != NULL, -1); xmlSecAssert2(keySize > 0, -1); xmlSecAssert2(in != NULL, -1); xmlSecAssert2(inSize > 0, -1); xmlSecAssert2(out != NULL, -1); xmlSecAssert2(outSize >= inSize + 8, -1); cipherMech = CKM_NETSCAPE_AES_KEY_WRAP; slot = PK11_GetBestSlot(cipherMech, NULL); if (slot == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_GetBestSlot", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } keyItem.data = (unsigned char *)key; keyItem.len = keySize; aeskey = PK11_ImportSymKey(slot, cipherMech, PK11_OriginUnwrap, enc ? CKA_ENCRYPT : CKA_DECRYPT, &keyItem, NULL); if (aeskey == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_ImportSymKey", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } SecParam = PK11_ParamFromIV(cipherMech, NULL); if (SecParam == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_ParamFromIV", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } EncContext = PK11_CreateContextBySymKey(cipherMech, enc ? CKA_ENCRYPT : CKA_DECRYPT, aeskey, SecParam); if (EncContext == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_CreateContextBySymKey", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } tmp1_outlen = tmp2_outlen = 0; rv = PK11_CipherOp(EncContext, out, &tmp1_outlen, outSize, (unsigned char *)in, inSize); if (rv != SECSuccess) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_CipherOp", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } rv = PK11_DigestFinal(EncContext, out+tmp1_outlen, &tmp2_outlen, outSize-tmp1_outlen); if (rv != SECSuccess) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_DigestFinal", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } result_len = tmp1_outlen + tmp2_outlen; done: if (slot) { PK11_FreeSlot(slot); } if (aeskey) { PK11_FreeSymKey(aeskey); } if (SecParam) { SECITEM_FreeItem(SecParam, PR_TRUE); } if (EncContext) { PK11_DestroyContext(EncContext, PR_TRUE); } return(result_len); }
/** * @brief Initialise a context for encrypting arbitrary data using the given key. * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If * *ctx is not NULL, *ctx must point at a previously created structure. * @param ctx The block context returned, see note. * @param iv Optional initialisation vector. If the buffer pointed to is NULL, * an IV will be created at random, in space allocated from the pool. * If the buffer pointed to is not NULL, the IV in the buffer will be * used. * @param key The key structure. * @param blockSize The block size of the cipher. * @param p The pool to use. * @return Returns APR_ENOIV if an initialisation vector is required but not specified. * Returns APR_EINIT if the backend failed to initialise the context. Returns * APR_ENOTIMPL if not implemented. */ static apr_status_t crypto_block_encrypt_init(apr_crypto_block_t **ctx, const unsigned char **iv, const apr_crypto_key_t *key, apr_size_t *blockSize, apr_pool_t *p) { PRErrorCode perr; SECItem * secParam; SECItem ivItem; unsigned char * usedIv; apr_crypto_block_t *block = *ctx; if (!block) { *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t)); } if (!block) { return APR_ENOMEM; } block->f = key->f; block->pool = p; block->provider = key->provider; apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper, apr_pool_cleanup_null); if (key->ivSize) { if (iv == NULL) { return APR_ENOIV; } if (*iv == NULL) { SECStatus s; usedIv = apr_pcalloc(p, key->ivSize); if (!usedIv) { return APR_ENOMEM; } apr_crypto_clear(p, usedIv, key->ivSize); s = PK11_GenerateRandom(usedIv, key->ivSize); if (s != SECSuccess) { return APR_ENOIV; } *iv = usedIv; } else { usedIv = (unsigned char *) *iv; } ivItem.data = usedIv; ivItem.len = key->ivSize; secParam = PK11_ParamFromIV(key->cipherMech, &ivItem); } else { secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey); } block->blockSize = PK11_GetBlockSize(key->cipherMech, secParam); block->ctx = PK11_CreateContextBySymKey(key->cipherMech, CKA_ENCRYPT, key->symKey, secParam); /* did an error occur? */ perr = PORT_GetError(); if (perr || !block->ctx) { key->f->result->rc = perr; key->f->result->msg = PR_ErrorToName(perr); return APR_EINIT; } if (blockSize) { *blockSize = PK11_GetBlockSize(key->cipherMech, secParam); } return APR_SUCCESS; }
void do_3des_nss(u_int8_t *buf, size_t buf_len, PK11SymKey *symkey, u_int8_t *iv, bool enc) { u_int8_t *tmp_buf; u_int8_t *new_iv; CK_MECHANISM_TYPE ciphermech; SECItem ivitem; SECItem *secparam; PK11Context *enccontext = NULL; SECStatus rv; int outlen; DBG(DBG_CRYPT, DBG_log("NSS: do_3des init start")); ciphermech = CKM_DES3_CBC; /* libreswan provides padding */ if (symkey == NULL) { loglog(RC_LOG_SERIOUS, "do_3des: NSS derived enc key is NULL"); abort(); } ivitem.type = siBuffer; ivitem.data = iv; ivitem.len = DES_CBC_BLOCK_SIZE; secparam = PK11_ParamFromIV(ciphermech, &ivitem); if (secparam == NULL) { loglog(RC_LOG_SERIOUS, "do_3des: Failure to set up PKCS11 param (err %d)", PR_GetError()); abort(); } outlen = 0; tmp_buf = PR_Malloc((PRUint32)buf_len); new_iv = (u_int8_t*)PR_Malloc((PRUint32)DES_CBC_BLOCK_SIZE); if (!enc) memcpy(new_iv, (char*) buf + buf_len - DES_CBC_BLOCK_SIZE, DES_CBC_BLOCK_SIZE); enccontext = PK11_CreateContextBySymKey(ciphermech, enc ? CKA_ENCRYPT : CKA_DECRYPT, symkey, secparam); if (enccontext == NULL) { loglog(RC_LOG_SERIOUS, "do_3des: PKCS11 context creation failure (err %d)", PR_GetError()); abort(); } rv = PK11_CipherOp(enccontext, tmp_buf, &outlen, buf_len, buf, buf_len); if (rv != SECSuccess) { loglog(RC_LOG_SERIOUS, "do_3des: PKCS11 operation failure (err %d)", PR_GetError()); abort(); } if (enc) memcpy(new_iv, (char*) tmp_buf + buf_len - DES_CBC_BLOCK_SIZE, DES_CBC_BLOCK_SIZE); memcpy(buf, tmp_buf, buf_len); memcpy(iv, new_iv, DES_CBC_BLOCK_SIZE); PK11_DestroyContext(enccontext, PR_TRUE); PR_Free(tmp_buf); PR_Free(new_iv); if (secparam != NULL) SECITEM_FreeItem(secparam, PR_TRUE); DBG(DBG_CRYPT, DBG_log("NSS: do_3des init end")); }
static int encrypt_nss( knet_handle_t knet_h, const struct iovec *iov, int iovcnt, unsigned char *buf_out, ssize_t *buf_out_len) { struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance; PK11Context* crypt_context = NULL; SECItem crypt_param; SECItem *nss_sec_param = NULL; int tmp_outlen = 0, tmp1_outlen = 0; unsigned int tmp2_outlen = 0; unsigned char *salt = buf_out; unsigned char *data = buf_out + SALT_SIZE; int err = -1; int i; if (PK11_GenerateRandom (salt, SALT_SIZE) != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "Failure to generate a random number %d", PR_GetError()); goto out; } crypt_param.type = siBuffer; crypt_param.data = salt; crypt_param.len = SALT_SIZE; nss_sec_param = PK11_ParamFromIV (cipher_to_nss[instance->crypto_cipher_type], &crypt_param); if (nss_sec_param == NULL) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "Failure to set up PKCS11 param (err %d)", PR_GetError()); goto out; } /* * Create cipher context for encryption */ crypt_context = PK11_CreateContextBySymKey (cipher_to_nss[instance->crypto_cipher_type], CKA_ENCRYPT, instance->nss_sym_key, nss_sec_param); if (!crypt_context) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_CreateContext failed (encrypt) crypt_type=%d (err %d)", (int)cipher_to_nss[instance->crypto_cipher_type], PR_GetError()); goto out; } for (i=0; i<iovcnt; i++) { if (PK11_CipherOp(crypt_context, data, &tmp_outlen, KNET_DATABUFSIZE_CRYPT, (unsigned char *)iov[i].iov_base, iov[i].iov_len) != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_CipherOp failed (encrypt) crypt_type=%d (err %d)", (int)cipher_to_nss[instance->crypto_cipher_type], PR_GetError()); goto out; } tmp1_outlen = tmp1_outlen + tmp_outlen; } if (PK11_DigestFinal(crypt_context, data + tmp1_outlen, &tmp2_outlen, KNET_DATABUFSIZE_CRYPT - tmp1_outlen) != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_DigestFinal failed (encrypt) crypt_type=%d (err %d)", (int)cipher_to_nss[instance->crypto_cipher_type], PR_GetError()); goto out; } *buf_out_len = tmp1_outlen + tmp2_outlen + SALT_SIZE; err = 0; out: if (crypt_context) { PK11_DestroyContext(crypt_context, PR_TRUE); } if (nss_sec_param) { SECITEM_FreeItem(nss_sec_param, PR_TRUE); } return err; }
static void do_aes(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc) { u_int8_t iv_bak[AES_CBC_BLOCK_SIZE]; u_int8_t *new_iv = NULL; /* logic will avoid copy to NULL */ u_int8_t *tmp_buf; CK_MECHANISM_TYPE ciphermech; SECItem ivitem; SECItem* secparam = NULL; PK11SymKey* symkey = NULL; PK11Context* enccontext = NULL; SECStatus rv; int outlen; DBG(DBG_CRYPT, DBG_log("NSS do_aes: enter")); ciphermech = CKM_AES_CBC; /*libreswan provides padding*/ memcpy(&symkey, key, key_size); if (symkey == NULL) { loglog(RC_LOG_SERIOUS, "do_aes: NSS derived enc key in NULL\n"); goto out; } ivitem.type = siBuffer; ivitem.data = iv; ivitem.len = AES_CBC_BLOCK_SIZE; secparam = PK11_ParamFromIV(ciphermech, &ivitem); if (secparam == NULL) { loglog(RC_LOG_SERIOUS, "do_aes: Failure to set up PKCS11 param (err %d)\n",PR_GetError()); goto out; } outlen = 0; tmp_buf= PR_Malloc((PRUint32)buf_len); if (!enc){ memcpy(new_iv=iv_bak,(char*) buf + buf_len-AES_CBC_BLOCK_SIZE,AES_CBC_BLOCK_SIZE); } enccontext = PK11_CreateContextBySymKey(ciphermech, enc? CKA_ENCRYPT : CKA_DECRYPT, symkey, secparam); rv = PK11_CipherOp(enccontext, tmp_buf, &outlen, buf_len, buf, buf_len); passert(rv==SECSuccess); PK11_DestroyContext(enccontext, PR_TRUE); memcpy(buf,tmp_buf,buf_len); if(enc){ new_iv = (u_int8_t*) buf + buf_len-AES_CBC_BLOCK_SIZE; } memcpy(iv, new_iv, AES_CBC_BLOCK_SIZE); PR_Free(tmp_buf); out: if (secparam) SECITEM_FreeItem(secparam, PR_TRUE); DBG(DBG_CRYPT, DBG_log("NSS do_aes: exit")); }
char * crypto_decrypt (const char *cipher, int key_type, const guint8 *data, gsize data_len, const char *iv, const gsize iv_len, const char *key, const gsize key_len, gsize *out_len, GError **error) { char *output = NULL; int decrypted_len = 0; CK_MECHANISM_TYPE cipher_mech; PK11SlotInfo *slot = NULL; SECItem key_item; PK11SymKey *sym_key = NULL; SECItem *sec_param = NULL; PK11Context *ctx = NULL; SECStatus s; gboolean success = FALSE; unsigned int pad_len = 0, extra = 0; guint32 i, real_iv_len = 0; if (!crypto_init (error)) return NULL; if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) { cipher_mech = CKM_DES3_CBC_PAD; real_iv_len = 8; } else if (!strcmp (cipher, CIPHER_DES_CBC)) { cipher_mech = CKM_DES_CBC_PAD; real_iv_len = 8; } else if (!strcmp (cipher, CIPHER_AES_CBC)) { cipher_mech = CKM_AES_CBC_PAD; real_iv_len = 16; } else { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_UNKNOWN_CIPHER, _("Private key cipher '%s' was unknown."), cipher); return NULL; } if (iv_len < real_iv_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_INVALID_DATA, _("Invalid IV length (must be at least %d)."), real_iv_len); return NULL; } output = g_malloc0 (data_len); slot = PK11_GetBestSlot (cipher_mech, NULL); if (!slot) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_FAILED, _("Failed to initialize the decryption cipher slot.")); goto out; } key_item.data = (unsigned char *) key; key_item.len = key_len; sym_key = PK11_ImportSymKey (slot, cipher_mech, PK11_OriginUnwrap, CKA_DECRYPT, &key_item, NULL); if (!sym_key) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to set symmetric key for decryption.")); goto out; } key_item.data = (unsigned char *) iv; key_item.len = real_iv_len; sec_param = PK11_ParamFromIV (cipher_mech, &key_item); if (!sec_param) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to set IV for decryption.")); goto out; } ctx = PK11_CreateContextBySymKey (cipher_mech, CKA_DECRYPT, sym_key, sec_param); if (!ctx) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to initialize the decryption context.")); goto out; } s = PK11_CipherOp (ctx, (unsigned char *) output, &decrypted_len, data_len, data, data_len); if (s != SECSuccess) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to decrypt the private key: %d."), PORT_GetError ()); goto out; } if (decrypted_len > data_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to decrypt the private key: decrypted data too large.")); goto out; } s = PK11_DigestFinal (ctx, (unsigned char *) (output + decrypted_len), &extra, data_len - decrypted_len); if (s != SECSuccess) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to finalize decryption of the private key: %d."), PORT_GetError ()); goto out; } decrypted_len += extra; pad_len = data_len - decrypted_len; /* Check if the padding at the end of the decrypted data is valid */ if (pad_len == 0 || pad_len > real_iv_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to decrypt the private key: unexpected padding length.")); goto out; } /* Validate tail padding; last byte is the padding size, and all pad bytes * should contain the padding size. */ for (i = pad_len; i > 0; i--) { if (output[data_len - i] != pad_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED, _("Failed to decrypt the private key.")); goto out; } } *out_len = decrypted_len; success = TRUE; out: if (ctx) PK11_DestroyContext (ctx, PR_TRUE); if (sym_key) PK11_FreeSymKey (sym_key); if (sec_param) SECITEM_FreeItem (sec_param, PR_TRUE); if (slot) PK11_FreeSlot (slot); if (!success) { if (output) { /* Don't expose key material */ memset (output, 0, data_len); g_free (output); output = NULL; } } return output; }
/* encrypt a block (XMLSEC_NSS_AES_BLOCK_SIZE), in and out can overlap */ static void xmlSecNssAesOp(PK11SymKey *aeskey, const xmlSecByte *in, xmlSecByte *out, int enc) { CK_MECHANISM_TYPE cipherMech; SECItem* SecParam = NULL; PK11Context* EncContext = NULL; SECStatus rv; int tmp1_outlen; unsigned int tmp2_outlen; xmlSecAssert(in != NULL); xmlSecAssert(out != NULL); cipherMech = CKM_AES_ECB; SecParam = PK11_ParamFromIV(cipherMech, NULL); if (SecParam == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_ParamFromIV", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } EncContext = PK11_CreateContextBySymKey(cipherMech, enc ? CKA_ENCRYPT : CKA_DECRYPT, aeskey, SecParam); if (EncContext == NULL) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_CreateContextBySymKey", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } tmp1_outlen = tmp2_outlen = 0; rv = PK11_CipherOp(EncContext, out, &tmp1_outlen, XMLSEC_NSS_AES_BLOCK_SIZE, (unsigned char *)in, XMLSEC_NSS_AES_BLOCK_SIZE); if (rv != SECSuccess) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_CipherOp", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } rv = PK11_DigestFinal(EncContext, out+tmp1_outlen, &tmp2_outlen, XMLSEC_NSS_AES_BLOCK_SIZE-tmp1_outlen); if (rv != SECSuccess) { xmlSecErr_a_ignorar5(XMLSEC_ERRORS_HERE, NULL, "PK11_DigestFinal", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } done: if (SecParam) { SECITEM_FreeItem(SecParam, PR_TRUE); } if (EncContext) { PK11_DestroyContext(EncContext, PR_TRUE); } }
static void ike_alg_nss_cbc(const struct encrypt_desc *alg, u_int8_t *in_buf, size_t in_buf_len, PK11SymKey *symkey, u_int8_t *iv, bool enc) { DBG(DBG_CRYPT, DBG_log("NSS ike_alg_nss_cbc: %s - enter", alg->common.name)); if (symkey == NULL) { PASSERT_FAIL("%s - NSS derived enc key in NULL", alg->common.name); } SECItem ivitem; ivitem.type = siBuffer; ivitem.data = iv; ivitem.len = alg->enc_blocksize; SECItem *secparam = PK11_ParamFromIV(alg->common.nss_mechanism, &ivitem); if (secparam == NULL) { PASSERT_FAIL("%s - Failure to set up PKCS11 param (err %d)", alg->common.name, PR_GetError()); } PK11Context *enccontext; enccontext = PK11_CreateContextBySymKey(alg->common.nss_mechanism, enc ? CKA_ENCRYPT : CKA_DECRYPT, symkey, secparam); if (enccontext == NULL) { PASSERT_FAIL("%s - PKCS11 context creation failure (err %d)", alg->common.name, PR_GetError()); } /* Output buffer for transformed data. */ u_int8_t *out_buf = PR_Malloc((PRUint32)in_buf_len); int out_buf_len = 0; SECStatus rv = PK11_CipherOp(enccontext, out_buf, &out_buf_len, in_buf_len, in_buf, in_buf_len); if (rv != SECSuccess) { PASSERT_FAIL("%s - PKCS11 operation failure (err %d)", alg->common.name, PR_GetError()); } PK11_DestroyContext(enccontext, PR_TRUE); /* * Update the IV ready for the next call to this function. */ u_int8_t *new_iv; if (enc) { /* * The IV for the next encryption call is the last * block of encrypted output data. */ new_iv = out_buf + out_buf_len - alg->enc_blocksize; } else { /* * The IV for the next decryption call is the last * block of the encrypted input data. */ new_iv = in_buf + in_buf_len - alg->enc_blocksize; } memcpy(iv, new_iv, alg->enc_blocksize); /* * Finally, copy the transformed data back to the buffer. Do * this after extracting the IV. */ memcpy(in_buf, out_buf, in_buf_len); PR_Free(out_buf); if (secparam != NULL) SECITEM_FreeItem(secparam, PR_TRUE); DBG(DBG_CRYPT, DBG_log("NSS ike_alg_nss_cbc: %s - exit", alg->common.name)); }
int nss_crypto_init(struct crypto_mech_data *mech_props, enum crypto_mech_op crypto_op, struct sss_nss_crypto_ctx *cctx) { CK_ATTRIBUTE_TYPE op; int ret; switch (crypto_op) { case op_encrypt: op = CKA_ENCRYPT; break; case op_decrypt: op = CKA_DECRYPT; break; case op_sign: op = CKA_SIGN; break; default: return EFAULT; } /* turn the raw key into a key object */ cctx->keyobj = PK11_ImportSymKey(cctx->slot, mech_props->cipher, PK11_OriginUnwrap, op, cctx->key, NULL); if (cctx->keyobj == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Failure to import key into NSS (err %d)\n", PR_GetError()); ret = EIO; goto done; } if (crypto_op == op_encrypt || crypto_op == op_decrypt) { /* turn the raw IV into a initialization vector object */ cctx->sparam = PK11_ParamFromIV(mech_props->cipher, cctx->iv); if (cctx->sparam == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Failure to set up PKCS11 param (err %d)\n", PR_GetError()); ret = EIO; goto done; } } else { cctx->sparam = SECITEM_AllocItem(NULL, NULL, 0); if (cctx->sparam == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Failure to allocate SECItem\n"); ret = EIO; goto done; } MAKE_SECITEM(NULL, 0, cctx->sparam); } /* Create cipher context */ cctx->ectx = PK11_CreateContextBySymKey(mech_props->cipher, op, cctx->keyobj, cctx->sparam); if (cctx->ectx == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create cipher context (err %d)\n", PORT_GetError()); ret = EIO; goto done; } ret = EOK; done: return ret; }
static gboolean purple_aes_cipher_nss_crypt(const guchar *input, guchar *output, size_t len, guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size, CK_ATTRIBUTE_TYPE operation) { PurpleAESCipherNSSContext context; CK_MECHANISM_TYPE cipher_mech = CKM_AES_CBC; SECItem key_item, iv_item; SECStatus ret; int outlen = 0; unsigned int outlen_tmp = 0; memset(&context, 0, sizeof(PurpleAESCipherNSSContext)); if (NSS_NoDB_Init(NULL) != SECSuccess) { purple_debug_error("cipher-aes", "NSS_NoDB_Init failed: %d\n", PR_GetError()); return FALSE; } context.slot = PK11_GetBestSlot(cipher_mech, NULL); if (context.slot == NULL) { purple_debug_error("cipher-aes", "PK11_GetBestSlot failed: %d\n", PR_GetError()); return FALSE; } key_item.type = siBuffer; key_item.data = key; key_item.len = key_size; context.sym_key = PK11_ImportSymKey(context.slot, cipher_mech, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL); if (context.sym_key == NULL) { purple_debug_error("cipher-aes", "PK11_ImportSymKey failed: %d\n", PR_GetError()); purple_aes_cipher_nss_cleanup(&context); return FALSE; } iv_item.type = siBuffer; iv_item.data = iv; iv_item.len = PURPLE_AES_BLOCK_SIZE; context.sec_param = PK11_ParamFromIV(cipher_mech, &iv_item); if (context.sec_param == NULL) { purple_debug_error("cipher-aes", "PK11_ParamFromIV failed: %d\n", PR_GetError()); purple_aes_cipher_nss_cleanup(&context); return FALSE; } context.enc_context = PK11_CreateContextBySymKey(cipher_mech, operation, context.sym_key, context.sec_param); if (context.enc_context == NULL) { purple_debug_error("cipher-aes", "PK11_CreateContextBySymKey failed: %d\n", PR_GetError()); purple_aes_cipher_nss_cleanup(&context); return FALSE; } ret = PK11_CipherOp(context.enc_context, output, &outlen, len, (guchar *)input, len); if (ret != SECSuccess) { purple_debug_error("cipher-aes", "PK11_CipherOp failed: %d\n", PR_GetError()); purple_aes_cipher_nss_cleanup(&context); return FALSE; } ret = PK11_DigestFinal(context.enc_context, output + outlen, &outlen_tmp, len - outlen); if (ret != SECSuccess) { purple_debug_error("cipher-aes", "PK11_DigestFinal failed: %d\n", PR_GetError()); purple_aes_cipher_nss_cleanup(&context); return FALSE; } purple_aes_cipher_nss_cleanup(&context); outlen += outlen_tmp; if (outlen != (int)len) { purple_debug_error("cipher-aes", "resulting length doesn't match: %d (expected: %lu)\n", outlen, len); return FALSE; } return TRUE; }