26 use Psr\Log\LoggerInterface;
84 $state .= rand() . uniqid( mt_rand(),
true );
94 $files[] = dirname( __DIR__ );
96 foreach ( $files
as $file ) {
97 MediaWiki\suppressWarnings();
98 $stat = stat( $file );
99 MediaWiki\restoreWarnings();
102 foreach ( $stat
as $k => $v ) {
103 if ( is_numeric( $k ) ) {
108 $path = realpath( $file );
109 if (
$path !==
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 );
134 foreach ( $this->randomFuncs
as $randomFunc ) {
135 $state .= call_user_func( $randomFunc );
155 $bufLength = 10000000;
156 $buffer = str_repeat(
' ', $bufLength );
161 $startTime = microtime(
true );
162 $currentTime = $startTime;
163 while ( $iterations < $minIterations || $currentTime - $startTime < $duration ) {
166 $bufPos = ( $bufPos + 13 ) % $bufLength;
169 $nextTime = microtime(
true );
170 $delta = (int)( ( $nextTime - $currentTime ) * 1000000 );
173 if ( $iterations % 100 === 0 ) {
174 $data = sha1( $data );
176 $currentTime = $nextTime;
179 $timeTaken = $currentTime - $startTime;
182 $this->logger->debug(
"Clock drift calculation " .
183 "(time-taken=" . ( $timeTaken * 1000 ) .
"ms, " .
184 "iterations=$iterations, " .
185 "time-per-iteration=" . ( $timeTaken / $iterations * 1e6 ) .
"us)" );
195 static $state =
null;
196 if ( is_null( $state ) ) {
217 if ( is_null( $this->strong ) ) {
218 throw new RuntimeException( __METHOD__ .
' called before generation of random data' );
236 public function generate( $bytes, $forceStrong =
false ) {
238 $bytes = floor( $bytes );
240 if ( is_null( $this->strong ) ) {
242 $this->strong =
true;
245 if ( strlen(
$buffer ) < $bytes ) {
252 if ( PHP_VERSION_ID >= 70000
253 || ( defined(
'HHVM_VERSION_ID' ) && HHVM_VERSION_ID >= 31101 )
255 $rem = $bytes - strlen(
$buffer );
256 $buffer .= random_bytes( $rem );
258 if ( strlen(
$buffer ) >= $bytes ) {
259 $this->strong =
true;
263 if ( strlen(
$buffer ) < $bytes ) {
270 if ( function_exists(
'mcrypt_create_iv' ) ) {
271 $rem = $bytes - strlen(
$buffer );
272 $iv = mcrypt_create_iv( $rem, MCRYPT_DEV_URANDOM );
273 if ( $iv ===
false ) {
274 $this->logger->debug(
"mcrypt_create_iv returned false." );
277 $this->logger->debug(
"mcrypt_create_iv generated " . strlen( $iv ) .
278 " bytes of randomness." );
283 if ( strlen(
$buffer ) < $bytes ) {
284 if ( function_exists(
'openssl_random_pseudo_bytes' ) ) {
285 $rem = $bytes - strlen(
$buffer );
286 $openssl_bytes = openssl_random_pseudo_bytes( $rem, $openssl_strong );
287 if ( $openssl_bytes ===
false ) {
288 $this->logger->debug(
"openssl_random_pseudo_bytes returned false." );
291 $this->logger->debug(
"openssl_random_pseudo_bytes generated " .
292 strlen( $openssl_bytes ) .
" bytes of " .
293 ( $openssl_strong ?
"strong" :
"weak" ) .
" randomness." );
295 if ( strlen(
$buffer ) >= $bytes ) {
298 $this->strong = !!$openssl_strong;
304 if ( strlen(
$buffer ) < $bytes &&
305 ( function_exists(
'stream_set_read_buffer' ) || $forceStrong )
307 $rem = $bytes - strlen(
$buffer );
308 if ( !function_exists(
'stream_set_read_buffer' ) && $forceStrong ) {
309 $this->logger->debug(
"Was forced to read from /dev/urandom " .
310 "without control over the buffer size." );
314 MediaWiki\suppressWarnings();
315 $urandom = fopen(
"/dev/urandom",
"rb" );
316 MediaWiki\restoreWarnings();
326 $chunk_size = 1024 * 8;
327 if ( function_exists(
'stream_set_read_buffer' ) ) {
329 stream_set_read_buffer( $urandom, $rem );
332 $random_bytes = fread( $urandom, max( $chunk_size, $rem ) );
335 $this->logger->debug(
"/dev/urandom generated " . strlen( $random_bytes ) .
336 " bytes of randomness." );
338 if ( strlen(
$buffer ) >= $bytes ) {
340 $this->strong =
true;
343 $this->logger->debug(
"/dev/urandom could not be opened." );
353 if ( strlen(
$buffer ) < $bytes ) {
354 $this->logger->debug( __METHOD__ .
355 ": Falling back to using a pseudo random state to generate randomness." );
357 while ( strlen(
$buffer ) < $bytes ) {
361 $this->strong =
false;
367 $generated = substr(
$buffer, 0, $bytes );
370 $this->logger->debug( strlen(
$buffer ) .
371 " bytes of randomness leftover in the buffer." );
392 $bytes = ceil( $chars / 2 );
394 $hex = bin2hex( $this->
generate( $bytes, $forceStrong ) );
403 return substr( $hex, 0, $chars );