Skip to content

Commit

Permalink
random: tighten up security. fixes bcoin-org#43.
Browse files Browse the repository at this point in the history
  • Loading branch information
chjj committed Feb 25, 2020
1 parent 3b348ca commit 1b7bcda
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 39 deletions.
2 changes: 2 additions & 0 deletions lib/bcrypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,5 @@ exports.x448 = require('./x448');

exports.version = '5.0.3';
exports.native = exports.SHA256.native;

Object.freeze(exports);
48 changes: 20 additions & 28 deletions lib/js/random.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const assert = require('../internal/assert');

const crypto = global.crypto || global.msCrypto;
const HAS_CRYPTO = crypto && typeof crypto.getRandomValues === 'function';
const getRandomValues = HAS_CRYPTO ? crypto.getRandomValues.bind(crypto) : null;
const MAX_BYTES = 65536;

/**
Expand All @@ -33,7 +34,7 @@ function randomBytes(size) {

const data = Buffer.allocUnsafeSlow(size);

getRandomValues(data);
randomFillSync(data);

return data;
}
Expand All @@ -60,7 +61,7 @@ function randomFill(data, off, size) {
assert((size >>> 0) === size);
assert(off + size <= data.length);

getRandomValues(data.slice(off, off + size));
randomFillSync(data.slice(off, off + size));

return data;
}
Expand Down Expand Up @@ -101,6 +102,8 @@ function randomRange(min, max) {
let x, r;

do {
array[0] = 0;

getRandomValues(array);

x = array[0];
Expand All @@ -114,12 +117,15 @@ function randomRange(min, max) {
* Helpers
*/

function getRandomValues(data) {
function randomFillSync(data) {
assert(data != null && typeof data === 'object');
assert(data.buffer instanceof ArrayBuffer);
assert((data.byteOffset >>> 0) === data.byteOffset);
assert((data.byteLength >>> 0) === data.byteLength);

if (!HAS_CRYPTO)
throw new Error('Entropy source not available.');

if (data.byteLength > 2 ** 31 - 1)
throw new RangeError('The value "size" is out of range.');

Expand All @@ -135,35 +141,19 @@ function getRandomValues(data) {
array[i] = 0x00;
}

// Native WebCrypto support.
if (HAS_CRYPTO) {
if (array.length > MAX_BYTES) {
for (let i = 0; i < array.length; i += MAX_BYTES) {
let j = i + MAX_BYTES;
if (array.length > MAX_BYTES) {
for (let i = 0; i < array.length; i += MAX_BYTES) {
let j = i + MAX_BYTES;

if (j > array.length)
j = array.length;
if (j > array.length)
j = array.length;

crypto.getRandomValues(array.subarray(i, j));
}
} else {
if (array.length > 0)
crypto.getRandomValues(array);
getRandomValues(array.subarray(i, j));
}

return;
}

// Fallback to Math.random (FOR TESTING ONLY).
if (!process.browser && process.env.NODE_TEST === '1') {
for (let i = 0; i < array.length; i++)
array[i] = Math.floor(Math.random() * 0x100);

return;
} else {
if (array.length > 0)
getRandomValues(array);
}

// Error if no randomness is available.
throw new Error('Entropy source not available.');
}

/*
Expand All @@ -175,3 +165,5 @@ exports.randomBytes = randomBytes;
exports.randomFill = randomFill;
exports.randomInt = randomInt;
exports.randomRange = randomRange;

Object.freeze(exports);
15 changes: 9 additions & 6 deletions lib/native/random.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

const assert = require('../internal/assert');
const crypto = require('crypto');
const randomFillSync = crypto.randomFillSync.bind(crypto);

/**
* Generate pseudo-random bytes.
Expand All @@ -25,7 +26,7 @@ function randomBytes(size) {

const data = Buffer.alloc(size, 0x00);

crypto.randomFillSync(data, 0, size);
randomFillSync(data, 0, size);

return data;
}
Expand Down Expand Up @@ -54,7 +55,7 @@ function randomFill(data, off, size) {

data.fill(0x00, off, off + size);

crypto.randomFillSync(data, off, size);
randomFillSync(data, off, size);

return data;
}
Expand Down Expand Up @@ -95,6 +96,8 @@ function randomRange(min, max) {
let x, r;

do {
array[0] = 0;

getRandomValues(array);

x = array[0];
Expand All @@ -117,22 +120,20 @@ function getRandomValues(array) {
if (hasTypedArray === null) {
try {
// Added in 9.0.0.
crypto.randomFillSync(new Uint32Array(1));
randomFillSync(new Uint32Array(1));
hasTypedArray = true;
} catch (e) {
hasTypedArray = false;
}
}

array.fill(0, 0, array.length);

if (!hasTypedArray) {
array = Buffer.from(array.buffer,
array.byteOffset,
array.byteLength);
}

crypto.randomFillSync(array);
randomFillSync(array);
}

/*
Expand All @@ -144,3 +145,5 @@ exports.randomBytes = randomBytes;
exports.randomFill = randomFill;
exports.randomInt = randomInt;
exports.randomRange = randomRange;

Object.freeze(exports);
5 changes: 1 addition & 4 deletions lib/random.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,4 @@

'use strict';

if (process.env.NODE_BACKEND === 'js' && process.env.NODE_TEST === '1')
module.exports = require('./js/random');
else
module.exports = require('./native/random');
module.exports = require('./native/random');
2 changes: 1 addition & 1 deletion test/bcrypto-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ describe('Bcrypto', function() {
assert.strictEqual(bcrypto.pbkdf2.native, 0);
assert.strictEqual(bcrypto.pgp.native, undefined);
assert.strictEqual(bcrypto.Poly1305.native, 0);
assert.strictEqual(bcrypto.random.native, 0);
assert.strictEqual(bcrypto.random.native, process.browser ? 0 : 1);
assert.strictEqual(bcrypto.RC4.native, 0);
assert.strictEqual(bcrypto.RIPEMD160.native, 0);
assert.strictEqual(bcrypto.rsa.native, 0);
Expand Down

0 comments on commit 1b7bcda

Please sign in to comment.