用 openssl_random_pseudo_bytes() 替换 rand()
我需要替换 PHP 的 rand()
函数,该函数使用强加密随机数生成器.
I need a replacement for PHP's rand()
function that uses a cryptographically strong random number generator.
openssl_random_pseudo_bytes()
函数可让您访问强随机数生成器,但它会将其数据输出为字节字符串.相反,我需要一个介于 0 和 X 之间的整数.
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.
我想关键是将 openssl_random_pseudo_bytes()
的输出转换为整数,然后您可以对其进行任何您需要的数学运算.我可以想到一些从字节字符串转换为整数的蛮力"方法,但我希望得到一些……优雅的东西.
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.
推荐答案
使用提供的建议,我使用 OpenSSL 创建了一个替代 rand() 的插件.我会把它包括在这里以供后代使用.
Using provided suggestions, I've created a drop-in replacement for rand() using OpenSSL. I'll include it here for posterity.
$pedantic 选项通过在结果不会在可能的范围内均匀分布时重新开始来提供无偏差的结果.
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;
}
相关文章