WordPress.org

Make WordPress Core

Ticket #28633: 28633.4.patch

File 28633.4.patch, 9.5 KB (added by sarciszewski, 5 years ago)

Edited the patch file manually because git://develop.git.wordpress.org is not working atm

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

    From fa13d0b974f313394c8f538d2a75b882cbbe26c1 Mon Sep 17 00:00:00 2001
    From: Scott Arciszewski <scott@resonantcore.net>
    Date: Thu, 02 Feb 2014 11:09: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     | 142 +++++++++++++++++++++++++++++++++++++-
     tests/phpunit/tests/functions.php |  35 ++++++++++
     6 files changed, 183 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       stream_set_read_buffer($fp, 0);
     2026                if ($fp !== false) {
     2027                        $buf = fread($fp, $bytes);
     2028                        fclose($fp);
     2029                        if ($buf !== FALSE) {
     2030                                return $buf;
     2031                        }
     2032                }
     2033        }
     2034    /**
     2035     * This is preferable to userspace RNGs (e.g. openssl)
     2036     * because it reads directly from /dev/urandom on most OS's,
     2037     * and uses Windows's Crypto APIs transparently.
     2038     *
     2039     * Requires the mcrypt extension be installed/enabled.
     2040     */
     2041        if (function_exists('mcrypt_create_iv')) {
     2042                $buf = mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM);
     2043                if($buf !== FALSE) {
     2044                        return $buf;
     2045                }
     2046        }
     2047    /**
     2048     * This is available since PHP 5.3.0 on every PHP install.
     2049     */
     2050        if (function_exists('openssl_random_pseudo_bytes')) {
     2051                $buf = openssl_random_pseudo_bytes($bytes);
     2052        if ($buf !== false) {
     2053                        return $buf;
     2054        }
     2055        }
     2056
     2057    /**
     2058     * Windows with PHP < 5.3.0 will not have the function
     2059     * openssl_random_pseudo_bytes() available, so let's use
     2060     * CAPICOM to work around this deficiency.
     2061     *
     2062     * When we stop supporting unsupported versions of PHP,
     2063     * (i.e. less than 5.5) this should be easily removable.
     2064     */
     2065    if (class_exists('\\COM', false)) {
     2066        try {
     2067            $util = new \COM('CAPICOM.Utilities.1');
     2068            $execs = 0;
     2069            /**
     2070             * Let's not let it loop forever. If we run N times and fail to
     2071             * get N bytes of entropy, then CAPICOM has failed us.
     2072             */
     2073            while ($execs < $bytes) {
     2074                $buf .= base64_decode($util->GetRandom($bytes, 0));
     2075                if (strlen($buf) > $bytes) {
     2076                    return substr($buf, 0, $bytes);
     2077                }
     2078            }
     2079        } catch (\Exception($e)) {
     2080            unset($e); // Let's not let CAPICOM errors kill our app
     2081        }
     2082    }
     2083    /**
     2084     * Okay, at this point, we cannot guarantee a CSPRNG no matter what we
     2085     * do. Our only recourse is to return something insecure.
     2086     */
     2087    for ($i = 0; $i < $bytes; ++$i) {
     2088        $buf .= chr(wp_rand(0, 255));
     2089    }
     2090    return $buf;
     2091}
     2092
     2093endif;
     2094
     2095if ( !function_exists('wp_random_positive_int'):
     2096/**
     2097 * Generate a random positive integer between 0 and PHP_INT_MAX
     2098 *
     2099 * @return int A random positive integer
     2100 */
     2101function wp_random_positive_int() {
     2102    $buf = wp_random_bytes(PHP_INT_SIZE);
     2103    if($buf === false) {
     2104        trigger_error('Random number failure', E_USER_ERROR);
     2105    }
     2106
     2107    $val = 0;
     2108    $i = strlen($buf);
     2109
     2110    do {
     2111        $i--;
     2112        $val <<= 8;
     2113        $val |= ord($buf[$i]);
     2114    } while ($i != 0);
     2115
     2116    return $val & PHP_INT_MAX;
     2117}
     2118endif;
     2119
     2120if ( !function_exists('wp_secure_rand') ):
     2121/**
     2122 * Generates an unbiased, unpredictably random number
     2123 *
     2124 * @since x.x.x
     2125 *
     2126 * @param int $min Lower limit for the generated number
     2127 * @param int $max Upper limit for the generated number
     2128 * @return int A random number between min and max
     2129 */
     2130function wp_secure_rand( $min = 0, $max = 0) {
     2131    $range = $max - $min;
     2132    if ($range < 2) {
     2133        return $min;
     2134    }
     2135    $rem = (PHP_INT_MAX - $range + 1) % $range;
     2136    do {
     2137        $val = wp_random_positive_int();
     2138        if ($val === false) {
     2139            // RNG failure
     2140            return false;
     2141        }
     2142    } while ($val < $rem);
     2143    return (int) ($min + $val % $range);
     2144}
     2145
     2146endif;
     2147
    20082148if ( !function_exists('wp_rand') ) :
    20092149/**
    20102150 * 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}