Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobias Nießen <tniessen@tnie.de>2020-01-03 14:01:34 +0300
committerShelley Vohr <shelley.vohr@gmail.com>2020-02-17 21:35:04 +0300
commitbf46c304dd46dbab49db3da16ef93eb4d11ad4f9 (patch)
tree26b12057e0ddba2005fc949cb002da11c2fed9ca /src/node_crypto.cc
parent0d3e095941ed812f0300a6c4a3424e329d03a74a (diff)
crypto: add crypto.diffieHellman
Currently, Node.js has separate (stateful) APIs for DH/ECDH, and no support for ECDH-ES. This commit adds a single stateless function to compute the DH/ECDH/ECDH-ES secret based on two KeyObjects. PR-URL: https://github.com/nodejs/node/pull/31178 Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Diffstat (limited to 'src/node_crypto.cc')
-rw-r--r--src/node_crypto.cc69
1 files changed, 59 insertions, 10 deletions
diff --git a/src/node_crypto.cc b/src/node_crypto.cc
index a4d0d8bec29..42dab91e662 100644
--- a/src/node_crypto.cc
+++ b/src/node_crypto.cc
@@ -5830,6 +5830,20 @@ void DiffieHellman::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
}, "No private key - did you forget to generate one?");
}
+static void ZeroPadDiffieHellmanSecret(size_t remainder_size,
+ AllocatedBuffer* ret) {
+ // 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 = ret->size();
+ if (remainder_size != prime_size) {
+ CHECK_LT(remainder_size, prime_size);
+ const size_t padding = prime_size - remainder_size;
+ memmove(ret->data() + padding, ret->data(), remainder_size);
+ memset(ret->data(), 0, padding);
+ }
+}
void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
@@ -5880,16 +5894,7 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
}
CHECK_GE(size, 0);
-
- // 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.
- if (static_cast<size_t>(size) != ret.size()) {
- CHECK_GT(ret.size(), static_cast<size_t>(size));
- memmove(ret.data() + ret.size() - size, ret.data(), size);
- memset(ret.data(), 0, ret.size() - size);
- }
+ ZeroPadDiffieHellmanSecret(static_cast<size_t>(size), &ret);
args.GetReturnValue().Set(ret.ToBuffer().ToLocalChecked());
}
@@ -7200,6 +7205,49 @@ void ConvertKey(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(buf);
}
+AllocatedBuffer StatelessDiffieHellman(Environment* env, ManagedEVPPKey our_key,
+ 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 AllocatedBuffer();
+
+ AllocatedBuffer result = env->AllocateManaged(out_size);
+ CHECK_NOT_NULL(result.data());
+
+ unsigned char* data = reinterpret_cast<unsigned char*>(result.data());
+ if (EVP_PKEY_derive(ctx.get(), data, &out_size) <= 0)
+ return AllocatedBuffer();
+
+ ZeroPadDiffieHellmanSecret(out_size, &result);
+ return result;
+}
+
+void StatelessDiffieHellman(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+
+ CHECK(args[0]->IsObject() && args[1]->IsObject());
+ KeyObject* our_key_object;
+ ASSIGN_OR_RETURN_UNWRAP(&our_key_object, args[0].As<Object>());
+ CHECK_EQ(our_key_object->GetKeyType(), kKeyTypePrivate);
+ KeyObject* their_key_object;
+ ASSIGN_OR_RETURN_UNWRAP(&their_key_object, args[1].As<Object>());
+ CHECK_NE(their_key_object->GetKeyType(), kKeyTypeSecret);
+
+ ManagedEVPPKey our_key = our_key_object->GetAsymmetricKey();
+ ManagedEVPPKey their_key = their_key_object->GetAsymmetricKey();
+
+ AllocatedBuffer out = StatelessDiffieHellman(env, our_key, their_key);
+ if (out.size() == 0)
+ return ThrowCryptoError(env, ERR_get_error(), "diffieHellman failed");
+
+ args.GetReturnValue().Set(out.ToBuffer().ToLocalChecked());
+}
+
void TimingSafeEqual(const FunctionCallbackInfo<Value>& args) {
ArrayBufferViewContents<char> buf1(args[0]);
@@ -7369,6 +7417,7 @@ void Initialize(Local<Object> target,
NODE_DEFINE_CONSTANT(target, kKeyTypePrivate);
NODE_DEFINE_CONSTANT(target, kSigEncDER);
NODE_DEFINE_CONSTANT(target, kSigEncP1363);
+ env->SetMethodNoSideEffect(target, "statelessDH", StatelessDiffieHellman);
env->SetMethod(target, "randomBytes", RandomBytes);
env->SetMethod(target, "signOneShot", SignOneShot);
env->SetMethod(target, "verifyOneShot", VerifyOneShot);