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