%PDF- <> %âãÏÓ endobj 2 0 obj <> endobj 3 0 obj <>/ExtGState<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/Annots[ 28 0 R 29 0 R] /MediaBox[ 0 0 595.5 842.25] /Contents 4 0 R/Group<>/Tabs/S>> endobj ºaâÚÎΞ-ÌE1ÍØÄ÷{òò2ÿ ÛÖ^ÔÀá TÎ{¦?§®¥kuµùÕ5sLOšuY>endobj 2 0 obj<>endobj 2 0 obj<>endobj 2 0 obj<>endobj 2 0 obj<> endobj 2 0 obj<>endobj 2 0 obj<>es 3 0 R>> endobj 2 0 obj<> ox[ 0.000000 0.000000 609.600000 935.600000]/Fi endobj 3 0 obj<> endobj 7 1 obj<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI]>>/Subtype/Form>> stream
#include "crypto/crypto_hkdf.h" #include "async_wrap-inl.h" #include "base_object-inl.h" #include "crypto/crypto_keys.h" #include "env-inl.h" #include "memory_tracker-inl.h" #include "threadpoolwork-inl.h" #include "v8.h" namespace node { using v8::FunctionCallbackInfo; using v8::Just; using v8::Maybe; using v8::Nothing; using v8::Uint32; using v8::Value; namespace crypto { HKDFConfig::HKDFConfig(HKDFConfig&& other) noexcept : mode(other.mode), length(other.length), digest(other.digest), key(other.key), salt(std::move(other.salt)), info(std::move(other.info)) {} HKDFConfig& HKDFConfig::operator=(HKDFConfig&& other) noexcept { if (&other == this) return *this; this->~HKDFConfig(); return *new (this) HKDFConfig(std::move(other)); } Maybe<bool> HKDFTraits::EncodeOutput( Environment* env, const HKDFConfig& params, ByteSource* out, v8::Local<v8::Value>* result) { *result = out->ToArrayBuffer(env); return Just(!result->IsEmpty()); } Maybe<bool> HKDFTraits::AdditionalConfig( CryptoJobMode mode, const FunctionCallbackInfo<Value>& args, unsigned int offset, HKDFConfig* params) { Environment* env = Environment::GetCurrent(args); params->mode = mode; CHECK(args[offset]->IsString()); // Hash CHECK(args[offset + 1]->IsObject()); // Key CHECK(IsAnyByteSource(args[offset + 2])); // Salt CHECK(IsAnyByteSource(args[offset + 3])); // Info CHECK(args[offset + 4]->IsUint32()); // Length Utf8Value hash(env->isolate(), args[offset]); params->digest = EVP_get_digestbyname(*hash); if (params->digest == nullptr) { THROW_ERR_CRYPTO_INVALID_DIGEST(env, "Invalid digest: %s", *hash); return Nothing<bool>(); } KeyObjectHandle* key; ASSIGN_OR_RETURN_UNWRAP(&key, args[offset + 1], Nothing<bool>()); params->key = key->Data(); ArrayBufferOrViewContents<char> salt(args[offset + 2]); ArrayBufferOrViewContents<char> info(args[offset + 3]); if (UNLIKELY(!salt.CheckSizeInt32())) { THROW_ERR_OUT_OF_RANGE(env, "salt is too big"); return Nothing<bool>(); } if (UNLIKELY(!info.CheckSizeInt32())) { THROW_ERR_OUT_OF_RANGE(env, "info is too big"); return Nothing<bool>(); } params->salt = mode == kCryptoJobAsync ? salt.ToCopy() : salt.ToByteSource(); params->info = mode == kCryptoJobAsync ? info.ToCopy() : info.ToByteSource(); params->length = args[offset + 4].As<Uint32>()->Value(); size_t max_length = EVP_MD_size(params->digest) * kMaxDigestMultiplier; if (params->length > max_length) { THROW_ERR_CRYPTO_INVALID_KEYLEN(env); return Nothing<bool>(); } return Just(true); } bool HKDFTraits::DeriveBits( Environment* env, const HKDFConfig& params, ByteSource* out) { EVPKeyCtxPointer ctx = EVPKeyCtxPointer(EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr)); if (!ctx || !EVP_PKEY_derive_init(ctx.get()) || !EVP_PKEY_CTX_set_hkdf_md(ctx.get(), params.digest) || !EVP_PKEY_CTX_add1_hkdf_info( ctx.get(), reinterpret_cast<const unsigned char*>(params.info.get()), params.info.size())) { return false; } // TODO(panva): Once support for OpenSSL 1.1.1 is dropped the whole // of HKDFTraits::DeriveBits can be refactored to use // EVP_KDF which does handle zero length key. if (params.key->GetSymmetricKeySize() != 0) { if (!EVP_PKEY_CTX_hkdf_mode(ctx.get(), EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND) || !EVP_PKEY_CTX_set1_hkdf_salt( ctx.get(), params.salt.data<unsigned char>(), params.salt.size()) || !EVP_PKEY_CTX_set1_hkdf_key(ctx.get(), reinterpret_cast<const unsigned char*>( params.key->GetSymmetricKey()), params.key->GetSymmetricKeySize())) { return false; } } else { // Workaround for EVP_PKEY_derive HKDF not handling zero length keys. unsigned char temp_key[EVP_MAX_MD_SIZE]; unsigned int len = sizeof(temp_key); if (params.salt.size() != 0) { if (HMAC(params.digest, params.salt.data<unsigned char>(), params.salt.size(), nullptr, 0, temp_key, &len) == nullptr) { return false; } } else { char salt[EVP_MAX_MD_SIZE] = {0}; if (HMAC(params.digest, salt, EVP_MD_size(params.digest), nullptr, 0, temp_key, &len) == nullptr) { return false; } } if (!EVP_PKEY_CTX_hkdf_mode(ctx.get(), EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) || !EVP_PKEY_CTX_set1_hkdf_key(ctx.get(), temp_key, len)) { return false; } } size_t length = params.length; char* data = MallocOpenSSL<char>(length); ByteSource buf = ByteSource::Allocated(data, length); unsigned char* ptr = reinterpret_cast<unsigned char*>(data); if (EVP_PKEY_derive(ctx.get(), ptr, &length) <= 0) return false; *out = std::move(buf); return true; } void HKDFConfig::MemoryInfo(MemoryTracker* tracker) const { tracker->TrackField("key", key); // If the job is sync, then the HKDFConfig does not own the data if (mode == kCryptoJobAsync) { tracker->TrackFieldWithSize("salt", salt.size()); tracker->TrackFieldWithSize("info", info.size()); } } } // namespace crypto } // namespace node