From dbee04cd0e8952e8558d386cbf18ee8204f25ce2 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Wed, 22 Mar 2017 07:34:55 +0100 Subject: [PATCH 1/3] crypto: support Uint8Array prime in createDH --- doc/api/crypto.md | 7 ++- lib/crypto.js | 10 ++-- test/parallel/test-crypto-dh.js | 96 ++++++++++++++++++++------------- 3 files changed, 71 insertions(+), 42 deletions(-) diff --git a/doc/api/crypto.md b/doc/api/crypto.md index 9557273a9b7b5a..e0725b74224646 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -1234,12 +1234,15 @@ The `key` is the raw key used by the `algorithm` and `iv` is an -- `prime` {string | Buffer} +- `prime` {string | Buffer | Uint8Array} - `prime_encoding` {string} - `generator` {number | string | Buffer} Defaults to `2`. - `generator_encoding` {string} @@ -1254,7 +1257,7 @@ The `prime_encoding` and `generator_encoding` arguments can be `'latin1'`, `'hex'`, or `'base64'`. If `prime_encoding` is specified, `prime` is expected to be a string; otherwise -a [`Buffer`][] is expected. +a [`Buffer`][] or `Uint8Array` is expected. If `generator_encoding` is specified, `generator` is expected to be a string; otherwise either a number or [`Buffer`][] is expected. diff --git a/lib/crypto.js b/lib/crypto.js index 7ceca8ba26601e..c280789b8eb8a2 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -42,6 +42,7 @@ const timingSafeEqual = binding.timingSafeEqual; const Buffer = require('buffer').Buffer; const stream = require('stream'); const util = require('util'); +const { isUint8Array } = process.binding('util'); const LazyTransform = require('internal/streams/lazy_transform'); const DH_GENERATOR = 2; @@ -368,10 +369,11 @@ function DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding) { if (!(this instanceof DiffieHellman)) return new DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding); - if (!(sizeOrKey instanceof Buffer) && - typeof sizeOrKey !== 'number' && - typeof sizeOrKey !== 'string') - throw new TypeError('First argument should be number, string or Buffer'); + if (typeof sizeOrKey !== 'number' && + typeof sizeOrKey !== 'string' && + !isUint8Array(sizeOrKey)) + throw new TypeError('First argument should be number, string, ' + + 'Uint8Array or Buffer'); if (keyEncoding) { if (typeof keyEncoding !== 'string' || diff --git a/test/parallel/test-crypto-dh.js b/test/parallel/test-crypto-dh.js index b95863a13ff9e7..94169ec0822d98 100644 --- a/test/parallel/test-crypto-dh.js +++ b/test/parallel/test-crypto-dh.js @@ -24,7 +24,7 @@ assert.strictEqual(dh1.verifyError, 0); assert.strictEqual(dh2.verifyError, 0); const argumentsError = - /^TypeError: First argument should be number, string or Buffer$/; + /^TypeError: First argument should be number, string, Uint8Array or Buffer$/; assert.throws(() => { crypto.createDiffieHellman([0x1, 0x2]); @@ -112,45 +112,69 @@ const modp2buf = Buffer.from([ 0x1f, 0xe6, 0x49, 0x28, 0x66, 0x51, 0xec, 0xe6, 0x53, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ]); -const exmodp2 = crypto.createDiffieHellman(modp2buf, Buffer.from([2])); -modp2.generateKeys(); -exmodp2.generateKeys(); -let modp2Secret = modp2.computeSecret(exmodp2.getPublicKey()).toString('hex'); -const exmodp2Secret = exmodp2.computeSecret(modp2.getPublicKey()) - .toString('hex'); -assert.strictEqual(modp2Secret, exmodp2Secret); -assert.strictEqual(modp2.verifyError, DH_NOT_SUITABLE_GENERATOR); -assert.strictEqual(exmodp2.verifyError, DH_NOT_SUITABLE_GENERATOR); - - -// Ensure specific generator (string with encoding) works as expected. -const exmodp2_2 = crypto.createDiffieHellman(modp2buf, '02', 'hex'); -exmodp2_2.generateKeys(); -modp2Secret = modp2.computeSecret(exmodp2_2.getPublicKey()).toString('hex'); -const exmodp2_2Secret = exmodp2_2.computeSecret(modp2.getPublicKey()) - .toString('hex'); -assert.strictEqual(modp2Secret, exmodp2_2Secret); -assert.strictEqual(exmodp2_2.verifyError, DH_NOT_SUITABLE_GENERATOR); - -// Ensure specific generator (string without encoding) works as expected. -const exmodp2_3 = crypto.createDiffieHellman(modp2buf, '\x02'); -exmodp2_3.generateKeys(); -modp2Secret = modp2.computeSecret(exmodp2_3.getPublicKey()).toString('hex'); -const exmodp2_3Secret = exmodp2_3.computeSecret(modp2.getPublicKey()) +{ + const exmodp2 = crypto.createDiffieHellman(modp2buf, Buffer.from([2])); + modp2.generateKeys(); + exmodp2.generateKeys(); + const modp2Secret = modp2.computeSecret(exmodp2.getPublicKey()) + .toString('hex'); + const exmodp2Secret = exmodp2.computeSecret(modp2.getPublicKey()) .toString('hex'); -assert.strictEqual(modp2Secret, exmodp2_3Secret); -assert.strictEqual(exmodp2_3.verifyError, DH_NOT_SUITABLE_GENERATOR); + assert.strictEqual(modp2Secret, exmodp2Secret); + assert.strictEqual(modp2.verifyError, DH_NOT_SUITABLE_GENERATOR); + assert.strictEqual(exmodp2.verifyError, DH_NOT_SUITABLE_GENERATOR); +} +{ + // Ensure specific generator (string with encoding) works as expected. + const exmodp2 = crypto.createDiffieHellman(modp2buf, '02', 'hex'); + exmodp2.generateKeys(); + const modp2Secret = modp2.computeSecret(exmodp2.getPublicKey()) + .toString('hex'); + const exmodp2Secret = exmodp2.computeSecret(modp2.getPublicKey()) + .toString('hex'); + assert.strictEqual(modp2Secret, exmodp2Secret); + assert.strictEqual(exmodp2.verifyError, DH_NOT_SUITABLE_GENERATOR); +} -// Ensure specific generator (numeric) works as expected. -const exmodp2_4 = crypto.createDiffieHellman(modp2buf, 2); -exmodp2_4.generateKeys(); -modp2Secret = modp2.computeSecret(exmodp2_4.getPublicKey()).toString('hex'); -const exmodp2_4Secret = exmodp2_4.computeSecret(modp2.getPublicKey()) - .toString('hex'); -assert.strictEqual(modp2Secret, exmodp2_4Secret); -assert.strictEqual(exmodp2_4.verifyError, DH_NOT_SUITABLE_GENERATOR); +{ + // Ensure specific generator (string with encoding) works as expected, + // with a Uint8Array as the first argument to createDiffieHellman(). + const exmodp2 = crypto.createDiffieHellman(new Uint8Array([...modp2buf]), + '02', 'hex'); + exmodp2.generateKeys(); + const modp2Secret = modp2.computeSecret(exmodp2.getPublicKey()) + .toString('hex'); + const exmodp2Secret = exmodp2.computeSecret(modp2.getPublicKey()) + .toString('hex'); + assert.strictEqual(modp2Secret, exmodp2Secret); + assert.strictEqual(exmodp2.verifyError, DH_NOT_SUITABLE_GENERATOR); +} + +{ + // Ensure specific generator (string without encoding) works as expected. + const exmodp2 = crypto.createDiffieHellman(modp2buf, '\x02'); + exmodp2.generateKeys(); + const modp2Secret = modp2.computeSecret(exmodp2.getPublicKey()) + .toString('hex'); + const exmodp2Secret = exmodp2.computeSecret(modp2.getPublicKey()) + .toString('hex'); + assert.strictEqual(modp2Secret, exmodp2Secret); + assert.strictEqual(exmodp2.verifyError, DH_NOT_SUITABLE_GENERATOR); +} + +{ + // Ensure specific generator (numeric) works as expected. + const exmodp2 = crypto.createDiffieHellman(modp2buf, 2); + exmodp2.generateKeys(); + const modp2Secret = modp2.computeSecret(exmodp2.getPublicKey()) + .toString('hex'); + const exmodp2Secret = exmodp2.computeSecret(modp2.getPublicKey()) + .toString('hex'); + assert.strictEqual(modp2Secret, exmodp2Secret); + assert.strictEqual(exmodp2.verifyError, DH_NOT_SUITABLE_GENERATOR); +} const p = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' + From 3a176d10f58d2ac18cdd38c3ad1263e378c3908b Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 24 Mar 2017 03:53:57 +0100 Subject: [PATCH 2/3] =?UTF-8?q?[squash]=20address=20bnoordhuis=E2=80=99=20?= =?UTF-8?q?and=20lpinca=E2=80=99s=20nits?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/crypto.js | 3 ++- test/parallel/test-crypto-dh.js | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/crypto.js b/lib/crypto.js index c280789b8eb8a2..662ddef60ef176 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -371,9 +371,10 @@ function DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding) { if (typeof sizeOrKey !== 'number' && typeof sizeOrKey !== 'string' && - !isUint8Array(sizeOrKey)) + !isUint8Array(sizeOrKey)) { throw new TypeError('First argument should be number, string, ' + 'Uint8Array or Buffer'); + } if (keyEncoding) { if (typeof keyEncoding !== 'string' || diff --git a/test/parallel/test-crypto-dh.js b/test/parallel/test-crypto-dh.js index 94169ec0822d98..7043b853ef6e70 100644 --- a/test/parallel/test-crypto-dh.js +++ b/test/parallel/test-crypto-dh.js @@ -120,7 +120,7 @@ const modp2buf = Buffer.from([ const modp2Secret = modp2.computeSecret(exmodp2.getPublicKey()) .toString('hex'); const exmodp2Secret = exmodp2.computeSecret(modp2.getPublicKey()) - .toString('hex'); + .toString('hex'); assert.strictEqual(modp2Secret, exmodp2Secret); assert.strictEqual(modp2.verifyError, DH_NOT_SUITABLE_GENERATOR); assert.strictEqual(exmodp2.verifyError, DH_NOT_SUITABLE_GENERATOR); @@ -133,7 +133,7 @@ const modp2buf = Buffer.from([ const modp2Secret = modp2.computeSecret(exmodp2.getPublicKey()) .toString('hex'); const exmodp2Secret = exmodp2.computeSecret(modp2.getPublicKey()) - .toString('hex'); + .toString('hex'); assert.strictEqual(modp2Secret, exmodp2Secret); assert.strictEqual(exmodp2.verifyError, DH_NOT_SUITABLE_GENERATOR); } @@ -147,7 +147,7 @@ const modp2buf = Buffer.from([ const modp2Secret = modp2.computeSecret(exmodp2.getPublicKey()) .toString('hex'); const exmodp2Secret = exmodp2.computeSecret(modp2.getPublicKey()) - .toString('hex'); + .toString('hex'); assert.strictEqual(modp2Secret, exmodp2Secret); assert.strictEqual(exmodp2.verifyError, DH_NOT_SUITABLE_GENERATOR); } @@ -159,7 +159,7 @@ const modp2buf = Buffer.from([ const modp2Secret = modp2.computeSecret(exmodp2.getPublicKey()) .toString('hex'); const exmodp2Secret = exmodp2.computeSecret(modp2.getPublicKey()) - .toString('hex'); + .toString('hex'); assert.strictEqual(modp2Secret, exmodp2Secret); assert.strictEqual(exmodp2.verifyError, DH_NOT_SUITABLE_GENERATOR); } @@ -171,7 +171,7 @@ const modp2buf = Buffer.from([ const modp2Secret = modp2.computeSecret(exmodp2.getPublicKey()) .toString('hex'); const exmodp2Secret = exmodp2.computeSecret(modp2.getPublicKey()) - .toString('hex'); + .toString('hex'); assert.strictEqual(modp2Secret, exmodp2Secret); assert.strictEqual(exmodp2.verifyError, DH_NOT_SUITABLE_GENERATOR); } From c5c41a88e9fb0b22cf0d148866ab18171512efcf Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 24 Mar 2017 19:57:49 +0100 Subject: [PATCH 3/3] =?UTF-8?q?[squash]=20address=20lpinca=E2=80=99s=20nit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/parallel/test-crypto-dh.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel/test-crypto-dh.js b/test/parallel/test-crypto-dh.js index 7043b853ef6e70..275d0a297f69dd 100644 --- a/test/parallel/test-crypto-dh.js +++ b/test/parallel/test-crypto-dh.js @@ -141,7 +141,7 @@ const modp2buf = Buffer.from([ { // Ensure specific generator (string with encoding) works as expected, // with a Uint8Array as the first argument to createDiffieHellman(). - const exmodp2 = crypto.createDiffieHellman(new Uint8Array([...modp2buf]), + const exmodp2 = crypto.createDiffieHellman(new Uint8Array(modp2buf), '02', 'hex'); exmodp2.generateKeys(); const modp2Secret = modp2.computeSecret(exmodp2.getPublicKey())