openssl_random_pseudo_bytes

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

openssl_random_pseudo_bytes生成伪随机字节字符串

说明

openssl_random_pseudo_bytes(int $length, bool &$strong_result = null): string

生成一个 string 的伪随机字节,字节数由 length 参数决定。

它还指示是否使用密码学强算法来生成伪随机字节,并通过可选的 strong_result 参数来实现。 这种情况很少出现 false,但某些系统可能已损坏或过时。

参数

length

所需的字节字符串的长度。 必须是小于或等于 2147483647 的正整数。 PHP 将尝试将此参数转换为非空整数以使用它。

strong_result

如果传递给函数,它将保存一个 bool 值,该值确定使用的算法是否为“密码学强”,例如,适合用于 GPG、密码等。 如果是,则为 true,否则为 false

返回值

返回生成的 string 字节。

错误/异常

openssl_random_pseudo_bytes() 在失败时抛出一个 Exception

变更日志

版本 说明
8.0.0 strong_result 现在可以为空。
7.4.0 该函数不再在失败时返回 false,而是抛出一个 Exception

示例

示例 #1 openssl_random_pseudo_bytes() 示例

<?php
for ($i = 1; $i <= 4; $i++) {
$bytes = openssl_random_pseudo_bytes($i, $cstrong);
$hex = bin2hex($bytes);

echo
"Lengths: Bytes: $i and Hex: " . strlen($hex) . PHP_EOL;
var_dump($hex);
var_dump($cstrong);
echo
PHP_EOL;
}
?>

上面的示例将输出类似于以下内容

Lengths: Bytes: 1 and Hex: 2
string(2) "42"
bool(true)

Lengths: Bytes: 2 and Hex: 4
string(4) "dc6e"
bool(true)

Lengths: Bytes: 3 and Hex: 6
string(6) "288591"
bool(true)

Lengths: Bytes: 4 and Hex: 8
string(8) "ab86d144"
bool(true)

参见

添加笔记

用户贡献的笔记 11 notes

nahun@telemako
10 年前
以下是一个示例,用于将随机数的分布显示为图像。 原始的 rand 和 mt_rand 比较归功于 mt_rand 页面上的 Hayley Watson。

rand 为红色,mt_rand 为绿色,openssl_random_pseudo_bytes 为蓝色。

注意:这只是数据的分布的基本表示。 与算法的强度或可靠性无关。

<?php
header
("Content-type: image/png");
$sizex=800;
$sizey=800;

$img = imagecreatetruecolor(3 * $sizex,$sizey);
$r = imagecolorallocate($img,255, 0, 0);
$g = imagecolorallocate($img,0, 255, 0);
$b = imagecolorallocate($img,0, 0, 255);
imagefilledrectangle($img, 0, 0, 3 * $sizex, $sizey, imagecolorallocate($img, 255, 255, 255));

$p = 0;
for(
$i=0; $i < 100000; $i++) {
$np = rand(0,$sizex);
imagesetpixel($img, $p, $np, $r);
$p = $np;
}

$p = 0;
for(
$i=0; $i < 100000; $i++) {
$np = mt_rand(0,$sizex);
imagesetpixel($img, $p + $sizex, $np, $g);
$p = $np;
}

$p = 0;
for(
$i=0; $i < 100000; $i++) {
$np = floor($sizex*(hexdec(bin2hex(openssl_random_pseudo_bytes(4)))/0xffffffff));
imagesetpixel($img, $p + (2*$sizex), $np, $b);
$p = $np;
}

imagepng($img);
imagedestroy($img);
?>
powtac at gmx dot de
8 年前
[编辑注:此错误已在 PHP 5.4.44、5.5.28 和 PHP 5.6.12 中修复]

在 PHP 5.6 之前,openssl_random_pseudo_bytes() 并没有使用“密码学强算法”!
请参阅错误报告 https://bugs.php.net/bug.php?id=70014 以及相应的源代码 https://github.com/php/php-src/blob/php-5.6.10/ext/openssl/openssl.c#L5408
christophe dot weis at statec dot etat dot lu
13 年前
使用 OpenSSL 替换 rand() 的另一种方法。

请注意,使用模运算符 (%) 对结果进行截断的解决方案不是密码学安全的,因为生成的数字分布不均,即某些数字出现的频率可能高于其他数字。

比使用模运算符更好的解决方案是,如果结果过大,则丢弃结果并生成新的结果。

<?php
function crypto_rand_secure($min, $max) {
$range = $max - $min;
if (
$range == 0) return $min; // 不是那么随机...
$log = log($range, 2);
$bytes = (int) ($log / 8) + 1; // 以字节为单位的长度
$bits = (int) $log + 1; // 以位为单位的长度
$filter = (int) (1 << $bits) - 1; // 将所有低位设置为 1
do {
$rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes, $s)));
$rnd = $rnd & $filter; // 丢弃无关的位
} while ($rnd >= $range);
return
$min + $rnd;
}
?>
mailjeffclayton [at] gmail
4 年前
从给定范围内获取整数,并确保均匀分布

