Skip to content

Commit 93d36bf

Browse files
panvaaduh95
authored andcommitted
crypto: allow non-multiple of 8 in SubtleCrypto.deriveBits
PR-URL: #55296 Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent cf3f7ac commit 93d36bf

5 files changed

Lines changed: 28 additions & 27 deletions

File tree

‎doc/api/webcrypto.md‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -600,9 +600,6 @@ Using the method and parameters specified in `algorithm` and the keying
600600
material provided by `baseKey`, `subtle.deriveBits()` attempts to generate
601601
`length` bits.
602602

603-
The Node.js implementation requires that `length`, when a number, is a multiple
604-
of `8`.
605-
606603
When `length` is not provided or `null` the maximum number of bits for a given
607604
algorithm is generated. This is allowed for the `'ECDH'`, `'X25519'`, and `'X448'`
608605
algorithms, for other algorithms `length` is required to be a number.

‎lib/internal/crypto/diffiehellman.js‎

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const {
55
MathCeil,
66
ObjectDefineProperty,
77
SafeSet,
8+
Uint8Array,
89
}=primordials;
910

1011
const{ Buffer }=require('buffer');
@@ -295,6 +296,8 @@ function diffieHellman(options) {
295296
returnstatelessDH(privateKey[kHandle],publicKey[kHandle]);
296297
}
297298

299+
letmasks;
300+
298301
// The ecdhDeriveBits function is part of the Web Crypto API and serves both
299302
// deriveKeys and deriveBits functions.
300303
asyncfunctionecdhDeriveBits(algorithm,baseKey,length){
@@ -341,18 +344,25 @@ async function ecdhDeriveBits(algorithm, baseKey, length) {
341344

342345
// If the length is not a multiple of 8 the nearest ceiled
343346
// multiple of 8 is sliced.
344-
length=MathCeil(length/8);
345-
const{ byteLength }=bits;
347+
constsliceLength=MathCeil(length/8);
346348

349+
const{ byteLength }=bits;
347350
// If the length is larger than the derived secret, throw.
348-
// Otherwise, we either return the secret or a truncated
349-
// slice.
350-
if(byteLength<length)
351+
if(byteLength<sliceLength)
351352
throwlazyDOMException('derived bit length is too small','OperationError');
352353

353-
returnlength===byteLength ?
354-
bits :
355-
ArrayBufferPrototypeSlice(bits,0,length);
354+
constslice=ArrayBufferPrototypeSlice(bits,0,sliceLength);
355+
356+
constmod=length%8;
357+
if(mod===0)
358+
returnslice;
359+
360+
// eslint-disable-next-line no-sparse-arrays
361+
masks||=[,0b10000000,0b11000000,0b11100000,0b11110000,0b11111000,0b11111100,0b11111110];
362+
363+
constmasked=newUint8Array(slice);
364+
masked[sliceLength-1]=masked[sliceLength-1]&masks[mod];
365+
returnmasked.buffer;
356366
}
357367

358368
module.exports={

‎test/parallel/test-webcrypto-derivebits-cfrg.js‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,11 @@ async function prepareKeys() {
140140
public: publicKey
141141
},privateKey,8*size-11);
142142

143-
assert.strictEqual(
144-
Buffer.from(bits).toString('hex'),
145-
result.slice(0,-2));
143+
constexpected=Buffer.from(result.slice(0,-2),'hex');
144+
expected[size-2]=expected[size-2]&0b11111000;
145+
assert.deepStrictEqual(
146+
Buffer.from(bits),
147+
expected);
146148
}
147149
}));
148150

‎test/parallel/test-webcrypto-derivebits-ecdh.js‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,11 @@ async function prepareKeys() {
161161
public: publicKey
162162
},privateKey,8*size-11);
163163

164-
assert.strictEqual(
165-
Buffer.from(bits).toString('hex'),
166-
result.slice(0,-2));
164+
constexpected=Buffer.from(result.slice(0,-2),'hex');
165+
expected[size-2]=expected[size-2]&0b11111000;
166+
assert.deepStrictEqual(
167+
Buffer.from(bits),
168+
expected);
167169
}
168170
}));
169171

‎test/wpt/status/WebCryptoAPI.cjs‎

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,6 @@ module.exports = {
88
'algorithm-discards-context.https.window.js': {
99
'skip': 'Not relevant in Node.js context',
1010
},
11-
'derive_bits_keys/derived_bits_length.https.any.js': {
12-
'fail': {
13-
// See https://github.com/nodejs/node/pull/55296
14-
// The fix is pending a decision whether truncation in ECDH/X* will be removed from the spec entirely
15-
'expected': [
16-
"ECDH derivation with 230 as 'length' parameter",
17-
"X25519 derivation with 230 as 'length' parameter",
18-
],
19-
},
20-
},
2111
'historical.any.js': {
2212
'skip': 'Not relevant in Node.js context',
2313
},

0 commit comments

Comments
 (0)