From 8fc10c8322ddea610f3e42305d3cfa3321cb5cbb Mon Sep 17 00:00:00 2001 From: kyungrae Date: Thu, 30 Jul 2026 01:28:40 +0900 Subject: [PATCH 1/3] test,doc: cover and document multi-byte offset/size in randomFill Signed-off-by: kyungrae --- doc/api/crypto.md | 18 ++++++++----- test/parallel/test-crypto-random.js | 42 +++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/doc/api/crypto.md b/doc/api/crypto.md index b73093c648a9..0806500113b5 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -5574,9 +5574,12 @@ changes: * `buffer` {ArrayBuffer|Buffer|TypedArray|DataView} Must be supplied. The size of the provided `buffer` must not be larger than `2**31 - 1`. -* `offset` {number} **Default:** `0` -* `size` {number} **Default:** `buffer.length - offset`. The `size` must - not be larger than `2**31 - 1`. +* `offset` {number} The start position, in elements for a `TypedArray` and in + bytes for an `ArrayBuffer` or `DataView`. **Default:** `0` +* `size` {number} The amount to fill, in the same units as `offset`. + **Default:** `buffer.length - offset` for a `TypedArray`, or + `buffer.byteLength - offset` for an `ArrayBuffer` or `DataView`. The `size` + must not be larger than `2**31 - 1`. * `callback` {Function} `function(err, buf) {}`. This function is similar to [`crypto.randomBytes()`][] but requires the first @@ -5711,9 +5714,12 @@ changes: * `buffer` {ArrayBuffer|Buffer|TypedArray|DataView} Must be supplied. The size of the provided `buffer` must not be larger than `2**31 - 1`. -* `offset` {number} **Default:** `0` -* `size` {number} **Default:** `buffer.length - offset`. The `size` must - not be larger than `2**31 - 1`. +* `offset` {number} The start position, in elements for a `TypedArray` and in + bytes for an `ArrayBuffer` or `DataView`. **Default:** `0` +* `size` {number} The amount to fill, in the same units as `offset`. + **Default:** `buffer.length - offset` for a `TypedArray`, or + `buffer.byteLength - offset` for an `ArrayBuffer` or `DataView`. The `size` + must not be larger than `2**31 - 1`. * Returns: {ArrayBuffer|Buffer|TypedArray|DataView} The object passed as `buffer` argument. diff --git a/test/parallel/test-crypto-random.js b/test/parallel/test-crypto-random.js index ceaa859a0e03..66305e000bff 100644 --- a/test/parallel/test-crypto-random.js +++ b/test/parallel/test-crypto-random.js @@ -218,6 +218,48 @@ common.expectWarning('DeprecationWarning', })); } +{ + const buf = new Uint16Array(4); + const before = Buffer.from(buf.buffer).toString('hex'); + crypto.randomFillSync(buf, 1, 1); + const after = Buffer.from(buf.buffer).toString('hex'); + assert.notStrictEqual(before, after); + assert.deepStrictEqual(before.slice(0, 4), after.slice(0, 4)); + assert.deepStrictEqual(before.slice(8), after.slice(8)); +} + +{ + const buf = new Uint32Array(4); + const before = Buffer.from(buf.buffer).toString('hex'); + crypto.randomFillSync(buf, 1, 1); + const after = Buffer.from(buf.buffer).toString('hex'); + assert.notStrictEqual(before, after); + assert.deepStrictEqual(before.slice(0, 8), after.slice(0, 8)); + assert.deepStrictEqual(before.slice(16), after.slice(16)); +} + +{ + const buf = new Uint16Array(4); + const before = Buffer.from(buf.buffer).toString('hex'); + crypto.randomFill(buf, 1, 1, common.mustSucceed((buf) => { + const after = Buffer.from(buf.buffer).toString('hex'); + assert.notStrictEqual(before, after); + assert.deepStrictEqual(before.slice(0, 4), after.slice(0, 4)); + assert.deepStrictEqual(before.slice(8), after.slice(8)); + })); +} + +{ + const buf = new Uint32Array(4); + const before = Buffer.from(buf.buffer).toString('hex'); + crypto.randomFill(buf, 1, 1, common.mustSucceed((buf) => { + const after = Buffer.from(buf.buffer).toString('hex'); + assert.notStrictEqual(before, after); + assert.deepStrictEqual(before.slice(0, 8), after.slice(0, 8)); + assert.deepStrictEqual(before.slice(16), after.slice(16)); + })); +} + { [ Buffer.alloc(10), From 54310ecfc0bb370bc719a7fd91770e6442355e16 Mon Sep 17 00:00:00 2001 From: kyungrae Date: Fri, 31 Jul 2026 23:46:35 +0900 Subject: [PATCH 2/3] crypto: fix randomFill() with offset for ArrayBuffer and DataView Signed-off-by: kyungrae --- lib/internal/crypto/random.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/crypto/random.js b/lib/internal/crypto/random.js index a75c14fd2a1c..919ad68f5617 100644 --- a/lib/internal/crypto/random.js +++ b/lib/internal/crypto/random.js @@ -168,7 +168,7 @@ function randomFill(buf, offset, size, callback) { size = buf.length; } else if (typeof size === 'function') { callback = size; - size = buf.length - offset; + size = (buf.length ?? buf.byteLength) - offset; } else { validateFunction(callback, 'callback'); } From fe7d6b18c874afd2fca4801cb87cbc2d0bd29bea Mon Sep 17 00:00:00 2001 From: kyungrae Date: Fri, 31 Jul 2026 23:46:44 +0900 Subject: [PATCH 3/3] test: make multi-byte randomFill tests flaky-safe Signed-off-by: kyungrae --- test/parallel/test-crypto-random.js | 31 ++++++++++++++++++----------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/test/parallel/test-crypto-random.js b/test/parallel/test-crypto-random.js index 66305e000bff..88b6fcba84d7 100644 --- a/test/parallel/test-crypto-random.js +++ b/test/parallel/test-crypto-random.js @@ -219,47 +219,54 @@ common.expectWarning('DeprecationWarning', } { - const buf = new Uint16Array(4); + const buf = new Uint16Array(10); const before = Buffer.from(buf.buffer).toString('hex'); - crypto.randomFillSync(buf, 1, 1); + crypto.randomFillSync(buf, 1, 8); const after = Buffer.from(buf.buffer).toString('hex'); assert.notStrictEqual(before, after); assert.deepStrictEqual(before.slice(0, 4), after.slice(0, 4)); - assert.deepStrictEqual(before.slice(8), after.slice(8)); + assert.deepStrictEqual(before.slice(-4), after.slice(-4)); } { - const buf = new Uint32Array(4); + const buf = new Uint32Array(10); const before = Buffer.from(buf.buffer).toString('hex'); - crypto.randomFillSync(buf, 1, 1); + crypto.randomFillSync(buf, 1, 8); const after = Buffer.from(buf.buffer).toString('hex'); assert.notStrictEqual(before, after); assert.deepStrictEqual(before.slice(0, 8), after.slice(0, 8)); - assert.deepStrictEqual(before.slice(16), after.slice(16)); + assert.deepStrictEqual(before.slice(-8), after.slice(-8)); } { - const buf = new Uint16Array(4); + const buf = new Uint16Array(10); const before = Buffer.from(buf.buffer).toString('hex'); - crypto.randomFill(buf, 1, 1, common.mustSucceed((buf) => { + crypto.randomFill(buf, 1, 8, common.mustSucceed((buf) => { const after = Buffer.from(buf.buffer).toString('hex'); assert.notStrictEqual(before, after); assert.deepStrictEqual(before.slice(0, 4), after.slice(0, 4)); - assert.deepStrictEqual(before.slice(8), after.slice(8)); + assert.deepStrictEqual(before.slice(-4), after.slice(-4)); })); } { - const buf = new Uint32Array(4); + const buf = new Uint32Array(10); const before = Buffer.from(buf.buffer).toString('hex'); - crypto.randomFill(buf, 1, 1, common.mustSucceed((buf) => { + crypto.randomFill(buf, 1, 8, common.mustSucceed((buf) => { const after = Buffer.from(buf.buffer).toString('hex'); assert.notStrictEqual(before, after); assert.deepStrictEqual(before.slice(0, 8), after.slice(0, 8)); - assert.deepStrictEqual(before.slice(16), after.slice(16)); + assert.deepStrictEqual(before.slice(-8), after.slice(-8)); })); } +{ + // randomFill() with an offset and no size must not throw for types + // without a .length property, matching randomFillSync(). + crypto.randomFill(new ArrayBuffer(10), 2, common.mustSucceed()); + crypto.randomFill(new DataView(new ArrayBuffer(10)), 2, common.mustSucceed()); +} + { [ Buffer.alloc(10),