Commit f930e3ad449 for nodejs
commit f930e3ad44976b756efabbe4dcb5e2df6ee1d4b6
Author: Filip Skokan <panva.ip@gmail.com>
Date: Tue Sep 22 22:25:22 2026 +0200
crypto: copy derived bits without species
Use the byte-copy helper for truncated ECDH results so ArrayBuffer
species cannot replace or resize the returned key material.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/66237
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Aviv Keller <me@aviv.sh>
diff --git a/lib/internal/crypto/diffiehellman.js b/lib/internal/crypto/diffiehellman.js
index 63a9451b3cc..46659419c8d 100644
--- a/lib/internal/crypto/diffiehellman.js
+++ b/lib/internal/crypto/diffiehellman.js
@@ -2,7 +2,6 @@
const {
ArrayBufferPrototypeGetByteLength,
- ArrayBufferPrototypeSlice,
FunctionPrototypeCall,
ObjectDefineProperty,
TypedArrayPrototypeGetBuffer,
@@ -381,11 +380,8 @@ function ecdhDeriveBits(algorithm, baseKey, length) {
if (byteLength < sliceLength)
throw lazyDOMException('derived bit length is too small', 'OperationError');
- if (length % 8 === 0) {
- if (byteLength === sliceLength)
- return bits;
- return ArrayBufferPrototypeSlice(bits, 0, sliceLength);
- }
+ if (length % 8 === 0 && byteLength === sliceLength)
+ return bits;
return TypedArrayPrototypeGetBuffer(truncateToBitLength(length, bits));
});
diff --git a/test/parallel/test-webcrypto-derived-bits-species.js b/test/parallel/test-webcrypto-derived-bits-species.js
new file mode 100644
index 00000000000..491dc0df877
--- /dev/null
+++ b/test/parallel/test-webcrypto-derived-bits-species.js
@@ -0,0 +1,26 @@
+'use strict';
+
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const { subtle } = globalThis.crypto;
+
+(async () => {
+ const keys = await subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256' }, false, ['deriveBits']);
+ const algorithm = { name: 'ECDH', public: keys.publicKey };
+ const expected = await subtle.deriveBits(algorithm, keys.privateKey, 128);
+ const species = Object.getOwnPropertyDescriptor(ArrayBuffer, Symbol.species);
+ Object.defineProperty(ArrayBuffer, Symbol.species, {
+ configurable: true,
+ get: common.mustNotCall(),
+ });
+ try {
+ const actual = await subtle.deriveBits(algorithm, keys.privateKey, 128);
+ assert.deepStrictEqual(actual, expected);
+ assert.strictEqual(Object.getPrototypeOf(actual), ArrayBuffer.prototype);
+ } finally {
+ Object.defineProperty(ArrayBuffer, Symbol.species, species);
+ }
+})().then(common.mustCall());