%PDF- %PDF-
| Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/src/crypto/ |
| Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/src/crypto/crypto_hmac.cc |
#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 v8::Boolean;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::HandleScope;
using v8::Isolate;
using v8::Just;
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),
ctx_(nullptr) {
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());
const EVP_MD* md = EVP_get_digestbyname(hash_type);
if (md == nullptr)
return THROW_ERR_CRYPTO_INVALID_DIGEST(
env(), "Invalid digest: %s", hash_type);
if (key_len == 0) {
key = "";
}
ctx_.reset(HMAC_CTX_new());
if (!ctx_ || !HMAC_Init_ex(ctx_.get(), key, key_len, md, nullptr)) {
ctx_.reset();
return ThrowCryptoError(env(), ERR_get_error());
}
}
void Hmac::HmacInit(const FunctionCallbackInfo<Value>& args) {
Hmac* hmac;
ASSIGN_OR_RETURN_UNWRAP(&hmac, args.Holder());
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) {
return ctx_ && HMAC_Update(ctx_.get(),
reinterpret_cast<const unsigned char*>(data),
len) == 1;
}
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 (UNLIKELY(size > INT_MAX))
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.Holder());
enum encoding encoding = BUFFER;
if (args.Length() >= 1) {
encoding = ParseEncoding(env->isolate(), args[0], BUFFER);
}
unsigned char md_value[EVP_MAX_MD_SIZE];
unsigned int md_len = 0;
if (hmac->ctx_) {
bool ok = HMAC_Final(hmac->ctx_.get(), md_value, &md_len);
hmac->ctx_.reset();
if (!ok) {
return ThrowCryptoError(env, ERR_get_error(), "Failed to finalize HMAC");
}
}
Local<Value> error;
MaybeLocal<Value> rc =
StringBytes::Encode(env->isolate(),
reinterpret_cast<const char*>(md_value),
md_len,
encoding,
&error);
if (rc.IsEmpty()) {
CHECK(!error.IsEmpty());
env->isolate()->ThrowException(error);
return;
}
args.GetReturnValue().Set(rc.FromMaybe(Local<Value>()));
}
HmacConfig::HmacConfig(HmacConfig&& other) noexcept
: job_mode(other.job_mode),
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.get());
// If the job is sync, then the HmacConfig does not own the data
if (job_mode == kCryptoJobAsync) {
tracker->TrackFieldWithSize("data", data.size());
tracker->TrackFieldWithSize("signature", signature.size());
}
}
Maybe<bool> HmacTraits::AdditionalConfig(
CryptoJobMode mode,
const FunctionCallbackInfo<Value>& args,
unsigned int offset,
HmacConfig* params) {
Environment* env = Environment::GetCurrent(args);
params->job_mode = mode;
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 = EVP_get_digestbyname(*digest);
if (params->digest == nullptr) {
THROW_ERR_CRYPTO_INVALID_DIGEST(env, "Invalid digest: %s", *digest);
return Nothing<bool>();
}
KeyObjectHandle* key;
ASSIGN_OR_RETURN_UNWRAP(&key, args[offset + 2], Nothing<bool>());
params->key = key->Data();
ArrayBufferOrViewContents<char> data(args[offset + 3]);
if (UNLIKELY(!data.CheckSizeInt32())) {
THROW_ERR_OUT_OF_RANGE(env, "data is too big");
return Nothing<bool>();
}
params->data = mode == kCryptoJobAsync
? data.ToCopy()
: data.ToByteSource();
if (!args[offset + 4]->IsUndefined()) {
ArrayBufferOrViewContents<char> signature(args[offset + 4]);
if (UNLIKELY(!signature.CheckSizeInt32())) {
THROW_ERR_OUT_OF_RANGE(env, "signature is too big");
return Nothing<bool>();
}
params->signature = mode == kCryptoJobAsync
? signature.ToCopy()
: signature.ToByteSource();
}
return Just(true);
}
bool HmacTraits::DeriveBits(
Environment* env,
const HmacConfig& params,
ByteSource* out) {
HMACCtxPointer ctx(HMAC_CTX_new());
if (!ctx ||
!HMAC_Init_ex(
ctx.get(),
params.key->GetSymmetricKey(),
params.key->GetSymmetricKeySize(),
params.digest,
nullptr)) {
return false;
}
if (!HMAC_Update(
ctx.get(),
params.data.data<unsigned char>(),
params.data.size())) {
return false;
}
ByteSource::Builder buf(EVP_MAX_MD_SIZE);
unsigned int len;
if (!HMAC_Final(ctx.get(), buf.data<unsigned char>(), &len)) {
return false;
}
*out = std::move(buf).release(len);
return true;
}
Maybe<bool> HmacTraits::EncodeOutput(
Environment* env,
const HmacConfig& params,
ByteSource* out,
Local<Value>* result) {
switch (params.mode) {
case SignConfiguration::kSign:
*result = out->ToArrayBuffer(env);
break;
case SignConfiguration::kVerify:
*result = Boolean::New(
env->isolate(),
out->size() > 0 && out->size() == params.signature.size() &&
memcmp(out->data(), params.signature.data(), out->size()) == 0);
break;
default:
UNREACHABLE();
}
return Just(!result->IsEmpty());
}
} // namespace crypto
} // namespace node