/** * Makes sure that the PRNG has been seeded with a fairly secure value * * @static * @access private * @return void */ private static function seedRandom() { static $seeded = FALSE; if ($seeded) { return TRUE; } $bytes = NULL; // // On linux/unix/solaris we should be able to use /dev/urandom // if (!self::checkOS('windows') && ($handle = fopen('/dev/urandom', 'rb'))) { $bytes = fread($handle, 4); fclose($handle); // // On windows we should be able to use the Cryptographic Application Programming Interface COM object // } elseif (self::checkOS('windows') && class_exists('COM', FALSE)) { try { // This COM object no longer seems to work on PHP 5.2.9+, no response on the bug report yet $capi = new COM('CAPICOM.Utilities.1'); $bytes = base64_decode($capi->getrandom(4, 0)); unset($capi); } catch (Exception $e) { } } // // If we could not use the OS random number generators we get some of the most unique info we can // if (!$bytes) { $string = microtime(TRUE) . uniqid('', TRUE) . join('', stat(__FILE__)) . disk_free_space(dirname(__FILE__)); $bytes = substr(pack('H*', md5($string)), 0, 4); } $seed = (int) (base_convert(bin2hex($bytes), 16, 10) - 2147483647); mt_srand($seed); return $seeded = TRUE; }
/** * Makes sure that the PRNG has been seeded with a fairly secure value * * @return void */ private static function seedRandom() { static $seeded = FALSE; if ($seeded) { return; } $old_level = error_reporting(error_reporting() & ~E_WARNING); $bytes = NULL; // On linux/unix/solaris we should be able to use /dev/urandom if (!fCore::checkOS('windows') && ($handle = fopen('/dev/urandom', 'rb'))) { $bytes = fread($handle, 32); fclose($handle); // On windows we should be able to use the Cryptographic Application Programming Interface COM object } elseif (fCore::checkOS('windows') && class_exists('COM', FALSE)) { try { // This COM object no longer seems to work on PHP 5.2.9+, no response on the bug report yet $capi = new COM('CAPICOM.Utilities.1'); $bytes = base64_decode($capi->getrandom(32, 0)); unset($capi); } catch (Exception $e) { } } // If we could not use the OS random number generators we get some of the most unique info we can if (!$bytes) { $bytes = microtime(TRUE) . uniqid('', TRUE) . join('', stat(__FILE__)) . disk_free_space(__FILE__); } error_reporting($old_level); $seed = md5($bytes); $seed = base_convert($seed, 16, 10); $seed = (double) substr($seed, 0, 13) + (double) substr($seed, 14, 13); mt_srand($seed); $seeded = TRUE; }
/** * This method will generate strong random data for cryptographic use. * * @param int $length * @return binary */ public static function getRandomBytes($length) { $length = (int) $length; if ($length < 1) { throw new Exception('Length cannot be less than 1.'); } // Works on systems that have OpenSSL installed and OpenSSL extension loaded. if (function_exists('openssl_random_pseudo_bytes')) { $random = openssl_random_pseudo_bytes($length, $strong); if ($strong) { return (string) $random; } } // Only execute on unix based systems if (DIRECTORY_SEPARATOR === '/') { // Works on Sun Solaris, Unix and Linux systems. $fp = @fopen('/dev/urandom', 'rb'); if ($fp) { $random = fread($fp, $length); fclose($fp); return (string) $random; } } // Works on Windows x86. if (class_exists('COM')) { try { $csp = new COM('CAPICOM.Utilities.1'); // We are stripping because sometimes the method appends newlines? $random = substr((string) base64_decode($csp->getrandom($length, 0)), 0, $length); unset($csp); return (string) $random; } catch (Exception $e) { } } // PHP has a bug that prevents you from creating a byte array via variants. Thus, no CSP support for Windows x64. // If someone is able to circumvent this problem, please email me. // Could work on Windows x64. if (false) { if (class_exists('DOTNET')) { try { $csp = new DOTNET("mscorlib", "System.Security.Cryptography.RNGCryptoServiceProvider"); $array = array_fill(0, $length, null); $variant = new VARIANT($array, VT_ARRAY | VT_UI1); $csp->GetBytes($variant); unset($csp); return (string) implode('', $array); } catch (Exception $e) { } } } // This is random data from OpenSSL that was marked as "weak". It's better than mt_rand(). if (isset($random)) { return (string) $random; } // Falling back to PHP's mt_rand() and the rest if nothing worked. // This basically means we are either on a Windows x64 system without OpenSSL or on a really weird system. :| $random = ''; $backtrace = debug_backtrace(); $stat = stat($backtrace[0]['file']); // Using the name of the caller script. for ($a = 0; $a < $length; $a++) { // Since we can't use any good random generators, we need to use as many poor "random" sources as possible. $source = mt_rand(); // Weak pseudo random. $source += microtime(true); // Non-random and is poor in tight loops - yes, like this one. // $source += uniqid('', true); // The only real reason to use uniqid() here is due to its use of the internal LCG. $source += memory_get_usage(); // Has a weak avalance effect and is predictable. $source += getmypid(); // Non-random and doesn't change until the next request. $source += $stat[7] + substr($stat[8], -3, 3) + substr($stat[9], -3, 3) + substr($stat[10], -3, 3); // File stats. // Let's make it a byte. $random .= chr($source % 255); } return (string) $random; }