/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/crypto/crypto_hmac.cc
270 строк
8 KB
Filip Skokan
src: implement MemoryRetainer protocol for ByteSource
29 июл 2026, 20:48
Не верифицирован
29 июл 2026, 20:48
29d183d
Код
Авторство
О чём код?
#include "crypto/crypto_hmac.h" #include "async_wrap-inl.h" #include "base_object-inl.h" #include "crypto/crypto_keys.h" #include "crypto/crypto_sig.h" #include "crypto/crypto_util.h" #include "env-inl.h" #include "memory_tracker-inl.h" #include "node_buffer.h" #include "string_bytes.h" #include "threadpoolwork-inl.h" #include "v8.h" namespace node { using ncrypto::Digest; using ncrypto::HMACCtxPointer; using v8::Boolean; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::HandleScope; using v8::Isolate; using v8::JustVoid; using v8::Local; using v8::Maybe; using v8::MaybeLocal; using v8::Nothing; using v8::Object; using v8::Uint32; using v8::Value; namespace crypto { Hmac::Hmac(Environment* env, Local<Object> wrap) : BaseObject(env, wrap) { MakeWeak(); } void Hmac::MemoryInfo(MemoryTracker* tracker) const { tracker->TrackFieldWithSize("context", ctx_ ? kSizeOf_HMAC_CTX : 0); } void Hmac::Initialize(Environment* env, Local<Object> target) { Isolate* isolate = env->isolate(); Local<FunctionTemplate> t = NewFunctionTemplate(isolate, New); t->InstanceTemplate()->SetInternalFieldCount(Hmac::kInternalFieldCount); SetProtoMethod(isolate, t, "init", HmacInit); SetProtoMethod(isolate, t, "update", HmacUpdate); SetProtoMethod(isolate, t, "digest", HmacDigest); SetConstructorFunction(env->context(), target, "Hmac", t); HmacJob::Initialize(env, target); } void Hmac::RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(New); registry->Register(HmacInit); registry->Register(HmacUpdate); registry->Register(HmacDigest); HmacJob::RegisterExternalReferences(registry); } void Hmac::New(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); new Hmac(env, args.This()); } void Hmac::HmacInit(const char* hash_type, const char* key, int key_len) { HandleScope scope(env()->isolate()); Digest md = Digest::FromName(hash_type); if (!md) [[unlikely]] { return THROW_ERR_CRYPTO_INVALID_DIGEST( env(), "Invalid digest: %s", hash_type); } if (key_len == 0) { key = ""; } ctx_ = HMACCtxPointer::New(); ncrypto::Buffer<const void> key_buf{ .data = key, .len = static_cast<size_t>(key_len), }; if (!ctx_.init(key_buf, md)) [[unlikely]] { ctx_.reset(); return ThrowCryptoError(env(), ERR_get_error()); } } void Hmac::HmacInit(const FunctionCallbackInfo<Value>& args) { Hmac* hmac; ASSIGN_OR_RETURN_UNWRAP(&hmac, args.This()); Environment* env = hmac->env(); const node::Utf8Value hash_type(env->isolate(), args[0]); ByteSource key = ByteSource::FromSecretKeyBytes(env, args[1]); hmac->HmacInit(*hash_type, key.data<char>(), key.size()); } bool Hmac::HmacUpdate(const char* data, size_t len) { ncrypto::Buffer<const void> buf{ .data = data, .len = len, }; return ctx_.update(buf); } void Hmac::HmacUpdate(const FunctionCallbackInfo<Value>& args) { Decode<Hmac>(args, [](Hmac* hmac, const FunctionCallbackInfo<Value>& args, const char* data, size_t size) { Environment* env = Environment::GetCurrent(args); if (size > INT_MAX) [[unlikely]] return THROW_ERR_OUT_OF_RANGE(env, "data is too long"); bool r = hmac->HmacUpdate(data, size); args.GetReturnValue().Set(r); }); } void Hmac::HmacDigest(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); Hmac* hmac; ASSIGN_OR_RETURN_UNWRAP(&hmac, args.This()); enum encoding encoding = BUFFER; if (args.Length() >= 1) { encoding = ParseEncoding(env->isolate(), args[0], BUFFER); } unsigned char md_value[Digest::MAX_SIZE]; ncrypto::Buffer<void> buf{ .data = md_value, .len = sizeof(md_value), }; if (hmac->ctx_) { if (!hmac->ctx_.digestInto(&buf)) [[unlikely]] { hmac->ctx_.reset(); return ThrowCryptoError(env, ERR_get_error(), "Failed to finalize HMAC"); } hmac->ctx_.reset(); } Local<Value> ret; if (StringBytes::Encode(env->isolate(), reinterpret_cast<const char*>(md_value), buf.len, encoding) .ToLocal(&ret)) { args.GetReturnValue().Set(ret); } } HmacConfig::HmacConfig(HmacConfig&& other) noexcept : mode(other.mode), key(std::move(other.key)), data(std::move(other.data)), signature(std::move(other.signature)), digest(other.digest) {} HmacConfig& HmacConfig::operator=(HmacConfig&& other) noexcept { if (&other == this) return *this; this->~HmacConfig(); return *new (this) HmacConfig(std::move(other)); } void HmacConfig::MemoryInfo(MemoryTracker* tracker) const { tracker->TrackField("key", key); tracker->TraitTrackInline(data, "data"); tracker->TraitTrackInline(signature, "signature"); } Maybe<void> HmacTraits::AdditionalConfig( CryptoJobMode mode, const FunctionCallbackInfo<Value>& args, unsigned int offset, HmacConfig* params) { Environment* env = Environment::GetCurrent(args); CHECK(args[offset]->IsUint32()); // SignConfiguration::Mode params->mode = static_cast<SignConfiguration::Mode>(args[offset].As<Uint32>()->Value()); CHECK(args[offset + 1]->IsString()); // Hash CHECK(args[offset + 2]->IsObject()); // Key Utf8Value digest(env->isolate(), args[offset + 1]); params->digest = Digest::FromName(*digest); if (!params->digest) [[unlikely]] { THROW_ERR_CRYPTO_INVALID_DIGEST(env, "Invalid digest: %s", digest); return Nothing<void>(); } KeyObjectHandle* key; ASSIGN_OR_RETURN_UNWRAP(&key, args[offset + 2], Nothing<void>()); params->key = key->Data().addRef(); ArrayBufferOrViewContents<char> data(args[offset + 3]); if (!data.CheckSizeInt32()) [[unlikely]] { THROW_ERR_OUT_OF_RANGE(env, "data is too big"); return Nothing<void>(); } params->data = IsCryptoJobAsync(mode) ? data.ToCopy() : data.ToByteSource(); if (!args[offset + 4]->IsUndefined()) { ArrayBufferOrViewContents<char> signature(args[offset + 4]); if (!signature.CheckSizeInt32()) [[unlikely]] { THROW_ERR_OUT_OF_RANGE(env, "signature is too big"); return Nothing<void>(); } params->signature = IsCryptoJobAsync(mode) ? signature.ToCopy() : signature.ToByteSource(); } return JustVoid(); } bool HmacTraits::DeriveBits(Environment* env, const HmacConfig& params, ByteSource* out, CryptoJobMode mode, CryptoErrorStore* errors) { auto ctx = HMACCtxPointer::New(); ncrypto::Buffer<const void> key_buf{ .data = params.key.GetSymmetricKey(), .len = params.key.GetSymmetricKeySize(), }; if (!ctx.init(key_buf, params.digest)) [[unlikely]] { return false; } ncrypto::Buffer<const void> buffer{ .data = params.data.data(), .len = params.data.size(), }; if (!ctx.update(buffer)) [[unlikely]] { return false; } auto buf = ctx.digest(); if (!buf) [[unlikely]] return false; DCHECK(!buf.isSecure()); *out = ByteSource::Allocated(buf.release()); return true; } MaybeLocal<Value> HmacTraits::EncodeOutput(Environment* env, const HmacConfig& params, ByteSource* out) { switch (params.mode) { case SignConfiguration::Mode::Sign: return out->ToArrayBuffer(env); case SignConfiguration::Mode::Verify: return Boolean::New( env->isolate(), out->size() > 0 && out->size() == params.signature.size() && CRYPTO_memcmp( out->data(), params.signature.data(), out->size()) == 0); } UNREACHABLE(); } } // namespace crypto } // namespace node