I need a replacement for PHP's rand()
function that uses a cryptographically strong random number generator.
The openssl_random_pseudo_bytes()
function gets you access to the strong random number generator, but it outputs its data as a byte string. Instead, I need an integer between 0 and X.
I imagine the key is to get the output of openssl_random_pseudo_bytes()
into an integer, then you can do any math on it that you need to. I can think of a few "brute force" ways of converting from a byte string to an integer, but I was hoping for something ... elegant.
Using provided suggestions, I've created a drop-in replacement for rand() using OpenSSL. I'll include it here for posterity.
The $pedantic option gives bias-free results by starting over when results won't be evenly distributed across the possible range.
function crypto_rand($min,$max,$pedantic=True) {
$diff = $max - $min;
if ($diff <= 0) return $min; // not so random...
$range = $diff + 1; // because $max is inclusive
$bits = ceil(log(($range),2));
$bytes = ceil($bits/8.0);
$bits_max = 1 << $bits;
// e.g. if $range = 3000 (bin: 101110111000)
// +--------+--------+
// |....1011|10111000|
// +--------+--------+
// bits=12, bytes=2, bits_max=2^12=4096
$num = 0;
do {
$num = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes))) % $bits_max;
if ($num >= $range) {
if ($pedantic) continue; // start over instead of accepting bias
// else
$num = $num % $range; // to hell with security
}
break;
} while (True); // because goto attracts velociraptors
return $num + $min;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With