前に言ったように、私の rand 関数は phpseclib の crypt_random 関数の修正版です。私の最初の投稿で与えられたリンクでそれを見ることができました。少なくとも phpseclib 暗号化ライブラリの作成者はそれを確認しました。通常のアプリでは不十分ですか?私は極端な/理論的なセキュリティについて話すのではなく、実際に必要な程度の実用的なセキュリティについて話します.同時に、Web上のほとんどすべての通常のアプリケーションで「簡単に」/「十分に低コストで」利用できます.
phpseclib の crypt_random は、最悪の場合 (openssl_random_pseudo_bytes または urandom が利用できない) には効果的かつ静かに mt_rand (これは本当に弱いことを知っておく必要があります) にフォールバックしますが、私の関数はそのような場合にはるかに安全なスキームを使用します。これは、ブルート フォーシング/その出力の予測がはるかに困難であり、実際にはすべての通常のアプリ/サイトで十分であるというスキームへのフォールバックにすぎません。時間の経過とともに収集される可能性のある(実際には非常に可能性が高く、予測/回避が難しい)余分なエントロピーを使用しますが、これは部外者にとってすぐに知ることがほとんど不可能になります。この可能なエントロピーを mt_rand の出力 (および他のソースの出力: urandom、openssl_random_pseudo_bytes、mcrypt_create_iv) に追加します。知っておくべきことが通知された場合、このエントロピーは加算できますが、減算することはできません。(ほぼ確実に非常にまれな)最悪の場合、その余分なエントロピーは0または非常に小さい量になります。ほとんどすべてのケースであると私が思う平凡なケースでは、それは実際には必要以上のものになると思います。(私は膨大な暗号学の研究を行ってきたので、私が考えると言うとき、それは通常のプログラマーよりもはるかに情報に基づいた科学的分析に基づいています)。
変更した crypt_random の完全なコードを参照してください。
function crypt_random($min = 0, $max = 0x7FFFFFFF)
{
if ($min == $max) {
return $min;
}
global $entropy;
if (function_exists('openssl_random_pseudo_bytes')) {
// openssl_random_pseudo_bytes() is slow on windows per the following:
// http://stackoverflow.com/questions/1940168/openssl-random-pseudo-bytes-is-slow-php
if ((PHP_OS & "\xDF\xDF\xDF") !== 'WIN') { // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
extract(unpack('Nrandom', pack('H*', sha1(openssl_random_pseudo_bytes(4).$entropy.microtime()))));
return abs($random) % ($max - $min) + $min;
}
}
// see http://en.wikipedia.org/wiki//dev/random
static $urandom = true;
if ($urandom === true) {
// Warning's will be output unles the error suppression operator is used. Errors such as
// "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
$urandom = @fopen('/dev/urandom', 'rb');
}
if (!is_bool($urandom)) {
extract(unpack('Nrandom', pack('H*', sha1(fread($urandom, 4).$entropy.microtime()))));
// say $min = 0 and $max = 3. if we didn't do abs() then we could have stuff like this:
// -4 % 3 + 0 = -1, even though -1 < $min
return abs($random) % ($max - $min) + $min;
}
if(function_exists('mcrypt_create_iv') and version_compare(PHP_VERSION, '5.3.0', '>=')) {
@$tmp16=mcrypt_create_iv(4, MCRYPT_DEV_URANDOM);
if($tmp16!==false) {
extract(unpack('Nrandom', pack('H*', sha1($tmp16.$entropy.microtime()))));
return abs($random) % ($max - $min) + $min;
}
}
/* Prior to PHP 4.2.0, mt_srand() had to be called before mt_rand() could be called.
Prior to PHP 5.2.6, mt_rand()'s automatic seeding was subpar, as elaborated here:
http://www.suspekt.org/2008/08/17/mt_srand-and-not-so-random-numbers/
The seeding routine is pretty much ripped from PHP's own internal GENERATE_SEED() macro:
http://svn.php.net/viewvc/php/php-src/tags/php_5_3_2/ext/standard/php_rand.h?view=markup */
static $seeded;
if (!isset($seeded) and version_compare(PHP_VERSION, '5.2.5', '<=')) {
$seeded = true;
mt_srand(fmod(time() * getmypid(), 0x7FFFFFFF) ^ fmod(1000000 * lcg_value(), 0x7FFFFFFF));
}
extract(unpack('Nrandom', pack('H*', sha1(mt_rand(0, 0x7FFFFFFF).$entropy.microtime()))));
return abs($random) % ($max - $min) + $min;
}
$entropy には、これまでに結合されたすべてのリクエスト パラメータのエントロピー + 現在のリクエストのパラメータ エントロピー + インストール時に手動で設定されたランダムな文字列 (*) のエントロピーから得られる余分なエントロピーが含まれます。
*: 長さ: 22、小文字と大文字 + 数字で構成 (128 ビット以上のエントロピー)