【发布时间】:2011-11-05 12:31:52
【问题描述】:
我想生成一个随机字节序列以在安全敏感的上下文中使用。我正在寻找一种独立于操作系统的方式,所以我无法访问 /dev/(u)random。此外, openssl_random_pseudo_bytes() 可能不可用,所以让我们也忘记它。我也不对任何情况下的性能差异感兴趣。
查看 phpass 库(被许多人使用并且被认为足够安全)以生成随机序列,如果 /dev/urandom 不可用,它会回退到以下算法:
// Init:
$this->random_state = microtime();
if (function_exists('getmypid'))
$this->random_state .= getmypid();
// Generate
$count = ...number of bytes to generate
$output = '';
for ($i = 0; $i < $count; $i += 16) {
$this->random_state =
md5(microtime() . $this->random_state);
$output .=
pack('H*', md5($this->random_state));
}
$output = substr($output, 0, $count);
// $output ready
上述算法基本上是依赖getmypid()、md5()和microtime()来生成随机序列。许多人已经指出,时间/微时间和 pid 是安全应用程序的不良熵源,因此即使您使用 md5 和一些字符串操作转换它们,输出也不会是“安全随机”的。所以我们知道,上面的算法充其量只能和 pid 和 microtime 作为熵源一样好。
相比之下,这里有另一种算法。鉴于 rand 是由 PHP 自动播种的,它(可能)并不比以前的算法在安全方面更好,因为 rand/mt_rand 默认情况下也使用计算机时间和 pid 播种(ref)。但既然它不那么复杂,那不是更好的选择吗?我也可以改写这个问题:鉴于上面和下面的算法都依赖于 pid 和计算机时间来生成随机数,那么上面的算法是否仍然更好,为什么?
function RandomBytes($len)
{
// Seed
$seed = (double)microtime()*1000003;
if (function_exists('getmypid'))
$seed += getmypid();
mt_srand($seed);
$output = '';
for ($i = 0; $i < $len; ++$i)
$output .= chr(mt_rand(0, 255));
// optionally transform using pack('H*', ...) to make output printable
return $output;
}
最后一个问题,您知道在 PHP 中以独立于操作系统的方式生成随机字节的更好(=更随机)方式吗?
【问题讨论】:
-
在 PHP 中没有可移植且始终可用的方法来生成加密强的随机字节序列。你需要一个特定的环境或可用的工具,你的先决条件排除了这些。 -- phpass 仅使用 rand 或哈希解决方法的原因是它仅将其用作密码盐,这不依赖于高熵。
-
我明白,如果没有操作系统支持,我将无法生成加密安全的随机序列。但是我展示的第二个算法与第一个算法相比如何,(为什么)其中一个比另一个更好?
-
mt_rand 和 rand 已经播种,您实际上是通过减少种子的熵来降低这些函数的安全性。
-
第一个算法似乎也有类似的种子。如果我删除了 RandomBytes() 中的种子部分,会有什么变化吗?