From 4f43fd0a287a947740be17f0586c5bb929017e9b Mon Sep 17 00:00:00 2001 From: James M Snell Date: Thu, 2 Jan 2025 12:01:30 -0800 Subject: [PATCH] src: move CipherCtx methods to ncrypto --- deps/ncrypto/ncrypto.cc | 124 +++++++++++++++++++++++++++++++++--- deps/ncrypto/ncrypto.h | 48 +++++++++++++- src/crypto/crypto_aes.cc | 114 +++++++++++++++------------------ src/crypto/crypto_cipher.cc | 118 +++++++++++++++++----------------- 4 files changed, 270 insertions(+), 134 deletions(-) diff --git a/deps/ncrypto/ncrypto.cc b/deps/ncrypto/ncrypto.cc index d687904b677afd..5d8b5ef3c2e480 100644 --- a/deps/ncrypto/ncrypto.cc +++ b/deps/ncrypto/ncrypto.cc @@ -2294,7 +2294,7 @@ std::optional SSLPointer::verifyPeerCertificate() const { } const std::string_view SSLPointer::getClientHelloAlpn() const { - if (ssl_ == nullptr) return std::string_view(); + if (ssl_ == nullptr) return {}; const unsigned char* buf; size_t len; size_t rem; @@ -2305,34 +2305,34 @@ const std::string_view SSLPointer::getClientHelloAlpn() const { &buf, &rem) || rem < 2) { - return nullptr; + return {}; } len = (buf[0] << 8) | buf[1]; - if (len + 2 != rem) return nullptr; + if (len + 2 != rem) return {}; return reinterpret_cast(buf + 3); } const std::string_view SSLPointer::getClientHelloServerName() const { - if (ssl_ == nullptr) return std::string_view(); + if (ssl_ == nullptr) return {}; const unsigned char* buf; size_t len; size_t rem; if (!SSL_client_hello_get0_ext(get(), TLSEXT_TYPE_server_name, &buf, &rem) || rem <= 2) { - return nullptr; + return {}; } len = (*buf << 8) | *(buf + 1); - if (len + 2 != rem) return nullptr; + if (len + 2 != rem) return {}; rem = len; - if (rem == 0 || *(buf + 2) != TLSEXT_NAMETYPE_host_name) return nullptr; + if (rem == 0 || *(buf + 2) != TLSEXT_NAMETYPE_host_name) return {}; rem--; - if (rem <= 2) return nullptr; + if (rem <= 2) return {}; len = (*(buf + 3) << 8) | *(buf + 4); - if (len + 2 > rem) return nullptr; + if (len + 2 > rem) return {}; return reinterpret_cast(buf + 5); } @@ -2504,4 +2504,110 @@ bool Cipher::isSupportedAuthenticatedMode() const { } } +// ============================================================================ + +CipherCtxPointer CipherCtxPointer::New() { + auto ret = CipherCtxPointer(EVP_CIPHER_CTX_new()); + if (!ret) return {}; + EVP_CIPHER_CTX_init(ret.get()); + return ret; +} + +CipherCtxPointer::CipherCtxPointer(EVP_CIPHER_CTX* ctx) : ctx_(ctx) {} + +CipherCtxPointer::CipherCtxPointer(CipherCtxPointer&& other) noexcept + : ctx_(other.release()) {} + +CipherCtxPointer& CipherCtxPointer::operator=( + CipherCtxPointer&& other) noexcept { + if (this == &other) return *this; + this->~CipherCtxPointer(); + return *new (this) CipherCtxPointer(std::move(other)); +} + +CipherCtxPointer::~CipherCtxPointer() { + reset(); +} + +void CipherCtxPointer::reset(EVP_CIPHER_CTX* ctx) { + ctx_.reset(ctx); +} + +EVP_CIPHER_CTX* CipherCtxPointer::release() { + return ctx_.release(); +} + +void CipherCtxPointer::setFlags(int flags) { + if (!ctx_) return; + EVP_CIPHER_CTX_set_flags(ctx_.get(), flags); +} + +bool CipherCtxPointer::setKeyLength(size_t length) { + if (!ctx_) return false; + return EVP_CIPHER_CTX_set_key_length(ctx_.get(), length); +} + +bool CipherCtxPointer::setIvLength(size_t length) { + if (!ctx_) return false; + return EVP_CIPHER_CTX_ctrl( + ctx_.get(), EVP_CTRL_AEAD_SET_IVLEN, length, nullptr); +} + +bool CipherCtxPointer::setAeadTag(const Buffer& tag) { + if (!ctx_) return false; + return EVP_CIPHER_CTX_ctrl( + ctx_.get(), EVP_CTRL_AEAD_SET_TAG, tag.len, const_cast(tag.data)); +} + +bool CipherCtxPointer::setAeadTagLength(size_t length) { + if (!ctx_) return false; + return EVP_CIPHER_CTX_ctrl( + ctx_.get(), EVP_CTRL_AEAD_SET_TAG, length, nullptr); +} + +bool CipherCtxPointer::setPadding(bool padding) { + if (!ctx_) return false; + return EVP_CIPHER_CTX_set_padding(ctx_.get(), padding); +} + +int CipherCtxPointer::getBlockSize() const { + if (!ctx_) return 0; + return EVP_CIPHER_CTX_block_size(ctx_.get()); +} + +int CipherCtxPointer::getMode() const { + if (!ctx_) return 0; + return EVP_CIPHER_CTX_mode(ctx_.get()); +} + +int CipherCtxPointer::getNid() const { + if (!ctx_) return 0; + return EVP_CIPHER_CTX_nid(ctx_.get()); +} + +bool CipherCtxPointer::init(const Cipher& cipher, + bool encrypt, + const unsigned char* key, + const unsigned char* iv) { + if (!ctx_) return false; + return EVP_CipherInit_ex( + ctx_.get(), cipher, nullptr, key, iv, encrypt ? 1 : 0) == 1; +} + +bool CipherCtxPointer::update(const Buffer& in, + unsigned char* out, + int* out_len, + bool finalize) { + if (!ctx_) return false; + if (!finalize) { + return EVP_CipherUpdate(ctx_.get(), out, out_len, in.data, in.len) == 1; + } + return EVP_CipherFinal_ex(ctx_.get(), out, out_len) == 1; +} + +bool CipherCtxPointer::getAeadTag(size_t len, unsigned char* out) { + if (!ctx_) return false; + return EVP_CIPHER_CTX_ctrl(ctx_.get(), EVP_CTRL_AEAD_GET_TAG, len, out); +} + } // namespace ncrypto diff --git a/deps/ncrypto/ncrypto.h b/deps/ncrypto/ncrypto.h index e12fa7f925c08f..acf5485e2f41f6 100644 --- a/deps/ncrypto/ncrypto.h +++ b/deps/ncrypto/ncrypto.h @@ -197,7 +197,6 @@ using DeleteFnPtr = typename FunctionDeleter::Pointer; using BignumCtxPointer = DeleteFnPtr; using BignumGenCallbackPointer = DeleteFnPtr; -using CipherCtxPointer = DeleteFnPtr; using DSAPointer = DeleteFnPtr; using DSASigPointer = DeleteFnPtr; using ECDSASigPointer = DeleteFnPtr; @@ -213,6 +212,8 @@ using PKCS8Pointer = DeleteFnPtr; using RSAPointer = DeleteFnPtr; using SSLSessionPointer = DeleteFnPtr; +class CipherCtxPointer; + struct StackOfXASN1Deleter { void operator()(STACK_OF(ASN1_OBJECT) * p) const { sk_ASN1_OBJECT_pop_free(p, ASN1_OBJECT_free); @@ -425,6 +426,51 @@ class BignumPointer final { static bool defaultPrimeCheckCallback(int, int) { return 1; } }; +class CipherCtxPointer final { + public: + static CipherCtxPointer New(); + + CipherCtxPointer() = default; + explicit CipherCtxPointer(EVP_CIPHER_CTX* ctx); + CipherCtxPointer(CipherCtxPointer&& other) noexcept; + CipherCtxPointer& operator=(CipherCtxPointer&& other) noexcept; + NCRYPTO_DISALLOW_COPY(CipherCtxPointer) + ~CipherCtxPointer(); + + inline bool operator==(std::nullptr_t) const noexcept { + return ctx_ == nullptr; + } + inline operator bool() const { return ctx_ != nullptr; } + inline EVP_CIPHER_CTX* get() const { return ctx_.get(); } + inline operator EVP_CIPHER_CTX*() const { return ctx_.get(); } + void reset(EVP_CIPHER_CTX* ctx = nullptr); + EVP_CIPHER_CTX* release(); + + void setFlags(int flags); + bool setKeyLength(size_t length); + bool setIvLength(size_t length); + bool setAeadTag(const Buffer& tag); + bool setAeadTagLength(size_t length); + bool setPadding(bool padding); + bool init(const Cipher& cipher, + bool encrypt, + const unsigned char* key = nullptr, + const unsigned char* iv = nullptr); + + int getBlockSize() const; + int getMode() const; + int getNid() const; + + bool update(const Buffer& in, + unsigned char* out, + int* out_len, + bool finalize = false); + bool getAeadTag(size_t len, unsigned char* out); + + private: + DeleteFnPtr ctx_; +}; + class EVPKeyPointer final { public: static EVPKeyPointer New(); diff --git a/src/crypto/crypto_aes.cc b/src/crypto/crypto_aes.cc index 5fc63c9beb48c3..698f3574e47c3b 100644 --- a/src/crypto/crypto_aes.cc +++ b/src/crypto/crypto_aes.cc @@ -42,41 +42,28 @@ WebCryptoCipherStatus AES_Cipher(Environment* env, const int mode = params.cipher.getMode(); - CipherCtxPointer ctx(EVP_CIPHER_CTX_new()); - EVP_CIPHER_CTX_init(ctx.get()); - if (mode == EVP_CIPH_WRAP_MODE) - EVP_CIPHER_CTX_set_flags(ctx.get(), EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + auto ctx = CipherCtxPointer::New(); + if (mode == EVP_CIPH_WRAP_MODE) { + ctx.setFlags(EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + } const bool encrypt = cipher_mode == kWebCryptoCipherEncrypt; - if (!EVP_CipherInit_ex( - ctx.get(), - params.cipher, - nullptr, - nullptr, - nullptr, - encrypt)) { + if (!ctx.init(params.cipher, encrypt)) { // Cipher init failed return WebCryptoCipherStatus::FAILED; } - if (mode == EVP_CIPH_GCM_MODE && !EVP_CIPHER_CTX_ctrl( - ctx.get(), - EVP_CTRL_AEAD_SET_IVLEN, - params.iv.size(), - nullptr)) { + if (mode == EVP_CIPH_GCM_MODE && !ctx.setIvLength(params.iv.size())) { return WebCryptoCipherStatus::FAILED; } - if (!EVP_CIPHER_CTX_set_key_length(ctx.get(), - key_data.GetSymmetricKeySize()) || - !EVP_CipherInit_ex( - ctx.get(), - nullptr, - nullptr, + if (!ctx.setKeyLength(key_data.GetSymmetricKeySize()) || + !ctx.init( + ncrypto::Cipher(), + encrypt, reinterpret_cast(key_data.GetSymmetricKey()), - params.iv.data(), - encrypt)) { + params.iv.data())) { return WebCryptoCipherStatus::FAILED; } @@ -84,17 +71,19 @@ WebCryptoCipherStatus AES_Cipher(Environment* env, if (mode == EVP_CIPH_GCM_MODE) { switch (cipher_mode) { - case kWebCryptoCipherDecrypt: + case kWebCryptoCipherDecrypt: { // If in decrypt mode, the auth tag must be set in the params.tag. CHECK(params.tag); - if (!EVP_CIPHER_CTX_ctrl(ctx.get(), - EVP_CTRL_AEAD_SET_TAG, - params.tag.size(), - const_cast(params.tag.data()))) { + ncrypto::Buffer buffer = { + .data = params.tag.data(), + .len = params.tag.size(), + }; + if (!ctx.setAeadTag(buffer)) { return WebCryptoCipherStatus::FAILED; } break; - case kWebCryptoCipherEncrypt: + } + case kWebCryptoCipherEncrypt: { // In decrypt mode, we grab the tag length here. We'll use it to // ensure that that allocated buffer has enough room for both the // final block and the auth tag. Unlike our other AES-GCM implementation @@ -102,23 +91,22 @@ WebCryptoCipherStatus AES_Cipher(Environment* env, // of the generated ciphertext and returned in the same ArrayBuffer. tag_len = params.length; break; + } default: UNREACHABLE(); } } size_t total = 0; - int buf_len = in.size() + EVP_CIPHER_CTX_block_size(ctx.get()) + tag_len; + int buf_len = in.size() + ctx.getBlockSize() + tag_len; int out_len; - if (mode == EVP_CIPH_GCM_MODE && - params.additional_data.size() && - !EVP_CipherUpdate( - ctx.get(), - nullptr, - &out_len, - params.additional_data.data(), - params.additional_data.size())) { + ncrypto::Buffer buffer = { + .data = params.additional_data.data(), + .len = params.additional_data.size(), + }; + if (mode == EVP_CIPH_GCM_MODE && params.additional_data.size() && + !ctx.update(buffer, nullptr, &out_len)) { return WebCryptoCipherStatus::FAILED; } @@ -132,21 +120,20 @@ WebCryptoCipherStatus AES_Cipher(Environment* env, // // Refs: https://github.com/openssl/openssl/commit/420cb707b880e4fb649094241371701013eeb15f // Refs: https://github.com/nodejs/node/pull/38913#issuecomment-866505244 + buffer = { + .data = in.data(), + .len = in.size(), + }; if (in.empty()) { out_len = 0; - } else if (!EVP_CipherUpdate(ctx.get(), - buf.data(), - &out_len, - in.data(), - in.size())) { + } else if (!ctx.update(buffer, buf.data(), &out_len)) { return WebCryptoCipherStatus::FAILED; } total += out_len; CHECK_LE(out_len, buf_len); - out_len = EVP_CIPHER_CTX_block_size(ctx.get()); - if (!EVP_CipherFinal_ex( - ctx.get(), buf.data() + total, &out_len)) { + out_len = ctx.getBlockSize(); + if (!ctx.update({}, buf.data() + total, &out_len, true)) { return WebCryptoCipherStatus::FAILED; } total += out_len; @@ -154,11 +141,9 @@ WebCryptoCipherStatus AES_Cipher(Environment* env, // If using AES_GCM, grab the generated auth tag and append // it to the end of the ciphertext. if (cipher_mode == kWebCryptoCipherEncrypt && mode == EVP_CIPH_GCM_MODE) { - if (!EVP_CIPHER_CTX_ctrl(ctx.get(), - EVP_CTRL_AEAD_GET_TAG, - tag_len, - buf.data() + total)) + if (!ctx.getAeadTag(tag_len, buf.data() + total)) { return WebCryptoCipherStatus::FAILED; + } total += tag_len; } @@ -221,33 +206,34 @@ WebCryptoCipherStatus AES_CTR_Cipher2(const KeyObjectData& key_data, const ByteSource& in, unsigned const char* counter, unsigned char* out) { - CipherCtxPointer ctx(EVP_CIPHER_CTX_new()); + auto ctx = CipherCtxPointer::New(); + if (!ctx) { + return WebCryptoCipherStatus::FAILED; + } const bool encrypt = cipher_mode == kWebCryptoCipherEncrypt; - if (!EVP_CipherInit_ex( - ctx.get(), + if (!ctx.init( params.cipher, - nullptr, + encrypt, reinterpret_cast(key_data.GetSymmetricKey()), - counter, - encrypt)) { + counter)) { // Cipher init failed return WebCryptoCipherStatus::FAILED; } int out_len = 0; int final_len = 0; - if (!EVP_CipherUpdate( - ctx.get(), - out, - &out_len, - in.data(), - in.size())) { + ncrypto::Buffer buffer = { + .data = in.data(), + .len = in.size(), + }; + if (!ctx.update(buffer, out, &out_len)) { return WebCryptoCipherStatus::FAILED; } - if (!EVP_CipherFinal_ex(ctx.get(), out + out_len, &final_len)) + if (!ctx.update({}, out + out_len, &final_len, true)) { return WebCryptoCipherStatus::FAILED; + } out_len += final_len; if (static_cast(out_len) != in.size()) diff --git a/src/crypto/crypto_cipher.cc b/src/crypto/crypto_cipher.cc index 27294625037dba..8d8914058fc06c 100644 --- a/src/crypto/crypto_cipher.cc +++ b/src/crypto/crypto_cipher.cc @@ -66,14 +66,16 @@ void GetCipherInfo(const FunctionCallbackInfo& args) { // Test and input IV or key length to determine if it's acceptable. // If it is, then the getCipherInfo will succeed with the given // values. - CipherCtxPointer ctx(EVP_CIPHER_CTX_new()); - if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr, nullptr, nullptr, 1)) + auto ctx = CipherCtxPointer::New(); + if (!ctx.init(cipher, true)) { return; + } if (args[2]->IsInt32()) { int check_len = args[2].As()->Value(); - if (!EVP_CIPHER_CTX_set_key_length(ctx.get(), check_len)) + if (!ctx.setKeyLength(check_len)) { return; + } key_length = check_len; } @@ -91,11 +93,7 @@ void GetCipherInfo(const FunctionCallbackInfo& args) { case EVP_CIPH_GCM_MODE: // Fall through case EVP_CIPH_OCB_MODE: - if (!EVP_CIPHER_CTX_ctrl( - ctx.get(), - EVP_CTRL_AEAD_SET_IVLEN, - check_len, - nullptr)) { + if (!ctx.setIvLength(check_len)) { return; } break; @@ -312,15 +310,15 @@ void CipherBase::CommonInit(const char* cipher_type, int iv_len, unsigned int auth_tag_len) { CHECK(!ctx_); - ctx_.reset(EVP_CIPHER_CTX_new()); + ctx_ = CipherCtxPointer::New(); + CHECK(ctx_); if (cipher.getMode() == EVP_CIPH_WRAP_MODE) { - EVP_CIPHER_CTX_set_flags(ctx_.get(), EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + ctx_.setFlags(EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); } const bool encrypt = (kind_ == kCipher); - if (1 != EVP_CipherInit_ex(ctx_.get(), cipher, nullptr, - nullptr, nullptr, encrypt)) { + if (!ctx_.init(cipher, encrypt)) { return ThrowCryptoError(env(), ERR_get_error(), "Failed to initialize cipher"); } @@ -331,12 +329,12 @@ void CipherBase::CommonInit(const char* cipher_type, return; } - if (!EVP_CIPHER_CTX_set_key_length(ctx_.get(), key_len)) { + if (!ctx_.setKeyLength(key_len)) { ctx_.reset(); return THROW_ERR_CRYPTO_INVALID_KEYLEN(env()); } - if (1 != EVP_CipherInit_ex(ctx_.get(), nullptr, nullptr, key, iv, encrypt)) { + if (!ctx_.init(ncrypto::Cipher(), encrypt, key, iv)) { return ThrowCryptoError(env(), ERR_get_error(), "Failed to initialize cipher"); } @@ -498,15 +496,12 @@ bool CipherBase::InitAuthenticated( CHECK(IsAuthenticatedMode()); MarkPopErrorOnReturn mark_pop_error_on_return; - if (!EVP_CIPHER_CTX_ctrl(ctx_.get(), - EVP_CTRL_AEAD_SET_IVLEN, - iv_len, - nullptr)) { + if (!ctx_.setIvLength(iv_len)) { THROW_ERR_CRYPTO_INVALID_IV(env()); return false; } - const int mode = EVP_CIPHER_CTX_mode(ctx_.get()); + const int mode = ctx_.getMode(); if (mode == EVP_CIPH_GCM_MODE) { if (auth_tag_len != kNoAuthTagLength) { if (!IsValidGCMTagLength(auth_tag_len)) { @@ -526,7 +521,7 @@ bool CipherBase::InitAuthenticated( // length defaults to 16 bytes when encrypting. Unlike GCM, the // authentication tag length also defaults to 16 bytes when decrypting, // whereas GCM would accept any valid authentication tag length. - if (EVP_CIPHER_CTX_nid(ctx_.get()) == NID_chacha20_poly1305) { + if (ctx_.getNid() == NID_chacha20_poly1305) { auth_tag_len = 16; } else { THROW_ERR_CRYPTO_INVALID_AUTH_TAG( @@ -549,8 +544,7 @@ bool CipherBase::InitAuthenticated( } // Tell OpenSSL about the desired length. - if (!EVP_CIPHER_CTX_ctrl(ctx_.get(), EVP_CTRL_AEAD_SET_TAG, auth_tag_len, - nullptr)) { + if (!ctx_.setAeadTagLength(auth_tag_len)) { THROW_ERR_CRYPTO_INVALID_AUTH_TAG( env(), "Invalid authentication tag length: %u", auth_tag_len); return false; @@ -573,7 +567,7 @@ bool CipherBase::InitAuthenticated( bool CipherBase::CheckCCMMessageLength(int message_len) { CHECK(ctx_); - CHECK(EVP_CIPHER_CTX_mode(ctx_.get()) == EVP_CIPH_CCM_MODE); + CHECK(ctx_.getMode() == EVP_CIPH_CCM_MODE); if (message_len > max_message_size_) { THROW_ERR_CRYPTO_INVALID_MESSAGELEN(env()); @@ -624,7 +618,7 @@ void CipherBase::SetAuthTag(const FunctionCallbackInfo& args) { } unsigned int tag_len = auth_tag.size(); - const int mode = EVP_CIPHER_CTX_mode(cipher->ctx_.get()); + const int mode = cipher->ctx_.getMode(); bool is_valid; if (mode == EVP_CIPH_GCM_MODE) { // Restrict GCM tag lengths according to NIST 800-38d, page 9. @@ -669,10 +663,11 @@ void CipherBase::SetAuthTag(const FunctionCallbackInfo& args) { bool CipherBase::MaybePassAuthTagToOpenSSL() { if (auth_tag_state_ == kAuthTagKnown) { - if (!EVP_CIPHER_CTX_ctrl(ctx_.get(), - EVP_CTRL_AEAD_SET_TAG, - auth_tag_len_, - reinterpret_cast(auth_tag_))) { + ncrypto::Buffer buffer{ + .data = auth_tag_, + .len = auth_tag_len_, + }; + if (!ctx_.setAeadTag(buffer)) { return false; } auth_tag_state_ = kAuthTagPassedToOpenSSL; @@ -688,7 +683,7 @@ bool CipherBase::SetAAD( MarkPopErrorOnReturn mark_pop_error_on_return; int outlen; - const int mode = EVP_CIPHER_CTX_mode(ctx_.get()); + const int mode = ctx_.getMode(); // When in CCM mode, we need to set the authentication tag and the plaintext // length in advance. @@ -707,16 +702,21 @@ bool CipherBase::SetAAD( return false; } + ncrypto::Buffer buffer{ + .data = nullptr, + .len = static_cast(plaintext_len), + }; // Specify the plaintext length. - if (!EVP_CipherUpdate(ctx_.get(), nullptr, &outlen, nullptr, plaintext_len)) + if (!ctx_.update(buffer, nullptr, &outlen)) { return false; + } } - return 1 == EVP_CipherUpdate(ctx_.get(), - nullptr, - &outlen, - data.data(), - data.size()); + ncrypto::Buffer buffer{ + .data = data.data(), + .len = data.size(), + }; + return ctx_.update(buffer, nullptr, &outlen); } void CipherBase::SetAAD(const FunctionCallbackInfo& args) { @@ -743,7 +743,7 @@ CipherBase::UpdateResult CipherBase::Update( return kErrorState; MarkPopErrorOnReturn mark_pop_error_on_return; - const int mode = EVP_CIPHER_CTX_mode(ctx_.get()); + const int mode = ctx_.getMode(); if (mode == EVP_CIPH_CCM_MODE && !CheckCCMMessageLength(len)) return kErrorMessageSize; @@ -753,19 +753,17 @@ CipherBase::UpdateResult CipherBase::Update( if (kind_ == kDecipher && IsAuthenticatedMode()) CHECK(MaybePassAuthTagToOpenSSL()); - const int block_size = EVP_CIPHER_CTX_block_size(ctx_.get()); + const int block_size = ctx_.getBlockSize(); CHECK_GT(block_size, 0); if (len + block_size > INT_MAX) return kErrorState; int buf_len = len + block_size; - // For key wrapping algorithms, get output size by calling - // EVP_CipherUpdate() with null output. + ncrypto::Buffer buffer = { + .data = reinterpret_cast(data), + .len = len, + }; if (kind_ == kCipher && mode == EVP_CIPH_WRAP_MODE && - EVP_CipherUpdate(ctx_.get(), - nullptr, - &buf_len, - reinterpret_cast(data), - len) != 1) { + !ctx_.update(buffer, nullptr, &buf_len)) { return kErrorState; } @@ -774,11 +772,13 @@ CipherBase::UpdateResult CipherBase::Update( *out = ArrayBuffer::NewBackingStore(env()->isolate(), buf_len); } - int r = EVP_CipherUpdate(ctx_.get(), - static_cast((*out)->Data()), - &buf_len, - reinterpret_cast(data), - len); + buffer = { + .data = reinterpret_cast(data), + .len = len, + }; + + bool r = ctx_.update( + buffer, static_cast((*out)->Data()), &buf_len); CHECK_LE(static_cast(buf_len), (*out)->ByteLength()); if (buf_len == 0) { @@ -830,7 +830,7 @@ bool CipherBase::SetAutoPadding(bool auto_padding) { if (!ctx_) return false; MarkPopErrorOnReturn mark_pop_error_on_return; - return EVP_CIPHER_CTX_set_padding(ctx_.get(), auto_padding); + return ctx_.setPadding(auto_padding); } void CipherBase::SetAutoPadding(const FunctionCallbackInfo& args) { @@ -845,12 +845,12 @@ bool CipherBase::Final(std::unique_ptr* out) { if (!ctx_) return false; - const int mode = EVP_CIPHER_CTX_mode(ctx_.get()); + const int mode = ctx_.getMode(); { NoArrayBufferZeroFillScope no_zero_fill_scope(env()->isolate_data()); - *out = ArrayBuffer::NewBackingStore(env()->isolate(), - static_cast(EVP_CIPHER_CTX_block_size(ctx_.get()))); + *out = ArrayBuffer::NewBackingStore( + env()->isolate(), static_cast(ctx_.getBlockSize())); } if (kind_ == kDecipher && @@ -861,7 +861,7 @@ bool CipherBase::Final(std::unique_ptr* out) { // OpenSSL v1.x doesn't verify the presence of the auth tag so do // it ourselves, see https://github.com/nodejs/node/issues/45874. if (OPENSSL_VERSION_NUMBER < 0x30000000L && kind_ == kDecipher && - NID_chacha20_poly1305 == EVP_CIPHER_CTX_nid(ctx_.get()) && + NID_chacha20_poly1305 == ctx_.getNid() && auth_tag_state_ != kAuthTagPassedToOpenSSL) { return false; } @@ -874,9 +874,8 @@ bool CipherBase::Final(std::unique_ptr* out) { *out = ArrayBuffer::NewBackingStore(env()->isolate(), 0); } else { int out_len = (*out)->ByteLength(); - ok = EVP_CipherFinal_ex(ctx_.get(), - static_cast((*out)->Data()), - &out_len) == 1; + ok = ctx_.update( + {}, static_cast((*out)->Data()), &out_len, true); CHECK_LE(static_cast(out_len), (*out)->ByteLength()); if (out_len == 0) { @@ -897,9 +896,8 @@ bool CipherBase::Final(std::unique_ptr* out) { CHECK(mode == EVP_CIPH_GCM_MODE); auth_tag_len_ = sizeof(auth_tag_); } - ok = (1 == EVP_CIPHER_CTX_ctrl(ctx_.get(), EVP_CTRL_AEAD_GET_TAG, - auth_tag_len_, - reinterpret_cast(auth_tag_))); + ok = ctx_.getAeadTag(auth_tag_len_, + reinterpret_cast(auth_tag_)); } }