summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTobias Nießen <tniessen@tnie.de>2020-01-03 12:01:34 +0100
committerTobias Nießen <tniessen@tnie.de>2020-01-21 10:49:20 -0400
commitb4f8537cdc6f894c5e90bb8bf29a90a2db1438ca (patch)
tree41c24bf11d787366304cb64239344bdc1c55230b /lib
parentc6f8ea8d6578fd1f167bc943272eca5806224d2f (diff)
downloadnode-new-b4f8537cdc6f894c5e90bb8bf29a90a2db1438ca.tar.gz
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 'lib')
-rw-r--r--lib/crypto.js4
-rw-r--r--lib/internal/crypto/diffiehellman.js44
-rw-r--r--lib/internal/errors.js1
3 files changed, 45 insertions, 4 deletions
diff --git a/lib/crypto.js b/lib/crypto.js
index e2d1875d8d..cec0b2c094 100644
--- a/lib/crypto.js
+++ b/lib/crypto.js
@@ -70,7 +70,8 @@ const {
const {
DiffieHellman,
DiffieHellmanGroup,
- ECDH
+ ECDH,
+ diffieHellman
} = require('internal/crypto/diffiehellman');
const {
Cipher,
@@ -163,6 +164,7 @@ module.exports = {
createSecretKey,
createSign,
createVerify,
+ diffieHellman,
getCiphers,
getCurves,
getDiffieHellman: createDiffieHellmanGroup,
diff --git a/lib/internal/crypto/diffiehellman.js b/lib/internal/crypto/diffiehellman.js
index da8f87bf16..ae6b68b73b 100644
--- a/lib/internal/crypto/diffiehellman.js
+++ b/lib/internal/crypto/diffiehellman.js
@@ -2,16 +2,21 @@
const {
ObjectDefineProperty,
+ Set
} = primordials;
const { Buffer } = require('buffer');
const {
ERR_CRYPTO_ECDH_INVALID_FORMAT,
ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY,
- ERR_INVALID_ARG_TYPE
+ ERR_CRYPTO_INCOMPATIBLE_KEY,
+ ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE,
+ ERR_INVALID_ARG_TYPE,
+ ERR_INVALID_OPT_VALUE
} = require('internal/errors').codes;
const { validateString } = require('internal/validators');
const { isArrayBufferView } = require('internal/util/types');
+const { KeyObject } = require('internal/crypto/keys');
const {
getDefaultEncoding,
kHandle,
@@ -21,7 +26,8 @@ const {
DiffieHellman: _DiffieHellman,
DiffieHellmanGroup: _DiffieHellmanGroup,
ECDH: _ECDH,
- ECDHConvertKey: _ECDHConvertKey
+ ECDHConvertKey: _ECDHConvertKey,
+ statelessDH
} = internalBinding('crypto');
const {
POINT_CONVERSION_COMPRESSED,
@@ -232,8 +238,40 @@ function getFormat(format) {
return POINT_CONVERSION_UNCOMPRESSED;
}
+const dhEnabledKeyTypes = new Set(['dh', 'ec', 'x448', 'x25519']);
+
+function diffieHellman(options) {
+ if (typeof options !== 'object')
+ throw new ERR_INVALID_ARG_TYPE('options', 'object', options);
+
+ const { privateKey, publicKey } = options;
+ if (!(privateKey instanceof KeyObject))
+ throw new ERR_INVALID_OPT_VALUE('privateKey', privateKey);
+
+ if (!(publicKey instanceof KeyObject))
+ throw new ERR_INVALID_OPT_VALUE('publicKey', publicKey);
+
+ if (privateKey.type !== 'private')
+ throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(privateKey.type, 'private');
+
+ if (publicKey.type !== 'public' && publicKey.type !== 'private') {
+ throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(publicKey.type,
+ 'private or public');
+ }
+
+ const privateType = privateKey.asymmetricKeyType;
+ const publicType = publicKey.asymmetricKeyType;
+ if (privateType !== publicType || !dhEnabledKeyTypes.has(privateType)) {
+ throw new ERR_CRYPTO_INCOMPATIBLE_KEY('key types for Diffie-Hellman',
+ `${privateType} and ${publicType}`);
+ }
+
+ return statelessDH(privateKey[kHandle], publicKey[kHandle]);
+}
+
module.exports = {
DiffieHellman,
DiffieHellmanGroup,
- ECDH
+ ECDH,
+ diffieHellman
};
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index 936a5253c7..edd286a20a 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -767,6 +767,7 @@ E('ERR_CRYPTO_FIPS_UNAVAILABLE', 'Cannot set FIPS mode in a non-FIPS build.',
Error);
E('ERR_CRYPTO_HASH_FINALIZED', 'Digest already called', Error);
E('ERR_CRYPTO_HASH_UPDATE_FAILED', 'Hash update failed', Error);
+E('ERR_CRYPTO_INCOMPATIBLE_KEY', 'Incompatible %s: %s', Error);
E('ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS', 'The selected key encoding %s %s.',
Error);
E('ERR_CRYPTO_INVALID_DIGEST', 'Invalid digest: %s', TypeError);