Bump PHP version requirement to 7.0.0+
[lhc/web/wiklou.git] / includes / libs / CryptRand.php
index 6d18c81..474c564 100644 (file)
@@ -94,9 +94,9 @@ class CryptRand {
                $files[] = dirname( __DIR__ );
 
                foreach ( $files as $file ) {
-                       MediaWiki\suppressWarnings();
+                       Wikimedia\suppressWarnings();
                        $stat = stat( $file );
-                       MediaWiki\restoreWarnings();
+                       Wikimedia\restoreWarnings();
                        if ( $stat ) {
                                // stat() duplicates data into numeric and string keys so kill off all the numeric ones
                                foreach ( $stat as $k => $v ) {
@@ -182,7 +182,7 @@ class CryptRand {
                $this->logger->debug( "Clock drift calculation " .
                        "(time-taken=" . ( $timeTaken * 1000 ) . "ms, " .
                        "iterations=$iterations, " .
-                       "time-per-iteration=" . ( $timeTaken / $iterations * 1e6 ) . "us)\n" );
+                       "time-per-iteration=" . ( $timeTaken / $iterations * 1e6 ) . "us)" );
 
                return $data;
        }
@@ -234,9 +234,6 @@ class CryptRand {
         * @return string Raw binary random data
         */
        public function generate( $bytes, $forceStrong = false ) {
-
-               $this->logger->debug( "Generating cryptographic random bytes for\n" );
-
                $bytes = floor( $bytes );
                static $buffer = '';
                if ( is_null( $this->strong ) ) {
@@ -244,6 +241,24 @@ class CryptRand {
                        $this->strong = true;
                }
 
+               if ( strlen( $buffer ) < $bytes ) {
+                       // If available make use of PHP 7's random_bytes
+                       // On Linux, getrandom syscall will be used if available.
+                       // On Windows CryptGenRandom will always be used
+                       // On other platforms, /dev/urandom will be used.
+                       // Avoids polyfills from before php 7.0
+                       // All error situations will throw Exceptions and or Errors
+                       if ( PHP_VERSION_ID >= 70000
+                               || ( defined( 'HHVM_VERSION_ID' ) && HHVM_VERSION_ID >= 31101 )
+                       ) {
+                               $rem = $bytes - strlen( $buffer );
+                               $buffer .= random_bytes( $rem );
+                       }
+                       if ( strlen( $buffer ) >= $bytes ) {
+                               $this->strong = true;
+                       }
+               }
+
                if ( strlen( $buffer ) < $bytes ) {
                        // If available make use of mcrypt_create_iv URANDOM source to generate randomness
                        // On unix-like systems this reads from /dev/urandom but does it without any buffering
@@ -255,11 +270,11 @@ class CryptRand {
                                $rem = $bytes - strlen( $buffer );
                                $iv = mcrypt_create_iv( $rem, MCRYPT_DEV_URANDOM );
                                if ( $iv === false ) {
-                                       $this->logger->debug( "mcrypt_create_iv returned false.\n" );
+                                       $this->logger->debug( "mcrypt_create_iv returned false." );
                                } else {
                                        $buffer .= $iv;
                                        $this->logger->debug( "mcrypt_create_iv generated " . strlen( $iv ) .
-                                               " bytes of randomness.\n" );
+                                               " bytes of randomness." );
                                }
                        }
                }
@@ -269,12 +284,12 @@ class CryptRand {
                                $rem = $bytes - strlen( $buffer );
                                $openssl_bytes = openssl_random_pseudo_bytes( $rem, $openssl_strong );
                                if ( $openssl_bytes === false ) {
-                                       $this->logger->debug( "openssl_random_pseudo_bytes returned false.\n" );
+                                       $this->logger->debug( "openssl_random_pseudo_bytes returned false." );
                                } else {
                                        $buffer .= $openssl_bytes;
                                        $this->logger->debug( "openssl_random_pseudo_bytes generated " .
                                                strlen( $openssl_bytes ) . " bytes of " .
-                                               ( $openssl_strong ? "strong" : "weak" ) . " randomness.\n" );
+                                               ( $openssl_strong ? "strong" : "weak" ) . " randomness." );
                                }
                                if ( strlen( $buffer ) >= $bytes ) {
                                        // openssl tells us if the random source was strong, if some of our data was generated
@@ -291,13 +306,13 @@ class CryptRand {
                        $rem = $bytes - strlen( $buffer );
                        if ( !function_exists( 'stream_set_read_buffer' ) && $forceStrong ) {
                                $this->logger->debug( "Was forced to read from /dev/urandom " .
-                                       "without control over the buffer size.\n" );
+                                       "without control over the buffer size." );
                        }
                        // /dev/urandom is generally considered the best possible commonly
                        // available random source, and is available on most *nix systems.
-                       MediaWiki\suppressWarnings();
+                       Wikimedia\suppressWarnings();
                        $urandom = fopen( "/dev/urandom", "rb" );
-                       MediaWiki\restoreWarnings();
+                       Wikimedia\restoreWarnings();
 
                        // Attempt to read all our random data from urandom
                        // php's fread always does buffered reads based on the stream's chunk_size
@@ -317,14 +332,14 @@ class CryptRand {
                                $buffer .= $random_bytes;
                                fclose( $urandom );
                                $this->logger->debug( "/dev/urandom generated " . strlen( $random_bytes ) .
-                                       " bytes of randomness.\n" );
+                                       " bytes of randomness." );
 
                                if ( strlen( $buffer ) >= $bytes ) {
                                        // urandom is always strong, set to true if all our data was generated using it
                                        $this->strong = true;
                                }
                        } else {
-                               $this->logger->debug( "/dev/urandom could not be opened.\n" );
+                               $this->logger->debug( "/dev/urandom could not be opened." );
                        }
                }
 
@@ -336,7 +351,7 @@ class CryptRand {
                // out and being used to predict the /randomness/ that follows.
                if ( strlen( $buffer ) < $bytes ) {
                        $this->logger->debug( __METHOD__ .
-                               ": Falling back to using a pseudo random state to generate randomness.\n" );
+                               ": Falling back to using a pseudo random state to generate randomness." );
                }
                while ( strlen( $buffer ) < $bytes ) {
                        $buffer .= MWCryptHash::hmac( $this->randomState(), strval( mt_rand() ) );
@@ -352,7 +367,7 @@ class CryptRand {
                $buffer = substr( $buffer, $bytes );
 
                $this->logger->debug( strlen( $buffer ) .
-                       " bytes of randomness leftover in the buffer.\n" );
+                       " bytes of randomness leftover in the buffer." );
 
                return $generated;
        }