69 $state = serialize( $_SERVER );
76 $state .= rand() . uniqid( mt_rand(),
true );
86 $files[] = dirname( __DIR__ );
93 if ( defined(
'MW_CONFIG_FILE' ) ) {
99 $stat = stat(
$file );
103 foreach ( $stat
as $k => $v ) {
104 if ( is_numeric( $k ) ) {
109 if ( (
$path = realpath(
$file ) ) !==
false ) {
114 $state .= implode(
'', $stat );
124 if ( function_exists(
'getmypid' ) ) {
125 $state .= getmypid();
130 if ( function_exists(
'memory_get_usage' ) ) {
131 $state .= memory_get_usage(
true );
138 global $wgSecretKey, $wgProxyKey;
139 if ( $wgSecretKey ) {
140 $state .= $wgSecretKey;
141 } elseif ( $wgProxyKey ) {
142 $state .= $wgProxyKey;
160 $duration = ( self::MSEC_PER_BYTE / 1000 ) * $this->
hashLength();
162 $bufLength = 10000000;
163 $buffer = str_repeat(
' ', $bufLength );
168 $startTime = microtime(
true );
169 $currentTime = $startTime;
170 while ( $iterations < $minIterations || $currentTime - $startTime < $duration ) {
173 $bufPos = ( $bufPos + 13 ) % $bufLength;
174 $buffer[$bufPos] =
' ';
176 $nextTime = microtime(
true );
177 $delta = (int)( ( $nextTime - $currentTime ) * 1000000 );
180 if ( $iterations % 100 === 0 ) {
181 $data = sha1( $data );
183 $currentTime = $nextTime;
186 $timeTaken = $currentTime - $startTime;
187 $data = $this->
hash( $data );
189 wfDebug( __METHOD__ .
": Clock drift calculation " .
190 "(time-taken=" . ( $timeTaken * 1000 ) .
"ms, " .
191 "iterations=$iterations, " .
192 "time-per-iteration=" . ( $timeTaken / $iterations * 1e6 ) .
"us)\n" );
202 static $state =
null;
203 if ( is_null( $state ) ) {
222 if ( !is_null( $this->algo ) ) {
226 $algos = hash_algos();
227 $preference =
array(
'whirlpool',
'sha256',
'sha1',
'md5' );
229 foreach ( $preference
as $algorithm ) {
230 if ( in_array( $algorithm, $algos ) ) {
231 $this->algo = $algorithm;
232 wfDebug( __METHOD__ .
": Using the {$this->algo} hash algorithm.\n" );
243 throw new MWException(
"Could not find an acceptable hashing function in hash_algos()" );
267 protected function hash( $data ) {
279 protected function hmac( $data, $key ) {
280 return hash_hmac( $this->
hashAlgo(), $data, $key,
true );
287 if ( is_null( $this->strong ) ) {
288 throw new MWException( __METHOD__ .
' called before generation of random data' );
300 wfDebug( __METHOD__ .
": Generating cryptographic random bytes for " .
303 $bytes = floor( $bytes );
305 if ( is_null( $this->strong ) ) {
307 $this->strong =
true;
310 if ( strlen( $buffer ) < $bytes ) {
317 if ( function_exists(
'mcrypt_create_iv' ) ) {
319 $rem = $bytes - strlen( $buffer );
320 $iv = mcrypt_create_iv( $rem, MCRYPT_DEV_URANDOM );
321 if ( $iv ===
false ) {
322 wfDebug( __METHOD__ .
": mcrypt_create_iv returned false.\n" );
325 wfDebug( __METHOD__ .
": mcrypt_create_iv generated " . strlen( $iv ) .
326 " bytes of randomness.\n" );
332 if ( strlen( $buffer ) < $bytes ) {
338 if ( function_exists(
'openssl_random_pseudo_bytes' )
339 && ( !
wfIsWindows() || version_compare( PHP_VERSION,
'5.3.4',
'>=' ) )
342 $rem = $bytes - strlen( $buffer );
343 $openssl_bytes = openssl_random_pseudo_bytes( $rem, $openssl_strong );
344 if ( $openssl_bytes ===
false ) {
345 wfDebug( __METHOD__ .
": openssl_random_pseudo_bytes returned false.\n" );
347 $buffer .= $openssl_bytes;
348 wfDebug( __METHOD__ .
": openssl_random_pseudo_bytes generated " .
349 strlen( $openssl_bytes ) .
" bytes of " .
350 ( $openssl_strong ?
"strong" :
"weak" ) .
" randomness.\n" );
352 if ( strlen( $buffer ) >= $bytes ) {
355 $this->strong = !!$openssl_strong;
362 if ( strlen( $buffer ) < $bytes &&
363 ( function_exists(
'stream_set_read_buffer' ) || $forceStrong )
366 $rem = $bytes - strlen( $buffer );
367 if ( !function_exists(
'stream_set_read_buffer' ) && $forceStrong ) {
368 wfDebug( __METHOD__ .
": Was forced to read from /dev/urandom " .
369 "without control over the buffer size.\n" );
374 $urandom = fopen(
"/dev/urandom",
"rb" );
385 $chunk_size = 1024 * 8;
386 if ( function_exists(
'stream_set_read_buffer' ) ) {
388 stream_set_read_buffer( $urandom, $rem );
391 $random_bytes = fread( $urandom, max( $chunk_size, $rem ) );
392 $buffer .= $random_bytes;
394 wfDebug( __METHOD__ .
": /dev/urandom generated " . strlen( $random_bytes ) .
395 " bytes of randomness.\n" );
397 if ( strlen( $buffer ) >= $bytes ) {
399 $this->strong =
true;
402 wfDebug( __METHOD__ .
": /dev/urandom could not be opened.\n" );
413 if ( strlen( $buffer ) < $bytes ) {
415 ": Falling back to using a pseudo random state to generate randomness.\n" );
417 while ( strlen( $buffer ) < $bytes ) {
422 $this->strong =
false;
429 $generated = substr( $buffer, 0, $bytes );
430 $buffer = substr( $buffer, $bytes );
432 wfDebug( __METHOD__ .
": " . strlen( $buffer ) .
433 " bytes of randomness leftover in the buffer.\n" );
447 $bytes = ceil( $chars / 2 );
449 $hex = bin2hex( $this->
generate( $bytes, $forceStrong ) );
458 return substr( $hex, 0, $chars );
468 if ( is_null( self::$singleton ) ) {
469 self::$singleton =
new self;
498 public static function generate( $bytes, $forceStrong =
false ) {
514 public static function generateHex( $chars, $forceStrong =
false ) {