WordPress.org

Make WordPress Core

Ticket #28633: 28633.8.diff

File 28633.8.diff, 6.1 KB (added by dd32, 5 years ago)
  • src/wp-includes/pluggable.php

     
    20052005        for ( $i = 0; $i < $length; $i++ ) {
    20062006                $password .= substr($chars, wp_rand(0, strlen($chars) - 1), 1);
    20072007        }
    20082008
    20092009        /**
    20102010         * Filter the randomly-generated password.
    20112011         *
    20122012         * @since 3.0.0
    20132013         *
    20142014         * @param string $password The generated password.
    20152015         */
    20162016        return apply_filters( 'random_password', $password );
    20172017}
    20182018endif;
    20192019
     2020/**
     2021 * Generate a cryptographically secure random string
     2022 * @ref http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/
     2023 *
     2024 * @param int $bytes Number of random bytes.
     2025 * @return string A string of random charcters of $bytes length.
     2026 */
     2027function wp_random_bytes( $bytes = 32 ) {
     2028
     2029        // Uses system native Crypto API in most OS's
     2030        // Uses native Windows Crypto API in PHP 5.3+ (MCRYPT_DEV_URANDOM)
     2031        // Prior to 5.3.7 this may also fatal on Windows - https://bugs.php.net/bug.php?id=55169
     2032        $use_mcrypt = function_exists('mcrypt_create_iv');
     2033        $use_mcrypt = $use_mcrypt && ! ( 'WIN' == substr( PHP_OS, 0, 3 ) && version_compare( phpversion(), '5.3.7', '<') );
     2034        if ( $use_mcrypt ) {
     2035                $buf = mcrypt_create_iv( $bytes, MCRYPT_DEV_URANDOM );
     2036                if ( $buf !== false ) {
     2037                        return $buf;
     2038                }
     2039        }
     2040
     2041        // Use /dev/urandom if available
     2042        // Will cause issues with open_basedir denying access
     2043        if ( @is_readable( '/dev/urandom' ) ) {
     2044                $fp = @fopen( '/dev/urandom', 'rb' );
     2045
     2046                // Use unbuffered reads if available in PHP 5.3.3+ to avoid read-ahead buffering eating entropy
     2047                if ( $fp && function_exists( 'stream_set_read_buffer' ) ) {
     2048                        if ( false === stream_set_read_buffer( $fp, 0 ) ) {
     2049                                // We'll skip using /dev/urandom if we can't use an unbuffered file
     2050                                fclose( $fp );
     2051                                unset( $fp );
     2052                        }
     2053                }
     2054
     2055                if ( $fp ) {
     2056                        $buf = '';
     2057
     2058                        mbstring_binary_safe_encoding();
     2059
     2060                        // How many bytes do we need?
     2061                        $bytes_remaining = $bytes;
     2062                        do {
     2063                                $buf .= $read = fread( $fp, $bytes_remaining );
     2064                                if ( $read === false ) {
     2065                                        // We cannot safely read from /dev/urandom.
     2066                                        $buf = false;
     2067                                        break;
     2068                                }
     2069                                $bytes_remaining -= strlen( $read );
     2070                        } while( $bytes_remaining > 0 );
     2071
     2072                        reset_mbstring_encoding();
     2073
     2074                        fclose( $fp );
     2075
     2076                        if ( $buf ) {
     2077                                return $buf;
     2078                        }
     2079                }
     2080        }
     2081
     2082        // Available since PHP 5.3.0
     2083        // Uses native Windows Cyrpto API's in PHP 5.4+
     2084        // can be exceedingly slow before PHP 5.3.4 on windows - https://bugs.php.net/bug.php?id=51636
     2085        $use_openssl = function_exists('openssl_random_pseudo_bytes');
     2086        $use_openssl = $use_openssl && ! ( 'WIN' == substr( PHP_OS, 0, 3 ) && version_compare( phpversion(), '5.3.4', '<') );
     2087        if ( $use_openssl ) {
     2088                $buf = openssl_random_pseudo_bytes( $bytes );
     2089                if ( $buf !== false ) {
     2090                        return $buf;
     2091                }
     2092        }
     2093
     2094        // CAPICOM: Supported on 32bit Windows 2008 and older only (includes non-server Windows 7 & XP)
     2095        // Windows 2008 R2 and newer with .NET 1.0+ should use \DOTNET('mscorlib', 'System.Security.Cryptography.RNGCryptoServiceProvider') if available
     2096        // Lots of reports of the DOTNET route not working for many under windows throwing fatals / exceptions due to type mismatches
     2097
     2098        // UNTESTED, and deprecated in windows.
     2099        if ( false && class_exists( 'COM', false ) ) {
     2100                try {
     2101                        $execs = 0;
     2102                        $buf = '';
     2103                        $util = new COM( 'CAPICOM.Utilities.1' );
     2104                        if ( ! is_callable( $util, 'GetRandom' ) ) {
     2105                                throw new Exception( '$util->GetRandom not callable' );
     2106                        }
     2107
     2108                        /*
     2109                         * Let's not let it loop forever. If we run N times and fail to
     2110                         * get N bytes of entropy, then CAPICOM has failed us.
     2111                         */
     2112                        mbstring_binary_safe_encoding();
     2113                        while ( $execs++ < $bytes) {
     2114                                $buf .= base64_decode( $util->GetRandom( $bytes, 0 ) );
     2115                                if ( strlen( $buf ) >= $bytes ) {
     2116                                        reset_mbstring_encoding();
     2117                                        return substr( $buf, 0, $bytes );
     2118                                }
     2119                        }
     2120                        reset_mbstring_encoding();
     2121                } catch ( Exception $e ) {
     2122                        reset_mbstring_encoding();
     2123                }
     2124        }
     2125        if ( false && class_exists( 'DOTNET', false ) ) {
     2126                //DOTNET('mscorlib', 'System.Security.Cryptography.RNGCryptoServiceProvider')
     2127        }
     2128
     2129        // At this point, we're forced to fallback to a hash-based random source
     2130        $buf = '';
     2131        for ( $i = 0; $i < $bytes; ++$i ) {
     2132                $buf .= chr( wp_rand( 0, 255 ) );
     2133        }
     2134
     2135        return $buf;
     2136}
     2137
     2138/**
     2139 * Generate a random positive integer between 0 and PHP_INT_MAX.
     2140 *
     2141 * @return int A random positive integer.
     2142 */
     2143function wp_random_positive_int() {
     2144        $buf = wp_random_bytes( PHP_INT_SIZE );
     2145       
     2146        $val = 0;
     2147        $i = strlen( $buf );
     2148
     2149        // TODO: Test on a 32bit machine with PHP_INT_SIZE = 4
     2150        do {
     2151                $i--;
     2152                $val <<= 8;
     2153                $val |= ord( $buf[ $i ] );
     2154        } while( $i != 0 );
     2155
     2156        // effectively absint()
     2157        return $val & PHP_INT_MAX;
     2158}
     2159
     2160/**
     2161 * Generates an unbiased, unpredictably random number.
     2162 *
     2163 * @since x.x.x
     2164 *
     2165 * @param int $min Lower limit for the generated number.
     2166 * @param int $max Upper limit for the generated number.
     2167 * @return int A random number between min and max inclusively.
     2168 */
     2169function wp_secure_rand( $min = 0, $max = PHP_INT_MAX ) {
     2170        if ( $min == $max ) {
     2171                return $min;
     2172        }
     2173
     2174        // Calculate from 0..($max-$min), resulting in $min+$rand..$max
     2175        $max -= $min;
     2176
     2177        // 7776 -> 13
     2178        $bits = ceil( log( $max + 1 ) / log( 2 ) );
     2179
     2180        // 2^13 - 1 == 8191 or 0x00001111 11111111
     2181        // Calculate a mask of how much of the PHP int we're interested in
     2182        $mask = ceil( pow( 2, $bits ) ) - 1;
     2183
     2184        $val = 0;
     2185        do {
     2186                // Grab a random integer
     2187                $val = wp_random_positive_int();
     2188
     2189                // Apply the mask
     2190                $val &= $mask;
     2191
     2192                // Try again if this exceeds our upper limit.
     2193        } while ( $val > $max );
     2194
     2195        // $min..($min+$max)
     2196        return (int) ( $min + $val );
     2197}
     2198
     2199
    20202200if ( !function_exists('wp_rand') ) :
    20212201/**
    20222202 * Generates a random number
    20232203 *
    20242204 * @since 2.6.2
    20252205 *
    20262206 * @param int $min Lower limit for the generated number
    20272207 * @param int $max Upper limit for the generated number
    20282208 * @return int A random number between min and max
    20292209 */
    20302210function wp_rand( $min = 0, $max = 0 ) {
    20312211        global $rnd_value;
    20322212
    20332213        // Reset $rnd_value after 14 uses
    20342214        // 32(md5) + 40(sha1) + 40(sha1) / 8 = 14 random numbers from $rnd_value