我创建了这个函数来解决模运算结果导致范围结果重叠的问题(这会导致不均匀分布)。

对于不熟悉这个问题的人,我的意思如下

使用字节作为 256 进制(16 进制)的基数,并试图在例如 10-20(跨度为 11)的范围内找到一个值,无法被整除,因此值(使用模运算)会重叠,导致某些数字的优先级高于其他数字。

我并没有根据字节值进行计算,而是使用字节值作为键进行排序。这种方法非常快,而且不需要进行大型数据空间的乘法运算,这些运算很容易超过 Max Int 的值。

此外:为了使用户提供的参数不关心顺序,我使用了一个方便的交换函数,我在野外发现了这个函数,并将其与下面的函数一起使用。

// 交换函数

function swap(&$a,&$b) { list($a,$b)=array($b,$a); } // 交换 2 个变量 - 不需要临时变量!

// 函数用于在给定的整数范围内获取随机值

function get_secure_random_ranged_value($max=99, $min=0) // 处理 1 或 2 个参数,顺序无关紧要
{
$sortarray = array();
$lo = (int)$min;
$hi = (int)$max;
if ($lo > $hi) swap($lo,$hi);
$data_range = abs($hi - $lo) + 1; // +1 包括范围内的最低“零”值和最高值
$bytes_per_key = 4; // 最大值:ffff 十六进制 = 4,294,967,296 十进制(超过 40 亿) - 大范围的随机值覆盖了海量数据集
$num_bytes = $data_range * $bytes_per_key;
$byte_string = (bin2hex(openssl_random_pseudo_bytes($num_bytes))); // 只需调用一次即可获取字节字符串
$byte_blocksize = $bytes_per_key << 1; // 将字节大小乘以 2,因为一个字节是 2 个字符宽

while ($key = substr($byte_string,0,$byte_blocksize)) { // 从字符串中获取下一个字节块
$byte_string = substr($byte_string,$byte_blocksize); // 从字符串中移除选定的字节块
$sortarray[]=$key; // 将键临时作为数组值填充到数组中
}

$sortarray = array_flip($sortarray); // 交换,使用字节值作为键
ksort($sortarray); // 根据键随机化
return array_shift($sortarray) + $lo; // 从数组中获取顶部的值并将其添加到范围内的最低值
}

//
// 示例:从 0 到 21 获取值
//

for ($i=1;$i<=10;$i++) { $rnd = get_secure_random_ranged_value(21); echo "-> result: ".($rnd)." <br />\n"; }

//
// 示例:从 14 到 21 获取值
//

for ($i=1;$i<=10;$i++) { $rnd = get_secure_random_ranged_value(14,21); echo "-> result: ".($rnd)." <br />\n"; }

//
// 14-21 的示例结果
//

-> result: 14
-> result: 18
-> result: 20
-> result: 15
-> result: 20
-> result: 16
-> result: 21
-> result: 15
-> result: 16
-> result: 17
acatalept at gmail
13 年前
仅供参考,openssl_random_pseudo_bytes() 在 Windows 下可能非常慢,以至于无法使用。在我的几台 Windows 机器上,它经常超时(执行时间超过 30 秒)。

显然,这是 OpenSSL 的一个已知问题(并非 PHP 独有)。

请参阅:http://www.google.com/search?q=openssl_random_pseudo_bytes+slow
Tyler Larson
14 年前
如果你没有这个函数,但安装了 OpenSSL,你总是可以伪造它

<?php
function openssl_random_pseudo_bytes($length) {
$length_n = (int) $length; // shell 注入不好玩
$handle = popen("/usr/bin/openssl rand $length_n", "r");
$data = stream_get_contents($handle);
pclose($handle);
return
$data;
}
?>
crrodriguez at opensuse dot org
13 年前
请至少请求 8 字节的熵,理想情况下是 32 或 64 字节,以避免可能的理论暴力破解攻击。
匿名
12 年前
另一种获取随机 32 位整数的方法
function myRand($max){
do{
$result = floor($max*(hexdec(bin2hex(openssl_random_pseudo_bytes(4)))/0xffffffff));
}while($result == $max);
return $result;
}
umairkhi at hotmail dot com
6 年前
在修复了这里不安全的数字生成问题后

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-8867

此函数以及此处的文本需要更新。我相信此函数在 FIPS 兼容应用程序中是安全的,因为它现在使用 RAND_bytes 而不是不安全的 RAND_pseudo_bytes()。
atesin () gmail ! com
6 年前
如果不可用,请使用核心函数... 可能不那么安全和优化(任何帮助?),但实用

<?php

$bytes
= '';
while (
strlen($bytes) < $lenght)
$bytes .= chr(mt_rand(0, 255));

?>
Karsey
6 年前
为什么 bin2hex 返回的字符数量是字节的两倍?
To Top