Ticket #28633: 28633.3.patch
File 28633.3.patch, 9.4 KB (added by , 10 years ago) |
---|
-
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 ) { 245 245 if ( $value == get_option( 'admin_email' ) || !is_email( $value ) ) 246 246 return; 247 247 248 $hash = md5( $value. time() .mt_rand() );248 $hash = md5( wp_random_bytes(16) . $value. time() .mt_rand() ); 249 249 $new_admin_email = array( 250 250 'hash' => $hash, 251 251 'newemail' => $value … … function send_confirmation_on_profile_email() { 323 323 return; 324 324 } 325 325 326 $hash = md5( $_POST['email'] . time() . mt_rand());326 $hash = bin2hex(wp_random_bytes(16)); 327 327 $new_user_email = array( 328 328 'hash' => $hash, 329 329 '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! 1016 1016 1017 1017 $vhost_ok = false; 1018 1018 $errstr = ''; 1019 $hostname = substr( md5( time() ), 0, 6) . '.' . $domain; // Very random hostname!1019 $hostname = bin2hex( wp_random_bytes(3) ) . '.' . $domain; // Very random hostname! 1020 1020 $page = wp_remote_get( 'http://' . $hostname, array( 'timeout' => 5, 'httpversion' => '1.1' ) ); 1021 1021 if ( is_wp_error( $page ) ) 1022 1022 $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 ) { 1668 1668 function win_is_writable( $path ) { 1669 1669 1670 1670 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'); 1672 1672 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' ); 1674 1674 1675 1675 // check tmp file for read/write capabilities 1676 1676 $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 = '' ) { 713 713 function wpmu_signup_blog( $domain, $path, $title, $user, $user_email, $meta = array() ) { 714 714 global $wpdb; 715 715 716 $key = substr( md5( time() . rand() . $domain ), 0, 16);716 $key = bin2hex(wp_random_bytes(8)); 717 717 $meta = serialize($meta); 718 718 719 719 $wpdb->insert( $wpdb->signups, array( … … function wpmu_signup_user( $user, $user_email, $meta = array() ) { 748 748 // Format data 749 749 $user = preg_replace( '/\s+/', '', sanitize_user( $user, true ) ); 750 750 $user_email = sanitize_email( $user_email ); 751 $key = substr( md5( time() . rand() . $user_email ), 0, 16);751 $key = bin2hex(wp_random_bytes(8)); 752 752 $meta = serialize($meta); 753 753 754 754 $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 1991 1991 1992 1992 $password = ''; 1993 1993 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); 1995 1995 } 1996 1996 1997 1997 /** … … function wp_generate_password( $length = 12, $special_chars = true, $extra_speci 2005 2005 } 2006 2006 endif; 2007 2007 2008 if ( !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 */ 2016 function 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 2092 endif; 2093 2094 if ( !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 */ 2100 function 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 } 2117 endif; 2118 2119 if ( !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 */ 2129 function 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 2145 endif; 2146 2008 2147 if ( !function_exists('wp_rand') ) : 2009 2148 /** 2010 2149 * 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 { 611 611 $json = wp_json_encode( $data, 0, 1 ); 612 612 $this->assertFalse( $json ); 613 613 } 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 } 614 649 }