/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/crypto/crypto_kem.cc
267 строк
8 KB
Filip Skokan
src: implement MemoryRetainer protocol for ByteSource
29 июл 2026, 20:48
Не верифицирован
29 июл 2026, 20:48
29d183d
Код
Авторство
О чём код?
#include "crypto/crypto_kem.h" #if OPENSSL_WITH_KEM #include "async_wrap-inl.h" #include "base_object-inl.h" #include "crypto/crypto_keys.h" #include "crypto/crypto_util.h" #include "env-inl.h" #include "memory_tracker-inl.h" #include "threadpoolwork-inl.h" #include "v8.h" namespace node { using ncrypto::EVPKeyPointer; using v8::Array; using v8::FunctionCallbackInfo; using v8::Local; using v8::Maybe; using v8::MaybeLocal; using v8::Nothing; using v8::Object; using v8::Uint8Array; using v8::Value; namespace crypto { KEMConfiguration::KEMConfiguration(KEMConfiguration&& other) noexcept : key(std::move(other.key)), ciphertext(std::move(other.ciphertext)) {} KEMConfiguration& KEMConfiguration::operator=( KEMConfiguration&& other) noexcept { if (&other == this) return *this; this->~KEMConfiguration(); return *new (this) KEMConfiguration(std::move(other)); } void KEMConfiguration::MemoryInfo(MemoryTracker* tracker) const { tracker->TrackField("key", key); tracker->TraitTrackInline(ciphertext, "ciphertext"); } namespace { bool DoKEMDecapsulate(Environment* env, const EVPKeyPointer& private_key, const ByteSource& ciphertext, ByteSource* out, CryptoJobMode mode, CryptoErrorStore* errors) { ncrypto::Buffer<const void> ciphertext_buf{ciphertext.data(), ciphertext.size()}; auto shared_key = ncrypto::KEM::Decapsulate(private_key, ciphertext_buf); if (!shared_key) { errors->Insert(NodeCryptoError::DECAPSULATION_FAILED); errors->SetNodeErrorCode("ERR_CRYPTO_OPERATION_FAILED"); return false; } *out = ByteSource::Allocated(shared_key.release()); return true; } } // anonymous namespace // KEMEncapsulateTraits implementation Maybe<void> KEMEncapsulateTraits::AdditionalConfig( CryptoJobMode mode, const FunctionCallbackInfo<Value>& args, unsigned int offset, KEMConfiguration* params) { unsigned int key_offset = offset; auto public_key_data = KeyObjectData::GetPublicOrPrivateKeyFromJs(args, &key_offset); if (!public_key_data) { return Nothing<void>(); } params->key = std::move(public_key_data); return v8::JustVoid(); } void KEMEncapsulateJob::New(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); CHECK(args.IsConstructCall()); CryptoJobMode mode = GetCryptoJobMode(args[0]); AdditionalParams params; if (KEMEncapsulateTraits::AdditionalConfig(mode, args, 1, ¶ms) .IsNothing()) { return; } new KEMEncapsulateJob(env, args.This(), mode, std::move(params)); } void KEMEncapsulateJob::Initialize(Environment* env, Local<Object> target) { CryptoJob<KEMEncapsulateTraits>::Initialize(New, env, target); } void KEMEncapsulateJob::RegisterExternalReferences( ExternalReferenceRegistry* registry) { CryptoJob<KEMEncapsulateTraits>::RegisterExternalReferences(New, registry); } KEMEncapsulateJob::KEMEncapsulateJob(Environment* env, Local<Object> object, CryptoJobMode mode, AdditionalParams&& params) : CryptoJob<KEMEncapsulateTraits>(env, object, KEMEncapsulateTraits::Provider, mode, std::move(params)) {} void KEMEncapsulateJob::DoThreadPoolWork() { ncrypto::ClearErrorOnReturn clear_error_on_return; AdditionalParams* params = CryptoJob<KEMEncapsulateTraits>::params(); Mutex::ScopedLock lock(params->key.mutex()); auto result = ncrypto::KEM::Encapsulate(params->key.GetAsymmetricKey()); if (result) { out_.emplace(); out_->ciphertext = ByteSource::Allocated(result->ciphertext.release()); out_->shared_key = ByteSource::Allocated(result->shared_key.release()); } else { CryptoErrorStore* errors = CryptoJob<KEMEncapsulateTraits>::errors(); errors->Insert(NodeCryptoError::ENCAPSULATION_FAILED); errors->SetNodeErrorCode("ERR_CRYPTO_OPERATION_FAILED"); } } Maybe<void> KEMEncapsulateJob::ToResult(Local<Value>* err, Local<Value>* result) { Environment* env = AsyncWrap::env(); CryptoErrorStore* errors = CryptoJob<KEMEncapsulateTraits>::errors(); if (!out_) { if (errors->Empty()) errors->Capture(); CHECK(!errors->Empty()); *result = v8::Undefined(env->isolate()); if (!errors->ToException(env).ToLocal(err)) return Nothing<void>(); return v8::JustVoid(); } CHECK(errors->Empty()); *err = v8::Undefined(env->isolate()); ByteSource ciphertext = std::move(out_->ciphertext); ByteSource shared_key = std::move(out_->shared_key); if (mode() == kCryptoJobWebCrypto) { Local<Object> output = Object::New(env->isolate()); if (!output ->DefineOwnProperty(env->context(), OneByteString(env->isolate(), "sharedKey"), shared_key.ToArrayBuffer(env)) .FromMaybe(false) || !output ->DefineOwnProperty(env->context(), OneByteString(env->isolate(), "ciphertext"), ciphertext.ToArrayBuffer(env)) .FromMaybe(false)) { return Nothing<void>(); } *result = output; return v8::JustVoid(); } Local<Uint8Array> shared_key_buf; Local<Uint8Array> ciphertext_buf; if (!shared_key.ToBuffer(env).ToLocal(&shared_key_buf) || !ciphertext.ToBuffer(env).ToLocal(&ciphertext_buf)) { return Nothing<void>(); } Local<Array> output = Array::New(env->isolate(), 2); if (output->Set(env->context(), 0, shared_key_buf).IsNothing() || output->Set(env->context(), 1, ciphertext_buf).IsNothing()) { return Nothing<void>(); } *result = output; return v8::JustVoid(); } void KEMEncapsulateJob::MemoryInfo(MemoryTracker* tracker) const { if (out_) { tracker->TraitTrackInline(out_->ciphertext, "ciphertext"); tracker->TraitTrackInline(out_->shared_key, "shared_key"); } CryptoJob<KEMEncapsulateTraits>::MemoryInfo(tracker); } // KEMDecapsulateTraits implementation Maybe<void> KEMDecapsulateTraits::AdditionalConfig( CryptoJobMode mode, const FunctionCallbackInfo<Value>& args, unsigned int offset, KEMConfiguration* params) { Environment* env = Environment::GetCurrent(args); unsigned int key_offset = offset; auto private_key_data = KeyObjectData::GetPrivateKeyFromJs(args, &key_offset, true); if (!private_key_data) { return Nothing<void>(); } params->key = std::move(private_key_data); ArrayBufferOrViewContents<unsigned char> ciphertext(args[key_offset]); if (!ciphertext.CheckSizeInt32()) { THROW_ERR_OUT_OF_RANGE(env, "ciphertext is too big"); return Nothing<void>(); } params->ciphertext = IsCryptoJobAsync(mode) ? ciphertext.ToCopy() : ciphertext.ToByteSource(); return v8::JustVoid(); } bool KEMDecapsulateTraits::DeriveBits(Environment* env, const KEMConfiguration& params, ByteSource* out, CryptoJobMode mode, CryptoErrorStore* errors) { Mutex::ScopedLock lock(params.key.mutex()); const auto& private_key = params.key.GetAsymmetricKey(); return DoKEMDecapsulate( env, private_key, params.ciphertext, out, mode, errors); } MaybeLocal<Value> KEMDecapsulateTraits::EncodeOutput( Environment* env, const KEMConfiguration& params, ByteSource* out) { return out->ToBuffer(env); } void InitializeKEM(Environment* env, Local<Object> target) { KEMEncapsulateJob::Initialize(env, target); KEMDecapsulateJob::Initialize(env, target); constexpr int kKEMEncapsulate = static_cast<int>(KEMMode::Encapsulate); constexpr int kKEMDecapsulate = static_cast<int>(KEMMode::Decapsulate); NODE_DEFINE_CONSTANT(target, kKEMEncapsulate); NODE_DEFINE_CONSTANT(target, kKEMDecapsulate); } void RegisterKEMExternalReferences(ExternalReferenceRegistry* registry) { KEMEncapsulateJob::RegisterExternalReferences(registry); KEMDecapsulateJob::RegisterExternalReferences(registry); } namespace KEM { void Initialize(Environment* env, Local<Object> target) { InitializeKEM(env, target); } void RegisterExternalReferences(ExternalReferenceRegistry* registry) { RegisterKEMExternalReferences(registry); } } // namespace KEM } // namespace crypto } // namespace node #endif