introduce query to detect biased random number generators

This commit is contained in:
Erik Krogh Kristensen
2020-06-09 23:08:52 +02:00
parent c580ada527
commit 111f6d406c
5 changed files with 249 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
| bad-random.js:3:11:3:61 | crypto. ... s(1)[0] | Using addition on cryptographically random numbers produces biased results. |
| bad-random.js:4:11:4:61 | crypto. ... s(1)[0] | Using multiplication on cryptographically random numbers produces biased results. |
| bad-random.js:9:28:9:43 | buffer[i] / 25.6 | Using division on cryptographically random numbers produces biased results. |
| bad-random.js:11:17:11:31 | buffer[i] % 100 | Using modulo on cryptographically random numbers produces biased results. |
| bad-random.js:14:11:14:63 | Number( ... (0, 3)) | Using string concatenation on cryptographically random numbers produces biased results. |
| bad-random.js:73:32:73:42 | byte / 25.6 | Using division on cryptographically random numbers produces biased results. |
| bad-random.js:75:21:75:30 | byte % 100 | Using modulo on cryptographically random numbers produces biased results. |

View File

@@ -0,0 +1 @@
Security/CWE-327/BadRandomness.ql

View File

@@ -0,0 +1,77 @@
const crypto = require('crypto');
var bad = crypto.randomBytes(1)[0] + crypto.randomBytes(1)[0]; // NOT OK
var bad = crypto.randomBytes(1)[0] * crypto.randomBytes(1)[0]; // NOT OK
const buffer = crypto.randomBytes(bytes);
const digits = [];
for (let i = 0; i < buffer.length; ++i) {
digits.push(Math.floor(buffer[i] / 25.6)); // NOT OK
digits.push(buffer[i] % 8); // OK - 8 is a power of 2, so the result is unbiased.
digits.push(buffer[i] % 100); // NOT OK
}
var bad = Number('0.' + crypto.randomBytes(3).readUIntBE(0, 3)); // NOT OK
var good = Number(10 + crypto.randomBytes(3).readUIntBE(0, 3)); // OK
const internals = {};
exports.randomDigits = function (size) {
const digits = [];
let buffer = internals.random(size * 2);
let pos = 0;
while (digits.length < size) {
if (pos >= buffer.length) {
buffer = internals.random(size * 2);
pos = 0;
}
if (buffer[pos] < 250) {
digits.push(buffer[pos] % 10); // GOOD - protected by a bias-checking comparison.
}
++pos;
}
return digits.join('');
};
internals.random = function (bytes) {
try {
return crypto.randomBytes(bytes);
}
catch (err) {
throw new Error("Failed to make bits.");
}
};
exports.randomDigits2 = function (size) {
const digits = [];
let buffer = crypto.randomBytes(size * 2);
let pos = 0;
while (digits.length < size) {
if (pos >= buffer.length) {
buffer = internals.random(size * 2);
pos = 0;
}
var num = buffer[pos];
if (num < 250) {
digits.push(num % 10); // GOOD - protected by a bias-checking comparison.
}
++pos;
}
return digits.join('');
};
function setSteps() {
const buffer = crypto.randomBytes(bytes);
const digits = [];
for (const byte of buffer.values()) {
digits.push(Math.floor(byte / 25.6)); // NOT OK
digits.push(byte % 8); // OK - 8 is a power of 2, so the result is unbiased.
digits.push(byte % 100); // NOT OK
}
}