WordPress.org

Make WordPress Core

Ticket #28633: 28633.3.patch

File 28633.3.patch, 9.4 KB (added by sarciszewski, 5 years ago)

Now with Windows + 5.2 support

  • src/wp-admin/includes/ms.php

    From fa13d0b974f313394c8f538d2a75b882cbbe26c1 Mon Sep 17 00:00:00 2001
    From: Scott Arciszewski <scott@resonantcore.net>
    Date: Wed, 10 Dec 2014 08:06:01 -0500
    Subject: [PATCH 1/1] Patch 28633 redux -- we now have a CSPRNG for PHP 5.2.x
     on Windows systems.
    
    ---
     src/wp-admin/includes/ms.php      |   4 +-
     src/wp-admin/includes/schema.php  |   2 +-
     src/wp-includes/functions.php     |   4 +-
     src/wp-includes/ms-functions.php  |   4 +-
     src/wp-includes/pluggable.php     | 141 +++++++++++++++++++++++++++++++++++++-
     tests/phpunit/tests/functions.php |  35 ++++++++++
     6 files changed, 182 insertions(+), 8 deletions(-)
    
    diff --git a/src/wp-admin/includes/ms.php b/src/wp-admin/includes/ms.php
    index a9c62bb..39f2243 100644
    a b function update_option_new_admin_email( $old_value, $value ) { 
    245245        if ( $value == get_option( 'admin_email' ) || !is_email( $value ) )
    246246                return;
    247247
    248         $hash = md5( $value. time() .mt_rand() );
     248        $hash = md5( wp_random_bytes(16) . $value. time() .mt_rand() );
    249249        $new_admin_email = array(
    250250                'hash' => $hash,
    251251                'newemail' => $value
    function send_confirmation_on_profile_email() { 
    323323                        return;
    324324                }
    325325
    326                 $hash = md5( $_POST['email'] . time() . mt_rand() );
     326                $hash = bin2hex(wp_random_bytes(16));
    327327                $new_user_email = array(
    328328                                'hash' => $hash,
    329329                                'newemail' => $_POST['email']
  • src/wp-admin/includes/schema.php

    diff --git a/src/wp-admin/includes/schema.php b/src/wp-admin/includes/schema.php
    index 296a699..db0b2e6 100644
    a b We hope you enjoy your new site. Thanks! 
    10161016
    10171017                $vhost_ok = false;
    10181018                $errstr = '';
    1019                 $hostname = substr( md5( time() ), 0, 6 ) . '.' . $domain; // Very random hostname!
     1019                $hostname = bin2hex( wp_random_bytes(3) ) . '.' . $domain; // Very random hostname!
    10201020                $page = wp_remote_get( 'http://' . $hostname, array( 'timeout' => 5, 'httpversion' => '1.1' ) );
    10211021                if ( is_wp_error( $page ) )
    10221022                        $errstr = $page->get_error_message();
  • src/wp-includes/functions.php

    diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php
    index 76013c9..12393ba 100644
    a b function wp_is_writable( $path ) { 
    16681668function win_is_writable( $path ) {
    16691669
    16701670        if ( $path[strlen( $path ) - 1] == '/' ) // if it looks like a directory, check a random file within the directory
    1671                 return win_is_writable( $path . uniqid( mt_rand() ) . '.tmp');
     1671                return win_is_writable( $path . uniqid( bin2hex(wp_random_bytes(16)) ) . '.tmp');
    16721672        else if ( is_dir( $path ) ) // If it's a directory (and not a file) check a random file within the directory
    1673                 return win_is_writable( $path . '/' . uniqid( mt_rand() ) . '.tmp' );
     1673                return win_is_writable( $path . '/' . uniqid( bin2hex(wp_random_bytes(16)) ) . '.tmp' );
    16741674
    16751675        // check tmp file for read/write capabilities
    16761676        $should_delete_tmp_file = !file_exists( $path );
  • src/wp-includes/ms-functions.php

    diff --git a/src/wp-includes/ms-functions.php b/src/wp-includes/ms-functions.php
    index 5537fb3..82c2023 100644
    a b function wpmu_validate_blog_signup( $blogname, $blog_title, $user = '' ) { 
    713713function wpmu_signup_blog( $domain, $path, $title, $user, $user_email, $meta = array() )  {
    714714        global $wpdb;
    715715
    716         $key = substr( md5( time() . rand() . $domain ), 0, 16 );
     716        $key = bin2hex(wp_random_bytes(8));
    717717        $meta = serialize($meta);
    718718
    719719        $wpdb->insert( $wpdb->signups, array(
    function wpmu_signup_user( $user, $user_email, $meta = array() ) { 
    748748        // Format data
    749749        $user = preg_replace( '/\s+/', '', sanitize_user( $user, true ) );
    750750        $user_email = sanitize_email( $user_email );
    751         $key = substr( md5( time() . rand() . $user_email ), 0, 16 );
     751        $key = bin2hex(wp_random_bytes(8));
    752752        $meta = serialize($meta);
    753753
    754754        $wpdb->insert( $wpdb->signups, array(
  • src/wp-includes/pluggable.php

    diff --git a/src/wp-includes/pluggable.php b/src/wp-includes/pluggable.php
    index 8f3a5de..d3daf21 100644
    a b function wp_generate_password( $length = 12, $special_chars = true, $extra_speci 
    19911991
    19921992        $password = '';
    19931993        for ( $i = 0; $i < $length; $i++ ) {
    1994                 $password .= substr($chars, wp_rand(0, strlen($chars) - 1), 1);
     1994                $password .= substr($chars, wp_secure_rand(0, strlen($chars) - 1), 1);
    19951995        }
    19961996
    19971997        /**
    function wp_generate_password( $length = 12, $special_chars = true, $extra_speci 
    20052005}
    20062006endif;
    20072007
     2008if ( !function_exists('wp_random_bytes') ) :
     2009
     2010/**
     2011 * Generate a cryptographically secure random string
     2012 * @ref http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/
     2013 *
     2014 * @param int $bytes - how many bytes do we want?
     2015 */
     2016function wp_random_bytes($bytes = 32) {
     2017        $buf = '';
     2018    /**
     2019     * If /dev/urandom is available, let's prefer it over every other method
     2020     *
     2021     * This should only return false on Windows hosts and in chroot jails
     2022     */
     2023        if (is_readable('/dev/urandom')) {
     2024                $fp = fopen('/dev/urandom', 'rb');
     2025                if ($fp !== false) {
     2026                        $buf = fread($fp, $bytes);
     2027                        fclose($fp);
     2028                        if ($buf !== FALSE) {
     2029                                return $buf;
     2030                        }
     2031                }
     2032        }
     2033    /**
     2034     * This is preferable to userspace RNGs (e.g. openssl)
     2035     * because it reads directly from /dev/urandom on most OS's,
     2036     * and uses Windows's Crypto APIs transparently.
     2037     *
     2038     * Requires the mcrypt extension be installed/enabled.
     2039     */
     2040        if (function_exists('mcrypt_create_iv')) {
     2041                $buf = mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM);
     2042                if($buf !== FALSE) {
     2043                        return $buf;
     2044                }
     2045        }
     2046    /**
     2047     * This is available since PHP 5.3.0 on every PHP install.
     2048     */
     2049        if (function_exists('openssl_random_pseudo_bytes')) {
     2050                $buf = openssl_random_pseudo_bytes($bytes);
     2051        if ($buf !== false) {
     2052                        return $buf;
     2053        }
     2054        }
     2055
     2056    /**
     2057     * Windows with PHP < 5.3.0 will not have the function
     2058     * openssl_random_pseudo_bytes() available, so let's use
     2059     * CAPICOM to work around this deficiency.
     2060     *
     2061     * When we stop supporting unsupported versions of PHP,
     2062     * (i.e. less than 5.5) this should be easily removable.
     2063     */
     2064    if (class_exists('\\COM', false)) {
     2065        try {
     2066            $util = new \COM('CAPICOM.Utilities.1');
     2067            $execs = 0;
     2068            /**
     2069             * Let's not let it loop forever. If we run N times and fail to
     2070             * get N bytes of entropy, then CAPICOM has failed us.
     2071             */
     2072            while ($execs < $bytes) {
     2073                $buf .= base64_decode($util->GetRandom($bytes, 0));
     2074                if (strlen($buf) > $bytes) {
     2075                    return substr($buf, 0, $bytes);
     2076                }
     2077            }
     2078        } catch (\Exception($e)) {
     2079            unset($e); // Let's not let CAPICOM errors kill our app
     2080        }
     2081    }
     2082    /**
     2083     * Okay, at this point, we cannot guarantee a CSPRNG no matter what we
     2084     * do. Our only recourse is to return something insecure.
     2085     */
     2086    for ($i = 0; $i < $bytes; ++$i) {
     2087        $buf .= chr(wp_rand(0, 255));
     2088    }
     2089    return $buf;
     2090}
     2091
     2092endif;
     2093
     2094if ( !function_exists('wp_random_positive_int'):
     2095/**
     2096 * Generate a random positive integer between 0 and PHP_INT_MAX
     2097 *
     2098 * @return int A random positive integer
     2099 */
     2100function wp_random_positive_int() {
     2101    $buf = wp_random_bytes(PHP_INT_SIZE);
     2102    if($buf === false) {
     2103        trigger_error('Random number failure', E_USER_ERROR);
     2104    }
     2105
     2106    $val = 0;
     2107    $i = strlen($buf);
     2108
     2109    do {
     2110        $i--;
     2111        $val <<= 8;
     2112        $val |= ord($buf[$i]);
     2113    } while ($i != 0);
     2114
     2115    return $val & PHP_INT_MAX;
     2116}
     2117endif;
     2118
     2119if ( !function_exists('wp_secure_rand') ):
     2120/**
     2121 * Generates an unbiased, unpredictably random number
     2122 *
     2123 * @since x.x.x
     2124 *
     2125 * @param int $min Lower limit for the generated number
     2126 * @param int $max Upper limit for the generated number
     2127 * @return int A random number between min and max
     2128 */
     2129function wp_secure_rand( $min = 0, $max = 0) {
     2130    $range = $max - $min;
     2131    if ($range < 2) {
     2132        return $min;
     2133    }
     2134    $rem = (PHP_INT_MAX - $range + 1) % $range;
     2135    do {
     2136        $val = wp_random_positive_int();
     2137        if ($val === false) {
     2138            // RNG failure
     2139            return false;
     2140        }
     2141    } while ($val < $rem);
     2142    return (int) ($min + $val % $range);
     2143}
     2144
     2145endif;
     2146
    20082147if ( !function_exists('wp_rand') ) :
    20092148/**
    20102149 * Generates a random number
  • tests/phpunit/tests/functions.php

    diff --git a/tests/phpunit/tests/functions.php b/tests/phpunit/tests/functions.php
    index 1edd143..2f4f5ad 100644
    a b class Tests_Functions extends WP_UnitTestCase { 
    611611                $json = wp_json_encode( $data, 0, 1 );
    612612                $this->assertFalse( $json );
    613613        }
     614
     615    /**
     616     * @ticket 28633
     617     */
     618    function test_wp_secure_rand() {
     619        // Let's load a buffer
     620        $buff = array();
     621
     622        // How size do we want our test array to be?
     623
     624        //$size = wp_rand(16,256);
     625        $size = 16;
     626
     627        // We should expect
     628        $to_run = 10;
     629
     630        //
     631        for($i = 0; $i < $size; ++$i) {
     632            $buff[$i] = 0;
     633        }
     634
     635        $tests = $size * $to_run;
     636
     637        for($i = 0; $i < $tests; ++$i) {
     638            ++$buff[wp_secure_rand(0, $size - 1)];
     639        }
     640
     641        // With any luck, all of these should be near $to_run.
     642        $passed = 0;
     643        for($i = 0; $i < $size; ++$i) {
     644            $this->assertNotEquals($buff[$i], 0);
     645        }
     646
     647        // We can do statistical tests later to ensure the output is unbiased.
     648    }
    614649}