11cb0ef41Sopenharmony_ci#include "crypto/crypto_hmac.h"
21cb0ef41Sopenharmony_ci#include "async_wrap-inl.h"
31cb0ef41Sopenharmony_ci#include "base_object-inl.h"
41cb0ef41Sopenharmony_ci#include "crypto/crypto_keys.h"
51cb0ef41Sopenharmony_ci#include "crypto/crypto_sig.h"
61cb0ef41Sopenharmony_ci#include "crypto/crypto_util.h"
71cb0ef41Sopenharmony_ci#include "env-inl.h"
81cb0ef41Sopenharmony_ci#include "memory_tracker-inl.h"
91cb0ef41Sopenharmony_ci#include "node_buffer.h"
101cb0ef41Sopenharmony_ci#include "string_bytes.h"
111cb0ef41Sopenharmony_ci#include "threadpoolwork-inl.h"
121cb0ef41Sopenharmony_ci#include "v8.h"
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_cinamespace node {
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ciusing v8::Boolean;
171cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo;
181cb0ef41Sopenharmony_ciusing v8::FunctionTemplate;
191cb0ef41Sopenharmony_ciusing v8::HandleScope;
201cb0ef41Sopenharmony_ciusing v8::Isolate;
211cb0ef41Sopenharmony_ciusing v8::Just;
221cb0ef41Sopenharmony_ciusing v8::Local;
231cb0ef41Sopenharmony_ciusing v8::Maybe;
241cb0ef41Sopenharmony_ciusing v8::MaybeLocal;
251cb0ef41Sopenharmony_ciusing v8::Nothing;
261cb0ef41Sopenharmony_ciusing v8::Object;
271cb0ef41Sopenharmony_ciusing v8::Uint32;
281cb0ef41Sopenharmony_ciusing v8::Value;
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_cinamespace crypto {
311cb0ef41Sopenharmony_ciHmac::Hmac(Environment* env, Local<Object> wrap)
321cb0ef41Sopenharmony_ci    : BaseObject(env, wrap),
331cb0ef41Sopenharmony_ci      ctx_(nullptr) {
341cb0ef41Sopenharmony_ci  MakeWeak();
351cb0ef41Sopenharmony_ci}
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_civoid Hmac::MemoryInfo(MemoryTracker* tracker) const {
381cb0ef41Sopenharmony_ci  tracker->TrackFieldWithSize("context", ctx_ ? kSizeOf_HMAC_CTX : 0);
391cb0ef41Sopenharmony_ci}
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_civoid Hmac::Initialize(Environment* env, Local<Object> target) {
421cb0ef41Sopenharmony_ci  Isolate* isolate = env->isolate();
431cb0ef41Sopenharmony_ci  Local<FunctionTemplate> t = NewFunctionTemplate(isolate, New);
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci  t->InstanceTemplate()->SetInternalFieldCount(
461cb0ef41Sopenharmony_ci      Hmac::kInternalFieldCount);
471cb0ef41Sopenharmony_ci  t->Inherit(BaseObject::GetConstructorTemplate(env));
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci  SetProtoMethod(isolate, t, "init", HmacInit);
501cb0ef41Sopenharmony_ci  SetProtoMethod(isolate, t, "update", HmacUpdate);
511cb0ef41Sopenharmony_ci  SetProtoMethod(isolate, t, "digest", HmacDigest);
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci  SetConstructorFunction(env->context(), target, "Hmac", t);
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci  HmacJob::Initialize(env, target);
561cb0ef41Sopenharmony_ci}
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_civoid Hmac::RegisterExternalReferences(ExternalReferenceRegistry* registry) {
591cb0ef41Sopenharmony_ci  registry->Register(New);
601cb0ef41Sopenharmony_ci  registry->Register(HmacInit);
611cb0ef41Sopenharmony_ci  registry->Register(HmacUpdate);
621cb0ef41Sopenharmony_ci  registry->Register(HmacDigest);
631cb0ef41Sopenharmony_ci  HmacJob::RegisterExternalReferences(registry);
641cb0ef41Sopenharmony_ci}
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_civoid Hmac::New(const FunctionCallbackInfo<Value>& args) {
671cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
681cb0ef41Sopenharmony_ci  new Hmac(env, args.This());
691cb0ef41Sopenharmony_ci}
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_civoid Hmac::HmacInit(const char* hash_type, const char* key, int key_len) {
721cb0ef41Sopenharmony_ci  HandleScope scope(env()->isolate());
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci  const EVP_MD* md = EVP_get_digestbyname(hash_type);
751cb0ef41Sopenharmony_ci  if (md == nullptr)
761cb0ef41Sopenharmony_ci    return THROW_ERR_CRYPTO_INVALID_DIGEST(
771cb0ef41Sopenharmony_ci        env(), "Invalid digest: %s", hash_type);
781cb0ef41Sopenharmony_ci  if (key_len == 0) {
791cb0ef41Sopenharmony_ci    key = "";
801cb0ef41Sopenharmony_ci  }
811cb0ef41Sopenharmony_ci  ctx_.reset(HMAC_CTX_new());
821cb0ef41Sopenharmony_ci  if (!ctx_ || !HMAC_Init_ex(ctx_.get(), key, key_len, md, nullptr)) {
831cb0ef41Sopenharmony_ci    ctx_.reset();
841cb0ef41Sopenharmony_ci    return ThrowCryptoError(env(), ERR_get_error());
851cb0ef41Sopenharmony_ci  }
861cb0ef41Sopenharmony_ci}
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_civoid Hmac::HmacInit(const FunctionCallbackInfo<Value>& args) {
891cb0ef41Sopenharmony_ci  Hmac* hmac;
901cb0ef41Sopenharmony_ci  ASSIGN_OR_RETURN_UNWRAP(&hmac, args.Holder());
911cb0ef41Sopenharmony_ci  Environment* env = hmac->env();
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci  const node::Utf8Value hash_type(env->isolate(), args[0]);
941cb0ef41Sopenharmony_ci  ByteSource key = ByteSource::FromSecretKeyBytes(env, args[1]);
951cb0ef41Sopenharmony_ci  hmac->HmacInit(*hash_type, key.data<char>(), key.size());
961cb0ef41Sopenharmony_ci}
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_cibool Hmac::HmacUpdate(const char* data, size_t len) {
991cb0ef41Sopenharmony_ci  return ctx_ && HMAC_Update(ctx_.get(),
1001cb0ef41Sopenharmony_ci                             reinterpret_cast<const unsigned char*>(data),
1011cb0ef41Sopenharmony_ci                             len) == 1;
1021cb0ef41Sopenharmony_ci}
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_civoid Hmac::HmacUpdate(const FunctionCallbackInfo<Value>& args) {
1051cb0ef41Sopenharmony_ci  Decode<Hmac>(args, [](Hmac* hmac, const FunctionCallbackInfo<Value>& args,
1061cb0ef41Sopenharmony_ci                        const char* data, size_t size) {
1071cb0ef41Sopenharmony_ci    Environment* env = Environment::GetCurrent(args);
1081cb0ef41Sopenharmony_ci    if (UNLIKELY(size > INT_MAX))
1091cb0ef41Sopenharmony_ci      return THROW_ERR_OUT_OF_RANGE(env, "data is too long");
1101cb0ef41Sopenharmony_ci    bool r = hmac->HmacUpdate(data, size);
1111cb0ef41Sopenharmony_ci    args.GetReturnValue().Set(r);
1121cb0ef41Sopenharmony_ci  });
1131cb0ef41Sopenharmony_ci}
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_civoid Hmac::HmacDigest(const FunctionCallbackInfo<Value>& args) {
1161cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci  Hmac* hmac;
1191cb0ef41Sopenharmony_ci  ASSIGN_OR_RETURN_UNWRAP(&hmac, args.Holder());
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci  enum encoding encoding = BUFFER;
1221cb0ef41Sopenharmony_ci  if (args.Length() >= 1) {
1231cb0ef41Sopenharmony_ci    encoding = ParseEncoding(env->isolate(), args[0], BUFFER);
1241cb0ef41Sopenharmony_ci  }
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci  unsigned char md_value[EVP_MAX_MD_SIZE];
1271cb0ef41Sopenharmony_ci  unsigned int md_len = 0;
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  if (hmac->ctx_) {
1301cb0ef41Sopenharmony_ci    bool ok = HMAC_Final(hmac->ctx_.get(), md_value, &md_len);
1311cb0ef41Sopenharmony_ci    hmac->ctx_.reset();
1321cb0ef41Sopenharmony_ci    if (!ok) {
1331cb0ef41Sopenharmony_ci      return ThrowCryptoError(env, ERR_get_error(), "Failed to finalize HMAC");
1341cb0ef41Sopenharmony_ci    }
1351cb0ef41Sopenharmony_ci  }
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci  Local<Value> error;
1381cb0ef41Sopenharmony_ci  MaybeLocal<Value> rc =
1391cb0ef41Sopenharmony_ci      StringBytes::Encode(env->isolate(),
1401cb0ef41Sopenharmony_ci                          reinterpret_cast<const char*>(md_value),
1411cb0ef41Sopenharmony_ci                          md_len,
1421cb0ef41Sopenharmony_ci                          encoding,
1431cb0ef41Sopenharmony_ci                          &error);
1441cb0ef41Sopenharmony_ci  if (rc.IsEmpty()) {
1451cb0ef41Sopenharmony_ci    CHECK(!error.IsEmpty());
1461cb0ef41Sopenharmony_ci    env->isolate()->ThrowException(error);
1471cb0ef41Sopenharmony_ci    return;
1481cb0ef41Sopenharmony_ci  }
1491cb0ef41Sopenharmony_ci  args.GetReturnValue().Set(rc.FromMaybe(Local<Value>()));
1501cb0ef41Sopenharmony_ci}
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ciHmacConfig::HmacConfig(HmacConfig&& other) noexcept
1531cb0ef41Sopenharmony_ci    : job_mode(other.job_mode),
1541cb0ef41Sopenharmony_ci      mode(other.mode),
1551cb0ef41Sopenharmony_ci      key(std::move(other.key)),
1561cb0ef41Sopenharmony_ci      data(std::move(other.data)),
1571cb0ef41Sopenharmony_ci      signature(std::move(other.signature)),
1581cb0ef41Sopenharmony_ci      digest(other.digest) {}
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ciHmacConfig& HmacConfig::operator=(HmacConfig&& other) noexcept {
1611cb0ef41Sopenharmony_ci  if (&other == this) return *this;
1621cb0ef41Sopenharmony_ci  this->~HmacConfig();
1631cb0ef41Sopenharmony_ci  return *new (this) HmacConfig(std::move(other));
1641cb0ef41Sopenharmony_ci}
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_civoid HmacConfig::MemoryInfo(MemoryTracker* tracker) const {
1671cb0ef41Sopenharmony_ci  tracker->TrackField("key", key.get());
1681cb0ef41Sopenharmony_ci  // If the job is sync, then the HmacConfig does not own the data
1691cb0ef41Sopenharmony_ci  if (job_mode == kCryptoJobAsync) {
1701cb0ef41Sopenharmony_ci    tracker->TrackFieldWithSize("data", data.size());
1711cb0ef41Sopenharmony_ci    tracker->TrackFieldWithSize("signature", signature.size());
1721cb0ef41Sopenharmony_ci  }
1731cb0ef41Sopenharmony_ci}
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ciMaybe<bool> HmacTraits::AdditionalConfig(
1761cb0ef41Sopenharmony_ci    CryptoJobMode mode,
1771cb0ef41Sopenharmony_ci    const FunctionCallbackInfo<Value>& args,
1781cb0ef41Sopenharmony_ci    unsigned int offset,
1791cb0ef41Sopenharmony_ci    HmacConfig* params) {
1801cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci  params->job_mode = mode;
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci  CHECK(args[offset]->IsUint32());  // SignConfiguration::Mode
1851cb0ef41Sopenharmony_ci  params->mode =
1861cb0ef41Sopenharmony_ci    static_cast<SignConfiguration::Mode>(args[offset].As<Uint32>()->Value());
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci  CHECK(args[offset + 1]->IsString());  // Hash
1891cb0ef41Sopenharmony_ci  CHECK(args[offset + 2]->IsObject());  // Key
1901cb0ef41Sopenharmony_ci
1911cb0ef41Sopenharmony_ci  Utf8Value digest(env->isolate(), args[offset + 1]);
1921cb0ef41Sopenharmony_ci  params->digest = EVP_get_digestbyname(*digest);
1931cb0ef41Sopenharmony_ci  if (params->digest == nullptr) {
1941cb0ef41Sopenharmony_ci    THROW_ERR_CRYPTO_INVALID_DIGEST(env, "Invalid digest: %s", *digest);
1951cb0ef41Sopenharmony_ci    return Nothing<bool>();
1961cb0ef41Sopenharmony_ci  }
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ci  KeyObjectHandle* key;
1991cb0ef41Sopenharmony_ci  ASSIGN_OR_RETURN_UNWRAP(&key, args[offset + 2], Nothing<bool>());
2001cb0ef41Sopenharmony_ci  params->key = key->Data();
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci  ArrayBufferOrViewContents<char> data(args[offset + 3]);
2031cb0ef41Sopenharmony_ci  if (UNLIKELY(!data.CheckSizeInt32())) {
2041cb0ef41Sopenharmony_ci    THROW_ERR_OUT_OF_RANGE(env, "data is too big");
2051cb0ef41Sopenharmony_ci    return Nothing<bool>();
2061cb0ef41Sopenharmony_ci  }
2071cb0ef41Sopenharmony_ci  params->data = mode == kCryptoJobAsync
2081cb0ef41Sopenharmony_ci      ? data.ToCopy()
2091cb0ef41Sopenharmony_ci      : data.ToByteSource();
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_ci  if (!args[offset + 4]->IsUndefined()) {
2121cb0ef41Sopenharmony_ci    ArrayBufferOrViewContents<char> signature(args[offset + 4]);
2131cb0ef41Sopenharmony_ci    if (UNLIKELY(!signature.CheckSizeInt32())) {
2141cb0ef41Sopenharmony_ci      THROW_ERR_OUT_OF_RANGE(env, "signature is too big");
2151cb0ef41Sopenharmony_ci      return Nothing<bool>();
2161cb0ef41Sopenharmony_ci    }
2171cb0ef41Sopenharmony_ci    params->signature = mode == kCryptoJobAsync
2181cb0ef41Sopenharmony_ci        ? signature.ToCopy()
2191cb0ef41Sopenharmony_ci        : signature.ToByteSource();
2201cb0ef41Sopenharmony_ci  }
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_ci  return Just(true);
2231cb0ef41Sopenharmony_ci}
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_cibool HmacTraits::DeriveBits(
2261cb0ef41Sopenharmony_ci    Environment* env,
2271cb0ef41Sopenharmony_ci    const HmacConfig& params,
2281cb0ef41Sopenharmony_ci    ByteSource* out) {
2291cb0ef41Sopenharmony_ci  HMACCtxPointer ctx(HMAC_CTX_new());
2301cb0ef41Sopenharmony_ci
2311cb0ef41Sopenharmony_ci  if (!ctx ||
2321cb0ef41Sopenharmony_ci      !HMAC_Init_ex(
2331cb0ef41Sopenharmony_ci          ctx.get(),
2341cb0ef41Sopenharmony_ci          params.key->GetSymmetricKey(),
2351cb0ef41Sopenharmony_ci          params.key->GetSymmetricKeySize(),
2361cb0ef41Sopenharmony_ci          params.digest,
2371cb0ef41Sopenharmony_ci          nullptr)) {
2381cb0ef41Sopenharmony_ci    return false;
2391cb0ef41Sopenharmony_ci  }
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_ci  if (!HMAC_Update(
2421cb0ef41Sopenharmony_ci          ctx.get(),
2431cb0ef41Sopenharmony_ci          params.data.data<unsigned char>(),
2441cb0ef41Sopenharmony_ci          params.data.size())) {
2451cb0ef41Sopenharmony_ci    return false;
2461cb0ef41Sopenharmony_ci  }
2471cb0ef41Sopenharmony_ci
2481cb0ef41Sopenharmony_ci  ByteSource::Builder buf(EVP_MAX_MD_SIZE);
2491cb0ef41Sopenharmony_ci  unsigned int len;
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_ci  if (!HMAC_Final(ctx.get(), buf.data<unsigned char>(), &len)) {
2521cb0ef41Sopenharmony_ci    return false;
2531cb0ef41Sopenharmony_ci  }
2541cb0ef41Sopenharmony_ci
2551cb0ef41Sopenharmony_ci  *out = std::move(buf).release(len);
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ci  return true;
2581cb0ef41Sopenharmony_ci}
2591cb0ef41Sopenharmony_ci
2601cb0ef41Sopenharmony_ciMaybe<bool> HmacTraits::EncodeOutput(
2611cb0ef41Sopenharmony_ci    Environment* env,
2621cb0ef41Sopenharmony_ci    const HmacConfig& params,
2631cb0ef41Sopenharmony_ci    ByteSource* out,
2641cb0ef41Sopenharmony_ci    Local<Value>* result) {
2651cb0ef41Sopenharmony_ci  switch (params.mode) {
2661cb0ef41Sopenharmony_ci    case SignConfiguration::kSign:
2671cb0ef41Sopenharmony_ci      *result = out->ToArrayBuffer(env);
2681cb0ef41Sopenharmony_ci      break;
2691cb0ef41Sopenharmony_ci    case SignConfiguration::kVerify:
2701cb0ef41Sopenharmony_ci      *result = Boolean::New(
2711cb0ef41Sopenharmony_ci          env->isolate(),
2721cb0ef41Sopenharmony_ci          out->size() > 0 && out->size() == params.signature.size() &&
2731cb0ef41Sopenharmony_ci              memcmp(out->data(), params.signature.data(), out->size()) == 0);
2741cb0ef41Sopenharmony_ci      break;
2751cb0ef41Sopenharmony_ci    default:
2761cb0ef41Sopenharmony_ci      UNREACHABLE();
2771cb0ef41Sopenharmony_ci  }
2781cb0ef41Sopenharmony_ci  return Just(!result->IsEmpty());
2791cb0ef41Sopenharmony_ci}
2801cb0ef41Sopenharmony_ci
2811cb0ef41Sopenharmony_ci}  // namespace crypto
2821cb0ef41Sopenharmony_ci}  // namespace node
283