Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to generate a random 6 digit passphrase in node.js using randomBytes()

I am trying to generate exactly 6 random digits in Node.js, which needs to be cryptographically secure. Here is my code:

var crypto = require('crypto');

crypto.randomBytes(2, function(err, buffer) {
    console.log(parseInt(buffer.toString('hex'), 16));
});

The problem is that the result from this can be 4 or 5 digits, because we are converting from hex to decimal. Is there a way to keep the cryptographically secure function randomBytes(), but guarantee a 6 digit result?

like image 546
Justin Avatar asked Nov 03 '22 18:11

Justin


2 Answers

2 bytes have a maximum value of 65535, so you will never get 6 digits if you only use 2 bytes.

Use 3 bytes instead and then reduce it to 6 digits using substr:

var crypto = require('crypto');
crypto.randomBytes(3, function(err, buffer) {
    console.log(parseInt(buffer.toString('hex'), 16).toString().substr(0,6));
});

Another solution would be to execute randomBytes until you get a 6 digit value:

var crypto = require('crypto');
var secureVal = 0;
function generateSecureVal(cb) {
    crypto.randomBytes(3, function(err, buffer) {
        secureVal = parseInt(buffer.toString('hex'), 16);
        if (secureVal > 999999 || secureVal < 100000) {
            generateSecureVal(cb);
        } else {
            cb();
        }
    });
}

generateSecureVal(function(){
    console.log(secureVal);
});

The problem with the above is that it could theoretically get stuck in a neverending loop, and it will most likely use way more CPU cycles than the first example.

like image 84
mekwall Avatar answered Nov 09 '22 09:11

mekwall


A new function for doing this was added to Node v14.17

crypto.randomInt([min, ]max[, callback])

To get a 6 digit integer.

const crypto = require('crypto');
crypto.randomInt(100000, 999999, (err, n) => {
    if (err) throw err;
    console.log(`Random 6 digit integer: ${n}`);
});

Also per the documentation https://nodejs.org/api/crypto.html#cryptorandomintmin-max-callback you should also check that your min and max values are safe integers via:

Number.isSafeInteger() 
like image 21
schmidlop Avatar answered Nov 09 '22 09:11

schmidlop