WordPress.org

Make WordPress Core

Ticket #28633: 28633.9.diff

File 28633.9.diff, 5.8 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 * @since x.x.x
     2025 * @internal
     2026 *
     2027 * @param int $bytes Number of random bytes.
     2028 * @return string|WP_Error A string of random charcters of $bytes length, WP_Error if external random sources unavailable
     2029 */
     2030function wp_external_random_bytes( $bytes = 32 ) {
     2031
     2032        // Uses system native Crypto API in most OS's
     2033        // Uses native Windows Crypto API in PHP 5.3+ (MCRYPT_DEV_URANDOM)
     2034        // Prior to 5.3.7 this may also fatal on Windows - https://bugs.php.net/bug.php?id=55169
     2035        $use_mcrypt = function_exists('mcrypt_create_iv');
     2036        $use_mcrypt = $use_mcrypt && ! ( 'WIN' == substr( PHP_OS, 0, 3 ) && version_compare( phpversion(), '5.3.7', '<') );
     2037        if ( $use_mcrypt ) {
     2038                $buf = mcrypt_create_iv( $bytes, MCRYPT_DEV_URANDOM );
     2039                if ( $buf !== false ) {
     2040                        return $buf;
     2041                }
     2042        }
     2043
     2044        // Use /dev/urandom if available
     2045        // Will cause issues with open_basedir denying access
     2046        if ( @is_readable( '/dev/urandom' ) ) {
     2047                $fp = @fopen( '/dev/urandom', 'rb' );
     2048
     2049                // Use unbuffered reads if available in PHP 5.3.3+ to avoid read-ahead buffering eating entropy
     2050                if ( $fp && function_exists( 'stream_set_read_buffer' ) ) {
     2051                        if ( false === stream_set_read_buffer( $fp, 0 ) ) {
     2052                                // We'll skip using /dev/urandom if we can't use an unbuffered file
     2053                                fclose( $fp );
     2054                                unset( $fp );
     2055                        }
     2056                }
     2057
     2058                if ( $fp ) {
     2059                        $buf = '';
     2060
     2061                        mbstring_binary_safe_encoding();
     2062
     2063                        // How many bytes do we need?
     2064                        $bytes_remaining = $bytes;
     2065                        do {
     2066                                $buf .= $read = fread( $fp, $bytes_remaining );
     2067                                if ( $read === false ) {
     2068                                        // We cannot safely read from /dev/urandom.
     2069                                        $buf = false;
     2070                                        break;
     2071                                }
     2072                                $bytes_remaining -= strlen( $read );
     2073                        } while( $bytes_remaining > 0 );
     2074
     2075                        reset_mbstring_encoding();
     2076
     2077                        fclose( $fp );
     2078
     2079                        if ( $buf ) {
     2080                                return $buf;
     2081                        }
     2082                }
     2083        }
     2084
     2085        // Available since PHP 5.3.0
     2086        // Uses native Windows Cyrpto API's in PHP 5.4+
     2087        // can be exceedingly slow before PHP 5.3.4 on windows - https://bugs.php.net/bug.php?id=51636
     2088        $use_openssl = function_exists('openssl_random_pseudo_bytes');
     2089        $use_openssl = $use_openssl && ! ( 'WIN' == substr( PHP_OS, 0, 3 ) && version_compare( phpversion(), '5.3.4', '<') );
     2090        if ( $use_openssl ) {
     2091                $buf = openssl_random_pseudo_bytes( $bytes );
     2092                if ( $buf !== false ) {
     2093                        return $buf;
     2094                }
     2095        }
     2096
     2097        return new WP_Error( 'external_rand_source_unavailable', 'External Random Sources unavailable' );
     2098}
     2099
     2100/**
     2101 * Generate a random positive integer between 0 and PHP_INT_MAX.
     2102 *
     2103 * @since x.x.x
     2104 * @internal
     2105 *
     2106 * @return int|WP_Error A random positive integer, WP_Error upon no external random sources being available
     2107 */
     2108function wp_external_random_positive_int() {
     2109        $buf = wp_external_random_bytes( PHP_INT_SIZE );
     2110        if ( is_wp_error( $buf ) ) {
     2111                return $buf;
     2112        }
     2113
     2114        $val = 0;
     2115        $i = strlen( $buf );
     2116
     2117        // TODO: Test on a 32bit machine with PHP_INT_SIZE = 4
     2118        do {
     2119                $i--;
     2120                $val <<= 8;
     2121                $val |= ord( $buf[ $i ] );
     2122        } while( $i != 0 );
     2123
     2124        // effectively absint()
     2125        return $val & PHP_INT_MAX;
     2126}
     2127
     2128/**
     2129 * Generates an unbiased, unpredictably random number.
     2130 *
     2131 * @since x.x.x
     2132 * @internal
     2133 *
     2134 * @param int $min Lower limit for the generated number.
     2135 * @param int $max Upper limit for the generated number.
     2136 * @return int|WP_Error A random number between min and max inclusively, WP_Error on external rand-source failure
     2137 */
     2138function wp_external_rand( $min = 0, $max = PHP_INT_MAX ) {
     2139        // Compat for `wp_rand()`
     2140        if ( 0 === $max ) {
     2141                $max = PHP_INT_MAX;
     2142        }
     2143        if ( $min == $max ) {
     2144                return $min;
     2145        }
     2146
     2147        // Calculate from 0..($max-$min), resulting in $min+$rand..$max
     2148        $max -= $min;
     2149
     2150        // 7776 -> 13
     2151        $bits = ceil( log( $max + 1 ) / log( 2 ) );
     2152
     2153        // 2^13 - 1 == 8191 or 0x00001111 11111111
     2154        // Calculate a mask of how much of the PHP int we're interested in
     2155        $mask = ceil( pow( 2, $bits ) ) - 1;
     2156
     2157        do {
     2158                $val = wp_external_random_positive_int();
     2159                if ( is_wp_error( $val ) ) {
     2160                        return $val;
     2161                }
     2162
     2163                // Apply the mask to our val
     2164                $val &= $mask;
     2165        } while ( $val > $max );
     2166
     2167        // $min..($min+$max)
     2168        return (int) ( $min + $val );
     2169}
     2170
     2171
    20202172if ( !function_exists('wp_rand') ) :
    20212173/**
    20222174 * Generates a random number
    20232175 *
    20242176 * @since 2.6.2
    20252177 *
    20262178 * @param int $min Lower limit for the generated number
    20272179 * @param int $max Upper limit for the generated number
    20282180 * @return int A random number between min and max
    20292181 */
    20302182function wp_rand( $min = 0, $max = 0 ) {
    20312183        global $rnd_value;
    20322184
     2185        // Use an external-
     2186        static $external_rand_source_available = true;
     2187        if ( $external_rand_source_available ) {
     2188                $val = wp_external_rand( $min, $max );
     2189                if ( ! is_wp_error( $val ) ) {
     2190                        return $val;
     2191                }
     2192                $external_rand_source_available = false;
     2193        }
     2194
    20332195        // Reset $rnd_value after 14 uses
    20342196        // 32(md5) + 40(sha1) + 40(sha1) / 8 = 14 random numbers from $rnd_value
    20352197        if ( strlen($rnd_value) < 8 ) {
    20362198                if ( defined( 'WP_SETUP_CONFIG' ) )
    20372199                        static $seed = '';
    20382200                else
    20392201                        $seed = get_transient('random_seed');
    20402202                $rnd_value = md5( uniqid(microtime() . mt_rand(), true ) . $seed );
    20412203                $rnd_value .= sha1($rnd_value);
    20422204                $rnd_value .= sha1($rnd_value . $seed);
    20432205                $seed = md5($seed . $rnd_value);
    20442206                if ( ! defined( 'WP_SETUP_CONFIG' ) )
    20452207                        set_transient('random_seed', $seed);
    20462208        }
    20472209