Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js - How to generate random numbers in specific range using crypto.randomBytes

How can I generate random numbers in a specific range using crypto.randomBytes?

I want to be able to generate a random number like this:

console.log(random(55, 956)); // where 55 is minimum and 956 is maximum

and I'm limited to use crypto.randomBytes only inside random function to generate random number for this range.

I know how to convert generated bytes from randomBytes to hex or decimal but I can't figure out how to get a random number in a specific range from random bytes mathematically.

like image 439
Nicolo Avatar asked Nov 09 '15 12:11

Nicolo


People also ask

How do I generate a random number in node JS?

Calculate a random number between the min and max values like this:use Math. random() to generate a random number, multiply this random number with the difference of min and max and ultimately add min to it. This random number is between min and max , but not an integer. Finally, round the number with Math.

Is crypto randomBytes secure?

crypto.randomBytes(size[, callback]) Generates cryptographically strong pseudo-random data. The size argument is a number indicating the number of bytes to generate. This means that the random data is secure enough to use for encryption purposes.


2 Answers

To generate random number in a certain range you can use the following equation

Math.random() * (high - low) + low

But you want to use crypto.randomBytes instead of Math.random() this function returns a buffer with randomly generated bytes. In turn, you need to convert the result of this function from bytes to decimal. this can be done using biguint-format package. To install this package simply use the following command:

npm install biguint-format --save

Now you need to convert the result of crypto.randomBytes to decimal, you can do that as follow:

var x= crypto.randomBytes(1);
return format(x, 'dec');

Now you can create your random function which will be as follow:

var crypto = require('crypto'),
    format = require('biguint-format');

function randomC (qty) {
    var x= crypto.randomBytes(qty);
    return format(x, 'dec');
}
function random (low, high) {
    return randomC(4)/Math.pow(2,4*8-1) * (high - low) + low;
}
console.log(random(50,1000));
like image 187
Mustafamg Avatar answered Oct 24 '22 19:10

Mustafamg


Thanks to answer from @Mustafamg and huge help from @CodesInChaos I managed to resolve this issue. I made some tweaks and increase range to maximum 256^6-1 or 281,474,976,710,655. Range can be increased more but you need to use additional library for big integers, because 256^7-1 is out of Number.MAX_SAFE_INTEGER limits.

If anyone have same problem feel free to use it.

var crypto = require('crypto');

/*
Generating random numbers in specific range using crypto.randomBytes from crypto library
Maximum available range is 281474976710655 or 256^6-1
Maximum number for range must be equal or less than Number.MAX_SAFE_INTEGER (usually 9007199254740991)
Usage examples:
cryptoRandomNumber(0, 350);
cryptoRandomNumber(556, 1250425);
cryptoRandomNumber(0, 281474976710655);
cryptoRandomNumber((Number.MAX_SAFE_INTEGER-281474976710655), Number.MAX_SAFE_INTEGER);

Tested and working on 64bit Windows and Unix operation systems.
*/

function cryptoRandomNumber(minimum, maximum){
	var distance = maximum-minimum;
	
	if(minimum>=maximum){
		console.log('Minimum number should be less than maximum');
		return false;
	} else if(distance>281474976710655){
		console.log('You can not get all possible random numbers if range is greater than 256^6-1');
		return false;
	} else if(maximum>Number.MAX_SAFE_INTEGER){
		console.log('Maximum number should be safe integer limit');
		return false;
	} else {
		var maxBytes = 6;
		var maxDec = 281474976710656;
		
		// To avoid huge mathematical operations and increase function performance for small ranges, you can uncomment following script
		/*
		if(distance<256){
			maxBytes = 1;
			maxDec = 256;
		} else if(distance<65536){
			maxBytes = 2;
			maxDec = 65536;
		} else if(distance<16777216){
			maxBytes = 3;
			maxDec = 16777216;
		} else if(distance<4294967296){
			maxBytes = 4;
			maxDec = 4294967296;
		} else if(distance<1099511627776){
			maxBytes = 4;
			maxDec = 1099511627776;
		}
		*/
		
		var randbytes = parseInt(crypto.randomBytes(maxBytes).toString('hex'), 16);
		var result = Math.floor(randbytes/maxDec*(maximum-minimum+1)+minimum);
		
		if(result>maximum){
			result = maximum;
		}
		return result;
	}
}

So far it works fine and you can use it as really good random number generator, but I strictly not recommending using this function for any cryptographic services. If you will, use it on your own risk.

All comments, recommendations and critics are welcome!

like image 37
Nicolo Avatar answered Oct 24 '22 19:10

Nicolo