用openssl_random_pseudo_bytes()替换rand()

时间:2009-08-21 17:24:33

标签: php random cryptography

我需要替换使用加密强随机数生成器的PHP rand()函数。

openssl_random_pseudo_bytes()函数可让您访问强随机数生成器,但它将其数据作为字节字符串输出。相反,我需要一个介于0和 X 之间的整数。

我想关键是将openssl_random_pseudo_bytes()的输出变成一个整数,然后你可以根据需要对它进行任何数学运算。我可以想到一些从字节串转换为整数的“蛮力”方式,但我希望有一些......优雅。

7 个答案:

答案 0 :(得分:12)

使用提供的建议,我已经使用OpenSSL为rand()创建了一个替代品。我将它包含在这里供后人使用。

$ pedantic 选项通过在结果不会在可能的范围内均匀分布时重新开始提供无偏差结果。

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;
}

答案 1 :(得分:8)

openssl_random_pseudo_bytes()的手册页有一个我认为你想要的例子。您只需在bin2hex()的输出上调用openssl_random_pseudo_bytes()即可转换为十六进制数,然后在该值上hexdec()转换为十进制数。

$rand_num = hexdec(bin2hex(openssl_random_pseudo_bytes($length, $strong)));

此时,你可以做任何想要获得所需范围值的数学运算。您可能拥有的另一个(骗子)选项是运行系统命令以生成随机数 - 对于在线提供的各种操作系统,随机数生成器有一些不错的选项。

答案 2 :(得分:2)

以上解决方案的一个版本,它不使用递归函数调用:

function secure_rand($min,$max) {
    $range = $max - $min + 1;
    if ($range == 0) return $min;
    $length = (int) (log($range,2) / 8) + 1;
    $max = pow(2, 8 * $length);
    $num = $max + 1; // Hackish, I know..
    while ($num > $max) {
        $num = hexdec(bin2hex(openssl_random_pseudo_bytes($length,$s)));
    }
    return ($num  % $range) + $min;
}

答案 3 :(得分:2)

由于PHP 7现已推出,解决此问题的最简单方法是将mt_rand的所有实例替换为random_int

(假设您已经升级,那就是。)

答案 4 :(得分:1)

好吧,只需在openssl_random_pseudo_bytes的结果上使用hexdec,你就会得到你的整数。它是如此优雅:)

print hexdec('45261b8f');

>  1160125327

答案 5 :(得分:0)

执行此操作的最简单方法(以及此处所有选项中最安全的方法)是使用具有randomInt函数的CryptoLib,该函数为rand提供直接替代。

首先从您的项目中下载CryptoLib并将其粘贴到您的项目中:https://github.com/IcyApril/CryptoLib

两,请输入此代码。将path / to /替换为cryptolib.php目录,将min max替换为最小和最大数字:

<?php
  require_once('path/to/cryptoLib.php');

  $min = 1;
  $max = 5;

  $randomNum = CryptoLib::randomInt($min, $max);
?>

CryptoLib完整文档位于:https://cryptolib.ju.je/

答案 6 :(得分:-1)

function ($min,$max){
    $range = $max-$min+1;
    do{
        $result = floor($range*(hexdec(bin2hex(openssl_random_pseudo_bytes(4)))/0xffffffff));
    } while($result == $range);    
    return $result + $min;
}