@@ -5827,6 +5827,20 @@ void DiffieHellman::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
58275827 }, " No private key - did you forget to generate one?" );
58285828}
58295829
5830+ static void ZeroPadDiffieHellmanSecret (size_t remainder_size,
5831+ AllocatedBuffer* ret) {
5832+ // DH_size returns number of bytes in a prime number.
5833+ // DH_compute_key returns number of bytes in a remainder of exponent, which
5834+ // may have less bytes than a prime number. Therefore add 0-padding to the
5835+ // allocated buffer.
5836+ const size_t prime_size = ret->size ();
5837+ if (remainder_size != prime_size) {
5838+ CHECK_LT (remainder_size, prime_size);
5839+ const size_t padding = prime_size - remainder_size;
5840+ memmove (ret->data () + padding, ret->data (), remainder_size);
5841+ memset (ret->data (), 0 , padding);
5842+ }
5843+ }
58305844
58315845void DiffieHellman::ComputeSecret (const FunctionCallbackInfo<Value>& args) {
58325846 Environment* env = Environment::GetCurrent (args);
@@ -5877,16 +5891,7 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
58775891 }
58785892
58795893 CHECK_GE (size, 0 );
5880-
5881- // DH_size returns number of bytes in a prime number
5882- // DH_compute_key returns number of bytes in a remainder of exponent, which
5883- // may have less bytes than a prime number. Therefore add 0-padding to the
5884- // allocated buffer.
5885- if (static_cast <size_t >(size) != ret.size ()) {
5886- CHECK_GT (ret.size (), static_cast <size_t >(size));
5887- memmove (ret.data () + ret.size () - size, ret.data (), size);
5888- memset (ret.data (), 0 , ret.size () - size);
5889- }
5894+ ZeroPadDiffieHellmanSecret (static_cast <size_t >(size), &ret);
58905895
58915896 args.GetReturnValue ().Set (ret.ToBuffer ().ToLocalChecked ());
58925897}
@@ -7197,6 +7202,49 @@ void ConvertKey(const FunctionCallbackInfo<Value>& args) {
71977202 args.GetReturnValue ().Set (buf);
71987203}
71997204
7205+ AllocatedBuffer StatelessDiffieHellman (Environment* env, ManagedEVPPKey our_key,
7206+ ManagedEVPPKey their_key) {
7207+ size_t out_size;
7208+
7209+ EVPKeyCtxPointer ctx (EVP_PKEY_CTX_new (our_key.get (), nullptr ));
7210+ if (!ctx ||
7211+ EVP_PKEY_derive_init (ctx.get ()) <= 0 ||
7212+ EVP_PKEY_derive_set_peer (ctx.get (), their_key.get ()) <= 0 ||
7213+ EVP_PKEY_derive (ctx.get (), nullptr , &out_size) <= 0 )
7214+ return AllocatedBuffer ();
7215+
7216+ AllocatedBuffer result = env->AllocateManaged (out_size);
7217+ CHECK_NOT_NULL (result.data ());
7218+
7219+ unsigned char * data = reinterpret_cast <unsigned char *>(result.data ());
7220+ if (EVP_PKEY_derive (ctx.get (), data, &out_size) <= 0 )
7221+ return AllocatedBuffer ();
7222+
7223+ ZeroPadDiffieHellmanSecret (out_size, &result);
7224+ return result;
7225+ }
7226+
7227+ void StatelessDiffieHellman (const FunctionCallbackInfo<Value>& args) {
7228+ Environment* env = Environment::GetCurrent (args);
7229+
7230+ CHECK (args[0 ]->IsObject () && args[1 ]->IsObject ());
7231+ KeyObject* our_key_object;
7232+ ASSIGN_OR_RETURN_UNWRAP (&our_key_object, args[0 ].As <Object>());
7233+ CHECK_EQ (our_key_object->GetKeyType (), kKeyTypePrivate );
7234+ KeyObject* their_key_object;
7235+ ASSIGN_OR_RETURN_UNWRAP (&their_key_object, args[1 ].As <Object>());
7236+ CHECK_NE (their_key_object->GetKeyType (), kKeyTypeSecret );
7237+
7238+ ManagedEVPPKey our_key = our_key_object->GetAsymmetricKey ();
7239+ ManagedEVPPKey their_key = their_key_object->GetAsymmetricKey ();
7240+
7241+ AllocatedBuffer out = StatelessDiffieHellman (env, our_key, their_key);
7242+ if (out.size () == 0 )
7243+ return ThrowCryptoError (env, ERR_get_error (), " diffieHellman failed" );
7244+
7245+ args.GetReturnValue ().Set (out.ToBuffer ().ToLocalChecked ());
7246+ }
7247+
72007248
72017249void TimingSafeEqual (const FunctionCallbackInfo<Value>& args) {
72027250 ArrayBufferViewContents<char > buf1 (args[0 ]);
@@ -7366,6 +7414,7 @@ void Initialize(Local<Object> target,
73667414 NODE_DEFINE_CONSTANT (target, kKeyTypePrivate );
73677415 NODE_DEFINE_CONSTANT (target, kSigEncDER );
73687416 NODE_DEFINE_CONSTANT (target, kSigEncP1363 );
7417+ env->SetMethodNoSideEffect (target, " statelessDH" , StatelessDiffieHellman);
73697418 env->SetMethod (target, " randomBytes" , RandomBytes);
73707419 env->SetMethod (target, " signOneShot" , SignOneShot);
73717420 env->SetMethod (target, " verifyOneShot" , VerifyOneShot);
0 commit comments