@@ -5830,6 +5830,20 @@ void DiffieHellman::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
58305830 }, " No private key - did you forget to generate one?" );
58315831}
58325832
5833+ static void ZeroPadDiffieHellmanSecret (size_t remainder_size,
5834+ AllocatedBuffer* ret) {
5835+ // DH_size returns number of bytes in a prime number.
5836+ // DH_compute_key returns number of bytes in a remainder of exponent, which
5837+ // may have less bytes than a prime number. Therefore add 0-padding to the
5838+ // allocated buffer.
5839+ const size_t prime_size = ret->size ();
5840+ if (remainder_size != prime_size) {
5841+ CHECK_LT (remainder_size, prime_size);
5842+ const size_t padding = prime_size - remainder_size;
5843+ memmove (ret->data () + padding, ret->data (), remainder_size);
5844+ memset (ret->data (), 0 , padding);
5845+ }
5846+ }
58335847
58345848void DiffieHellman::ComputeSecret (const FunctionCallbackInfo<Value>& args) {
58355849 Environment* env = Environment::GetCurrent (args);
@@ -5880,16 +5894,7 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
58805894 }
58815895
58825896 CHECK_GE (size, 0 );
5883-
5884- // DH_size returns number of bytes in a prime number
5885- // DH_compute_key returns number of bytes in a remainder of exponent, which
5886- // may have less bytes than a prime number. Therefore add 0-padding to the
5887- // allocated buffer.
5888- if (static_cast <size_t >(size) != ret.size ()) {
5889- CHECK_GT (ret.size (), static_cast <size_t >(size));
5890- memmove (ret.data () + ret.size () - size, ret.data (), size);
5891- memset (ret.data (), 0 , ret.size () - size);
5892- }
5897+ ZeroPadDiffieHellmanSecret (static_cast <size_t >(size), &ret);
58935898
58945899 args.GetReturnValue ().Set (ret.ToBuffer ().ToLocalChecked ());
58955900}
@@ -7200,6 +7205,49 @@ void ConvertKey(const FunctionCallbackInfo<Value>& args) {
72007205 args.GetReturnValue ().Set (buf);
72017206}
72027207
7208+ AllocatedBuffer StatelessDiffieHellman (Environment* env, ManagedEVPPKey our_key,
7209+ ManagedEVPPKey their_key) {
7210+ size_t out_size;
7211+
7212+ EVPKeyCtxPointer ctx (EVP_PKEY_CTX_new (our_key.get (), nullptr ));
7213+ if (!ctx ||
7214+ EVP_PKEY_derive_init (ctx.get ()) <= 0 ||
7215+ EVP_PKEY_derive_set_peer (ctx.get (), their_key.get ()) <= 0 ||
7216+ EVP_PKEY_derive (ctx.get (), nullptr , &out_size) <= 0 )
7217+ return AllocatedBuffer ();
7218+
7219+ AllocatedBuffer result = env->AllocateManaged (out_size);
7220+ CHECK_NOT_NULL (result.data ());
7221+
7222+ unsigned char * data = reinterpret_cast <unsigned char *>(result.data ());
7223+ if (EVP_PKEY_derive (ctx.get (), data, &out_size) <= 0 )
7224+ return AllocatedBuffer ();
7225+
7226+ ZeroPadDiffieHellmanSecret (out_size, &result);
7227+ return result;
7228+ }
7229+
7230+ void StatelessDiffieHellman (const FunctionCallbackInfo<Value>& args) {
7231+ Environment* env = Environment::GetCurrent (args);
7232+
7233+ CHECK (args[0 ]->IsObject () && args[1 ]->IsObject ());
7234+ KeyObject* our_key_object;
7235+ ASSIGN_OR_RETURN_UNWRAP (&our_key_object, args[0 ].As <Object>());
7236+ CHECK_EQ (our_key_object->GetKeyType (), kKeyTypePrivate );
7237+ KeyObject* their_key_object;
7238+ ASSIGN_OR_RETURN_UNWRAP (&their_key_object, args[1 ].As <Object>());
7239+ CHECK_NE (their_key_object->GetKeyType (), kKeyTypeSecret );
7240+
7241+ ManagedEVPPKey our_key = our_key_object->GetAsymmetricKey ();
7242+ ManagedEVPPKey their_key = their_key_object->GetAsymmetricKey ();
7243+
7244+ AllocatedBuffer out = StatelessDiffieHellman (env, our_key, their_key);
7245+ if (out.size () == 0 )
7246+ return ThrowCryptoError (env, ERR_get_error (), " diffieHellman failed" );
7247+
7248+ args.GetReturnValue ().Set (out.ToBuffer ().ToLocalChecked ());
7249+ }
7250+
72037251
72047252void TimingSafeEqual (const FunctionCallbackInfo<Value>& args) {
72057253 ArrayBufferViewContents<char > buf1 (args[0 ]);
@@ -7369,6 +7417,7 @@ void Initialize(Local<Object> target,
73697417 NODE_DEFINE_CONSTANT (target, kKeyTypePrivate );
73707418 NODE_DEFINE_CONSTANT (target, kSigEncDER );
73717419 NODE_DEFINE_CONSTANT (target, kSigEncP1363 );
7420+ env->SetMethodNoSideEffect (target, " statelessDH" , StatelessDiffieHellman);
73727421 env->SetMethod (target, " randomBytes" , RandomBytes);
73737422 env->SetMethod (target, " signOneShot" , SignOneShot);
73747423 env->SetMethod (target, " verifyOneShot" , VerifyOneShot);
0 commit comments