@@ -5288,6 +5288,20 @@ void DiffieHellman::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
5288
5288
}, " No private key - did you forget to generate one?" );
5289
5289
}
5290
5290
5291
+ static void ZeroPadDiffieHellmanSecret (size_t remainder_size,
5292
+ AllocatedBuffer* ret) {
5293
+ // DH_size returns number of bytes in a prime number.
5294
+ // DH_compute_key returns number of bytes in a remainder of exponent, which
5295
+ // may have less bytes than a prime number. Therefore add 0-padding to the
5296
+ // allocated buffer.
5297
+ const size_t prime_size = ret->size ();
5298
+ if (remainder_size != prime_size) {
5299
+ CHECK_LT (remainder_size, prime_size);
5300
+ const size_t padding = prime_size - remainder_size;
5301
+ memmove (ret->data () + padding, ret->data (), remainder_size);
5302
+ memset (ret->data (), 0 , padding);
5303
+ }
5304
+ }
5291
5305
5292
5306
void DiffieHellman::ComputeSecret (const FunctionCallbackInfo<Value>& args) {
5293
5307
Environment* env = Environment::GetCurrent (args);
@@ -5334,16 +5348,7 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
5334
5348
}
5335
5349
5336
5350
CHECK_GE (size, 0 );
5337
-
5338
- // DH_size returns number of bytes in a prime number
5339
- // DH_compute_key returns number of bytes in a remainder of exponent, which
5340
- // may have less bytes than a prime number. Therefore add 0-padding to the
5341
- // allocated buffer.
5342
- if (static_cast <size_t >(size) != ret.size ()) {
5343
- CHECK_GT (ret.size (), static_cast <size_t >(size));
5344
- memmove (ret.data () + ret.size () - size, ret.data (), size);
5345
- memset (ret.data (), 0 , ret.size () - size);
5346
- }
5351
+ ZeroPadDiffieHellmanSecret (static_cast <size_t >(size), &ret);
5347
5352
5348
5353
args.GetReturnValue ().Set (ret.ToBuffer ().ToLocalChecked ());
5349
5354
}
@@ -6679,6 +6684,49 @@ void ConvertKey(const FunctionCallbackInfo<Value>& args) {
6679
6684
args.GetReturnValue ().Set (buf);
6680
6685
}
6681
6686
6687
+ AllocatedBuffer StatelessDiffieHellman (Environment* env, ManagedEVPPKey our_key,
6688
+ ManagedEVPPKey their_key) {
6689
+ size_t out_size;
6690
+
6691
+ EVPKeyCtxPointer ctx (EVP_PKEY_CTX_new (our_key.get (), nullptr ));
6692
+ if (!ctx ||
6693
+ EVP_PKEY_derive_init (ctx.get ()) <= 0 ||
6694
+ EVP_PKEY_derive_set_peer (ctx.get (), their_key.get ()) <= 0 ||
6695
+ EVP_PKEY_derive (ctx.get (), nullptr , &out_size) <= 0 )
6696
+ return AllocatedBuffer ();
6697
+
6698
+ AllocatedBuffer result = env->AllocateManaged (out_size);
6699
+ CHECK_NOT_NULL (result.data ());
6700
+
6701
+ unsigned char * data = reinterpret_cast <unsigned char *>(result.data ());
6702
+ if (EVP_PKEY_derive (ctx.get (), data, &out_size) <= 0 )
6703
+ return AllocatedBuffer ();
6704
+
6705
+ ZeroPadDiffieHellmanSecret (out_size, &result);
6706
+ return result;
6707
+ }
6708
+
6709
+ void StatelessDiffieHellman (const FunctionCallbackInfo<Value>& args) {
6710
+ Environment* env = Environment::GetCurrent (args);
6711
+
6712
+ CHECK (args[0 ]->IsObject () && args[1 ]->IsObject ());
6713
+ KeyObject* our_key_object;
6714
+ ASSIGN_OR_RETURN_UNWRAP (&our_key_object, args[0 ].As <Object>());
6715
+ CHECK_EQ (our_key_object->GetKeyType (), kKeyTypePrivate );
6716
+ KeyObject* their_key_object;
6717
+ ASSIGN_OR_RETURN_UNWRAP (&their_key_object, args[1 ].As <Object>());
6718
+ CHECK_NE (their_key_object->GetKeyType (), kKeyTypeSecret );
6719
+
6720
+ ManagedEVPPKey our_key = our_key_object->GetAsymmetricKey ();
6721
+ ManagedEVPPKey their_key = their_key_object->GetAsymmetricKey ();
6722
+
6723
+ AllocatedBuffer out = StatelessDiffieHellman (env, our_key, their_key);
6724
+ if (out.size () == 0 )
6725
+ return ThrowCryptoError (env, ERR_get_error (), " diffieHellman failed" );
6726
+
6727
+ args.GetReturnValue ().Set (out.ToBuffer ().ToLocalChecked ());
6728
+ }
6729
+
6682
6730
6683
6731
void TimingSafeEqual (const FunctionCallbackInfo<Value>& args) {
6684
6732
ArrayBufferViewContents<char > buf1 (args[0 ]);
@@ -6848,6 +6896,7 @@ void Initialize(Local<Object> target,
6848
6896
NODE_DEFINE_CONSTANT (target, kKeyTypePrivate );
6849
6897
NODE_DEFINE_CONSTANT (target, kSigEncDER );
6850
6898
NODE_DEFINE_CONSTANT (target, kSigEncP1363 );
6899
+ env->SetMethodNoSideEffect (target, " statelessDH" , StatelessDiffieHellman);
6851
6900
env->SetMethod (target, " randomBytes" , RandomBytes);
6852
6901
env->SetMethod (target, " signOneShot" , SignOneShot);
6853
6902
env->SetMethod (target, " verifyOneShot" , VerifyOneShot);
0 commit comments