%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_dh.cc |
#include "crypto/crypto_dh.h"
#include "async_wrap-inl.h"
#include "base_object-inl.h"
#include "crypto/crypto_keys.h"
#include "crypto/crypto_util.h"
#include "env-inl.h"
#include "memory_tracker-inl.h"
#include "threadpoolwork-inl.h"
#include "v8.h"
#include <variant>
namespace node {
using v8::ArrayBuffer;
using v8::BackingStore;
using v8::ConstructorBehavior;
using v8::Context;
using v8::DontDelete;
using v8::FunctionCallback;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::HandleScope;
using v8::Int32;
using v8::Isolate;
using v8::Just;
using v8::Local;
using v8::Maybe;
using v8::Nothing;
using v8::Object;
using v8::PropertyAttribute;
using v8::ReadOnly;
using v8::SideEffectType;
using v8::Signature;
using v8::String;
using v8::Value;
namespace crypto {
namespace {
void ZeroPadDiffieHellmanSecret(size_t remainder_size,
char* data,
size_t length) {
// DH_size returns number of bytes in a prime number.
// DH_compute_key returns number of bytes in a remainder of exponent, which
// may have less bytes than a prime number. Therefore add 0-padding to the
// allocated buffer.
const size_t prime_size = length;
if (remainder_size != prime_size) {
CHECK_LT(remainder_size, prime_size);
const size_t padding = prime_size - remainder_size;
memmove(data + padding, data, remainder_size);
memset(data, 0, padding);
}
}
} // namespace
DiffieHellman::DiffieHellman(Environment* env, Local<Object> wrap)
: BaseObject(env, wrap), verifyError_(0) {
MakeWeak();
}
void DiffieHellman::Initialize(Environment* env, Local<Object> target) {
Isolate* isolate = env->isolate();
Local<Context> context = env->context();
auto make = [&](Local<String> name, FunctionCallback callback) {
Local<FunctionTemplate> t = NewFunctionTemplate(isolate, callback);
const PropertyAttribute attributes =
static_cast<PropertyAttribute>(ReadOnly | DontDelete);
t->InstanceTemplate()->SetInternalFieldCount(
DiffieHellman::kInternalFieldCount);
SetProtoMethod(isolate, t, "generateKeys", GenerateKeys);
SetProtoMethod(isolate, t, "computeSecret", ComputeSecret);
SetProtoMethodNoSideEffect(isolate, t, "getPrime", GetPrime);
SetProtoMethodNoSideEffect(isolate, t, "getGenerator", GetGenerator);
SetProtoMethodNoSideEffect(isolate, t, "getPublicKey", GetPublicKey);
SetProtoMethodNoSideEffect(isolate, t, "getPrivateKey", GetPrivateKey);
SetProtoMethod(isolate, t, "setPublicKey", SetPublicKey);
SetProtoMethod(isolate, t, "setPrivateKey", SetPrivateKey);
Local<FunctionTemplate> verify_error_getter_templ =
FunctionTemplate::New(isolate,
DiffieHellman::VerifyErrorGetter,
Local<Value>(),
Signature::New(env->isolate(), t),
/* length */ 0,
ConstructorBehavior::kThrow,
SideEffectType::kHasNoSideEffect);
t->InstanceTemplate()->SetAccessorProperty(
env->verify_error_string(),
verify_error_getter_templ,
Local<FunctionTemplate>(),
attributes);
SetConstructorFunction(context, target, name, t);
};
make(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellman"), New);
make(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellmanGroup"),
DiffieHellmanGroup);
SetMethodNoSideEffect(
context, target, "statelessDH", DiffieHellman::Stateless);
DHKeyPairGenJob::Initialize(env, target);
DHKeyExportJob::Initialize(env, target);
DHBitsJob::Initialize(env, target);
}
void DiffieHellman::RegisterExternalReferences(
ExternalReferenceRegistry* registry) {
registry->Register(New);
registry->Register(DiffieHellmanGroup);
registry->Register(GenerateKeys);
registry->Register(ComputeSecret);
registry->Register(GetPrime);
registry->Register(GetGenerator);
registry->Register(GetPublicKey);
registry->Register(GetPrivateKey);
registry->Register(SetPublicKey);
registry->Register(SetPrivateKey);
registry->Register(DiffieHellman::VerifyErrorGetter);
registry->Register(DiffieHellman::Stateless);
DHKeyPairGenJob::RegisterExternalReferences(registry);
DHKeyExportJob::RegisterExternalReferences(registry);
DHBitsJob::RegisterExternalReferences(registry);
}
bool DiffieHellman::Init(int primeLength, int g) {
dh_.reset(DH_new());
if (!DH_generate_parameters_ex(dh_.get(), primeLength, g, nullptr))
return false;
return VerifyContext();
}
void DiffieHellman::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackFieldWithSize("dh", dh_ ? kSizeOf_DH : 0);
}
bool DiffieHellman::Init(BignumPointer&& bn_p, int g) {
dh_.reset(DH_new());
CHECK_GE(g, 2);
BignumPointer bn_g(BN_new());
return bn_g && BN_set_word(bn_g.get(), g) &&
DH_set0_pqg(dh_.get(), bn_p.release(), nullptr, bn_g.release()) &&
VerifyContext();
}
bool DiffieHellman::Init(const char* p, int p_len, int g) {
dh_.reset(DH_new());
if (p_len <= 0) {
ERR_put_error(ERR_LIB_BN, BN_F_BN_GENERATE_PRIME_EX,
BN_R_BITS_TOO_SMALL, __FILE__, __LINE__);
return false;
}
if (g <= 1) {
ERR_put_error(ERR_LIB_DH, DH_F_DH_BUILTIN_GENPARAMS,
DH_R_BAD_GENERATOR, __FILE__, __LINE__);
return false;
}
BignumPointer bn_p(
BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, nullptr));
BignumPointer bn_g(BN_new());
if (bn_p == nullptr || bn_g == nullptr || !BN_set_word(bn_g.get(), g) ||
!DH_set0_pqg(dh_.get(), bn_p.release(), nullptr, bn_g.release())) {
return false;
}
return VerifyContext();
}
bool DiffieHellman::Init(const char* p, int p_len, const char* g, int g_len) {
dh_.reset(DH_new());
if (p_len <= 0) {
ERR_put_error(ERR_LIB_BN, BN_F_BN_GENERATE_PRIME_EX,
BN_R_BITS_TOO_SMALL, __FILE__, __LINE__);
return false;
}
if (g_len <= 0) {
ERR_put_error(ERR_LIB_DH, DH_F_DH_BUILTIN_GENPARAMS,
DH_R_BAD_GENERATOR, __FILE__, __LINE__);
return false;
}
BignumPointer bn_g(
BN_bin2bn(reinterpret_cast<const unsigned char*>(g), g_len, nullptr));
if (BN_is_zero(bn_g.get()) || BN_is_one(bn_g.get())) {
ERR_put_error(ERR_LIB_DH, DH_F_DH_BUILTIN_GENPARAMS,
DH_R_BAD_GENERATOR, __FILE__, __LINE__);
return false;
}
BignumPointer bn_p(
BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, nullptr));
if (!DH_set0_pqg(dh_.get(), bn_p.get(), nullptr, bn_g.get())) {
return false;
}
// The DH_set0_pqg call above takes ownership of the bignums on success,
// so we should release them here so we don't end with a possible
// use-after-free or double free.
bn_p.release();
bn_g.release();
return VerifyContext();
}
constexpr int kStandardizedGenerator = 2;
template <BIGNUM* (*p)(BIGNUM*)>
BignumPointer InstantiateStandardizedGroup() {
return BignumPointer(p(nullptr));
}
typedef BignumPointer (*StandardizedGroupInstantiator)();
// Returns a function that can be used to create an instance of a standardized
// Diffie-Hellman group. The generator is always kStandardizedGenerator.
inline StandardizedGroupInstantiator FindDiffieHellmanGroup(const char* name) {
#define V(n, p) \
if (StringEqualNoCase(name, n)) return InstantiateStandardizedGroup<p>
V("modp1", BN_get_rfc2409_prime_768);
V("modp2", BN_get_rfc2409_prime_1024);
V("modp5", BN_get_rfc3526_prime_1536);
V("modp14", BN_get_rfc3526_prime_2048);
V("modp15", BN_get_rfc3526_prime_3072);
V("modp16", BN_get_rfc3526_prime_4096);
V("modp17", BN_get_rfc3526_prime_6144);
V("modp18", BN_get_rfc3526_prime_8192);
#undef V
return nullptr;
}
void DiffieHellman::DiffieHellmanGroup(
const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
DiffieHellman* diffieHellman = new DiffieHellman(env, args.This());
CHECK_EQ(args.Length(), 1);
THROW_AND_RETURN_IF_NOT_STRING(env, args[0], "Group name");
bool initialized = false;
const node::Utf8Value group_name(env->isolate(), args[0]);
auto group = FindDiffieHellmanGroup(*group_name);
if (group == nullptr)
return THROW_ERR_CRYPTO_UNKNOWN_DH_GROUP(env);
initialized = diffieHellman->Init(group(), kStandardizedGenerator);
if (!initialized)
THROW_ERR_CRYPTO_INITIALIZATION_FAILED(env);
}
void DiffieHellman::New(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
DiffieHellman* diffieHellman =
new DiffieHellman(env, args.This());
bool initialized = false;
if (args.Length() == 2) {
if (args[0]->IsInt32()) {
if (args[1]->IsInt32()) {
initialized = diffieHellman->Init(args[0].As<Int32>()->Value(),
args[1].As<Int32>()->Value());
}
} else {
ArrayBufferOrViewContents<char> arg0(args[0]);
if (UNLIKELY(!arg0.CheckSizeInt32()))
return THROW_ERR_OUT_OF_RANGE(env, "prime is too big");
if (args[1]->IsInt32()) {
initialized = diffieHellman->Init(arg0.data(),
arg0.size(),
args[1].As<Int32>()->Value());
} else {
ArrayBufferOrViewContents<char> arg1(args[1]);
if (UNLIKELY(!arg1.CheckSizeInt32()))
return THROW_ERR_OUT_OF_RANGE(env, "generator is too big");
initialized = diffieHellman->Init(arg0.data(), arg0.size(),
arg1.data(), arg1.size());
}
}
}
if (!initialized) {
return ThrowCryptoError(env, ERR_get_error(), "Initialization failed");
}
}
void DiffieHellman::GenerateKeys(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
DiffieHellman* diffieHellman;
ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.Holder());
if (!DH_generate_key(diffieHellman->dh_.get())) {
return ThrowCryptoError(env, ERR_get_error(), "Key generation failed");
}
const BIGNUM* pub_key;
DH_get0_key(diffieHellman->dh_.get(), &pub_key, nullptr);
std::unique_ptr<BackingStore> bs;
{
const int size = BN_num_bytes(pub_key);
CHECK_GE(size, 0);
NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
bs = ArrayBuffer::NewBackingStore(env->isolate(), size);
}
CHECK_EQ(static_cast<int>(bs->ByteLength()),
BN_bn2binpad(pub_key,
static_cast<unsigned char*>(bs->Data()),
bs->ByteLength()));
Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
Local<Value> buffer;
if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&buffer)) return;
args.GetReturnValue().Set(buffer);
}
void DiffieHellman::GetField(const FunctionCallbackInfo<Value>& args,
const BIGNUM* (*get_field)(const DH*),
const char* err_if_null) {
Environment* env = Environment::GetCurrent(args);
DiffieHellman* dh;
ASSIGN_OR_RETURN_UNWRAP(&dh, args.Holder());
const BIGNUM* num = get_field(dh->dh_.get());
if (num == nullptr)
return THROW_ERR_CRYPTO_INVALID_STATE(env, err_if_null);
std::unique_ptr<BackingStore> bs;
{
const int size = BN_num_bytes(num);
CHECK_GE(size, 0);
NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
bs = ArrayBuffer::NewBackingStore(env->isolate(), size);
}
CHECK_EQ(static_cast<int>(bs->ByteLength()),
BN_bn2binpad(num,
static_cast<unsigned char*>(bs->Data()),
bs->ByteLength()));
Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
Local<Value> buffer;
if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&buffer)) return;
args.GetReturnValue().Set(buffer);
}
void DiffieHellman::GetPrime(const FunctionCallbackInfo<Value>& args) {
GetField(args, [](const DH* dh) -> const BIGNUM* {
const BIGNUM* p;
DH_get0_pqg(dh, &p, nullptr, nullptr);
return p;
}, "p is null");
}
void DiffieHellman::GetGenerator(const FunctionCallbackInfo<Value>& args) {
GetField(args, [](const DH* dh) -> const BIGNUM* {
const BIGNUM* g;
DH_get0_pqg(dh, nullptr, nullptr, &g);
return g;
}, "g is null");
}
void DiffieHellman::GetPublicKey(const FunctionCallbackInfo<Value>& args) {
GetField(args, [](const DH* dh) -> const BIGNUM* {
const BIGNUM* pub_key;
DH_get0_key(dh, &pub_key, nullptr);
return pub_key;
}, "No public key - did you forget to generate one?");
}
void DiffieHellman::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
GetField(args, [](const DH* dh) -> const BIGNUM* {
const BIGNUM* priv_key;
DH_get0_key(dh, nullptr, &priv_key);
return priv_key;
}, "No private key - did you forget to generate one?");
}
void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
DiffieHellman* diffieHellman;
ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.Holder());
ClearErrorOnReturn clear_error_on_return;
CHECK_EQ(args.Length(), 1);
ArrayBufferOrViewContents<unsigned char> key_buf(args[0]);
if (UNLIKELY(!key_buf.CheckSizeInt32()))
return THROW_ERR_OUT_OF_RANGE(env, "secret is too big");
BignumPointer key(BN_bin2bn(key_buf.data(), key_buf.size(), nullptr));
std::unique_ptr<BackingStore> bs;
{
NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
bs = ArrayBuffer::NewBackingStore(env->isolate(),
DH_size(diffieHellman->dh_.get()));
}
int size = DH_compute_key(static_cast<unsigned char*>(bs->Data()),
key.get(),
diffieHellman->dh_.get());
if (size == -1) {
int checkResult;
int checked;
checked = DH_check_pub_key(diffieHellman->dh_.get(),
key.get(),
&checkResult);
if (!checked) {
return ThrowCryptoError(env, ERR_get_error(), "Invalid Key");
} else if (checkResult) {
if (checkResult & DH_CHECK_PUBKEY_TOO_SMALL) {
return THROW_ERR_CRYPTO_INVALID_KEYLEN(env,
"Supplied key is too small");
} else if (checkResult & DH_CHECK_PUBKEY_TOO_LARGE) {
return THROW_ERR_CRYPTO_INVALID_KEYLEN(env,
"Supplied key is too large");
}
}
return THROW_ERR_CRYPTO_INVALID_KEYTYPE(env);
}
CHECK_GE(size, 0);
ZeroPadDiffieHellmanSecret(size,
static_cast<char*>(bs->Data()),
bs->ByteLength());
Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
Local<Value> buffer;
if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&buffer)) return;
args.GetReturnValue().Set(buffer);
}
void DiffieHellman::SetKey(const FunctionCallbackInfo<Value>& args,
int (*set_field)(DH*, BIGNUM*), const char* what) {
Environment* env = Environment::GetCurrent(args);
DiffieHellman* dh;
ASSIGN_OR_RETURN_UNWRAP(&dh, args.Holder());
CHECK_EQ(args.Length(), 1);
ArrayBufferOrViewContents<unsigned char> buf(args[0]);
if (UNLIKELY(!buf.CheckSizeInt32()))
return THROW_ERR_OUT_OF_RANGE(env, "buf is too big");
BIGNUM* num = BN_bin2bn(buf.data(), buf.size(), nullptr);
CHECK_NOT_NULL(num);
CHECK_EQ(1, set_field(dh->dh_.get(), num));
}
void DiffieHellman::SetPublicKey(const FunctionCallbackInfo<Value>& args) {
SetKey(args,
[](DH* dh, BIGNUM* num) { return DH_set0_key(dh, num, nullptr); },
"Public key");
}
void DiffieHellman::SetPrivateKey(const FunctionCallbackInfo<Value>& args) {
SetKey(args,
[](DH* dh, BIGNUM* num) { return DH_set0_key(dh, nullptr, num); },
"Private key");
}
void DiffieHellman::VerifyErrorGetter(const FunctionCallbackInfo<Value>& args) {
HandleScope scope(args.GetIsolate());
DiffieHellman* diffieHellman;
ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.Holder());
args.GetReturnValue().Set(diffieHellman->verifyError_);
}
bool DiffieHellman::VerifyContext() {
int codes;
if (!DH_check(dh_.get(), &codes))
return false;
verifyError_ = codes;
return true;
}
// The input arguments to DhKeyPairGenJob can vary
// 1. CryptoJobMode
// and either
// 2. Group name (as a string)
// or
// 2. Prime or Prime Length
// 3. Generator
// Followed by the public and private key encoding parameters:
// * Public format
// * Public type
// * Private format
// * Private type
// * Cipher
// * Passphrase
Maybe<bool> DhKeyGenTraits::AdditionalConfig(
CryptoJobMode mode,
const FunctionCallbackInfo<Value>& args,
unsigned int* offset,
DhKeyPairGenConfig* params) {
Environment* env = Environment::GetCurrent(args);
if (args[*offset]->IsString()) {
Utf8Value group_name(env->isolate(), args[*offset]);
auto group = FindDiffieHellmanGroup(*group_name);
if (group == nullptr) {
THROW_ERR_CRYPTO_UNKNOWN_DH_GROUP(env);
return Nothing<bool>();
}
params->params.prime = group();
params->params.generator = kStandardizedGenerator;
*offset += 1;
} else {
if (args[*offset]->IsInt32()) {
int size = args[*offset].As<Int32>()->Value();
if (size < 0) {
THROW_ERR_OUT_OF_RANGE(env, "Invalid prime size");
return Nothing<bool>();
}
params->params.prime = size;
} else {
ArrayBufferOrViewContents<unsigned char> input(args[*offset]);
if (UNLIKELY(!input.CheckSizeInt32())) {
THROW_ERR_OUT_OF_RANGE(env, "prime is too big");
return Nothing<bool>();
}
params->params.prime = BignumPointer(
BN_bin2bn(input.data(), input.size(), nullptr));
}
CHECK(args[*offset + 1]->IsInt32());
params->params.generator = args[*offset + 1].As<Int32>()->Value();
*offset += 2;
}
return Just(true);
}
EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) {
EVPKeyPointer key_params;
if (BignumPointer* prime_fixed_value =
std::get_if<BignumPointer>(¶ms->params.prime)) {
DHPointer dh(DH_new());
if (!dh)
return EVPKeyCtxPointer();
BIGNUM* prime = prime_fixed_value->get();
BignumPointer bn_g(BN_new());
if (!BN_set_word(bn_g.get(), params->params.generator) ||
!DH_set0_pqg(dh.get(), prime, nullptr, bn_g.get())) {
return EVPKeyCtxPointer();
}
prime_fixed_value->release();
bn_g.release();
key_params = EVPKeyPointer(EVP_PKEY_new());
CHECK(key_params);
CHECK_EQ(EVP_PKEY_assign_DH(key_params.get(), dh.release()), 1);
} else if (int* prime_size = std::get_if<int>(¶ms->params.prime)) {
EVPKeyCtxPointer param_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DH, nullptr));
EVP_PKEY* raw_params = nullptr;
if (!param_ctx ||
EVP_PKEY_paramgen_init(param_ctx.get()) <= 0 ||
EVP_PKEY_CTX_set_dh_paramgen_prime_len(
param_ctx.get(),
*prime_size) <= 0 ||
EVP_PKEY_CTX_set_dh_paramgen_generator(
param_ctx.get(),
params->params.generator) <= 0 ||
EVP_PKEY_paramgen(param_ctx.get(), &raw_params) <= 0) {
return EVPKeyCtxPointer();
}
key_params = EVPKeyPointer(raw_params);
} else {
UNREACHABLE();
}
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(key_params.get(), nullptr));
if (!ctx || EVP_PKEY_keygen_init(ctx.get()) <= 0)
return EVPKeyCtxPointer();
return ctx;
}
Maybe<bool> DHKeyExportTraits::AdditionalConfig(
const FunctionCallbackInfo<Value>& args,
unsigned int offset,
DHKeyExportConfig* params) {
return Just(true);
}
WebCryptoKeyExportStatus DHKeyExportTraits::DoExport(
std::shared_ptr<KeyObjectData> key_data,
WebCryptoKeyFormat format,
const DHKeyExportConfig& params,
ByteSource* out) {
CHECK_NE(key_data->GetKeyType(), kKeyTypeSecret);
switch (format) {
case kWebCryptoKeyFormatPKCS8:
if (key_data->GetKeyType() != kKeyTypePrivate)
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
return PKEY_PKCS8_Export(key_data.get(), out);
case kWebCryptoKeyFormatSPKI:
if (key_data->GetKeyType() != kKeyTypePublic)
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
return PKEY_SPKI_Export(key_data.get(), out);
default:
UNREACHABLE();
}
}
namespace {
ByteSource StatelessDiffieHellmanThreadsafe(
const ManagedEVPPKey& our_key,
const ManagedEVPPKey& their_key) {
size_t out_size;
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(our_key.get(), nullptr));
if (!ctx ||
EVP_PKEY_derive_init(ctx.get()) <= 0 ||
EVP_PKEY_derive_set_peer(ctx.get(), their_key.get()) <= 0 ||
EVP_PKEY_derive(ctx.get(), nullptr, &out_size) <= 0)
return ByteSource();
ByteSource::Builder out(out_size);
if (EVP_PKEY_derive(ctx.get(), out.data<unsigned char>(), &out_size) <= 0) {
return ByteSource();
}
ZeroPadDiffieHellmanSecret(out_size, out.data<char>(), out.size());
return std::move(out).release();
}
} // namespace
void DiffieHellman::Stateless(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(args[0]->IsObject() && args[1]->IsObject());
KeyObjectHandle* our_key_object;
ASSIGN_OR_RETURN_UNWRAP(&our_key_object, args[0].As<Object>());
CHECK_EQ(our_key_object->Data()->GetKeyType(), kKeyTypePrivate);
KeyObjectHandle* their_key_object;
ASSIGN_OR_RETURN_UNWRAP(&their_key_object, args[1].As<Object>());
CHECK_NE(their_key_object->Data()->GetKeyType(), kKeyTypeSecret);
ManagedEVPPKey our_key = our_key_object->Data()->GetAsymmetricKey();
ManagedEVPPKey their_key = their_key_object->Data()->GetAsymmetricKey();
Local<Value> out;
if (!StatelessDiffieHellmanThreadsafe(our_key, their_key)
.ToBuffer(env)
.ToLocal(&out)) return;
if (Buffer::Length(out) == 0)
return ThrowCryptoError(env, ERR_get_error(), "diffieHellman failed");
args.GetReturnValue().Set(out);
}
Maybe<bool> DHBitsTraits::AdditionalConfig(
CryptoJobMode mode,
const FunctionCallbackInfo<Value>& args,
unsigned int offset,
DHBitsConfig* params) {
Environment* env = Environment::GetCurrent(args);
CHECK(args[offset]->IsObject()); // public key
CHECK(args[offset + 1]->IsObject()); // private key
KeyObjectHandle* private_key;
KeyObjectHandle* public_key;
ASSIGN_OR_RETURN_UNWRAP(&public_key, args[offset], Nothing<bool>());
ASSIGN_OR_RETURN_UNWRAP(&private_key, args[offset + 1], Nothing<bool>());
if (private_key->Data()->GetKeyType() != kKeyTypePrivate ||
public_key->Data()->GetKeyType() != kKeyTypePublic) {
THROW_ERR_CRYPTO_INVALID_KEYTYPE(env);
return Nothing<bool>();
}
params->public_key = public_key->Data();
params->private_key = private_key->Data();
return Just(true);
}
Maybe<bool> DHBitsTraits::EncodeOutput(
Environment* env,
const DHBitsConfig& params,
ByteSource* out,
v8::Local<v8::Value>* result) {
*result = out->ToArrayBuffer(env);
return Just(!result->IsEmpty());
}
bool DHBitsTraits::DeriveBits(
Environment* env,
const DHBitsConfig& params,
ByteSource* out) {
*out = StatelessDiffieHellmanThreadsafe(
params.private_key->GetAsymmetricKey(),
params.public_key->GetAsymmetricKey());
return true;
}
Maybe<bool> GetDhKeyDetail(
Environment* env,
std::shared_ptr<KeyObjectData> key,
Local<Object> target) {
ManagedEVPPKey pkey = key->GetAsymmetricKey();
CHECK_EQ(EVP_PKEY_id(pkey.get()), EVP_PKEY_DH);
return Just(true);
}
} // namespace crypto
} // namespace node