Ejemplo n.º 1
0
 public static function getBinary($length = 32)
 {
     if ($length < 1) {
         return '';
     }
     // There's not much point reading more than 256 bits of entropy from any single source.
     $capped_length = min($length, 32);
     // As usual, Windows requires special consideration.
     $is_windows = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
     // Variables to store state during entropy collection.
     $entropy = array();
     $sources = array();
     $total_strength = 0;
     $required_strength = 5;
     // Try getting entropy from various sources that are known to be good.
     if (function_exists('openssl_random_pseudo_bytes') && (!$is_windows || version_compare(PHP_VERSION, '5.4', '>='))) {
         $entropy[] = openssl_random_pseudo_bytes($capped_length, $crypto_strong);
         $sources[] = 'openssl';
         $total_strength += $crypto_strong ? 3 : 1;
     } elseif (function_exists('mcrypt_create_iv') && (!$is_windows || version_compare(PHP_VERSION, '5.3.7', '>='))) {
         $entropy[] = mcrypt_create_iv($capped_length, MCRYPT_DEV_URANDOM);
         $sources[] = 'mcrypt_dev_urandom';
         $total_strength += 4;
     } elseif ($is_windows && function_exists('mcrypt_create_iv') && defined('MCRYPT_RAND')) {
         $entropy[] = mcrypt_create_iv($capped_length, MCRYPT_RAND);
         $sources[] = 'mcrypt_rand';
         $total_strength += 2;
     } elseif (!$is_windows && file_exists('/dev/urandom') && is_readable('/dev/urandom')) {
         $entropy[] = fread($fp = fopen('/dev/urandom', 'rb'), $capped_length);
         fclose($fp);
         $sources[] = 'dev_urandom';
         $total_strength += 4;
     }
     // Supplement with multiple calls to rand() and mt_rand().
     while ($total_strength < $required_strength) {
         $rand = '';
         for ($i = 0; $i < $capped_length; $i += 4) {
             $rand .= pack('L', rand(0, 0x7fffffff) ^ mt_rand(0, 0x7fffffff));
         }
         $entropy[] = $rand;
         $sources[] = 'mt_rand';
         $total_strength += 1;
     }
     // Mix the entropy sources together using SHA-512.
     $mixer_content = end($entropy);
     $mixer_output = '';
     if (function_exists('hash_hmac') && in_array('sha256', hash_algos())) {
         for ($i = 0; $i < $length; $i += 32) {
             foreach ($entropy as $item) {
                 $mixer_content = hash_hmac('sha256', $item, $mixer_content . $i, true);
             }
             $mixer_output .= $mixer_content;
         }
     } else {
         for ($i = 0; $i < $length; $i += 20) {
             foreach ($entropy as $item) {
                 $mixer_content = sha1($item . $mixer_content . $i . microtime(), true);
             }
             $mixer_output .= $mixer_content;
         }
     }
     self::$_sources = $sources;
     return substr($mixer_output, 0, $length);
 }