Make WordPress Core

Ticket #28633: 28633.10.patch

File 28633.10.patch, 33.9 KB (added by sarciszewski, 9 years ago)

Use paragonie/random_compat

  • wp-includes/pluggable.php

    From 975345d36844cdbf836a8c6e466b54484fb51090 Mon Sep 17 00:00:00 2001
    From: Scott <scott@paragonie.com>
    Date: Wed, 9 Sep 2015 17:52:23 -0400
    Subject: [PATCH] Fix #28633 - use random_compat for PHP 7 CSPRNG functions in
     PHP 5
    
    ---
     wp-includes/pluggable.php                          |  10 ++
     wp-includes/random_compat/byte_safe_strings.php    | 154 +++++++++++++++++++
     wp-includes/random_compat/error_polyfill.php       |  56 +++++++
     wp-includes/random_compat/random.php               |  80 ++++++++++
     .../random_compat/random_bytes_com_dotnet.php      |  76 +++++++++
     .../random_compat/random_bytes_dev_urandom.php     | 137 +++++++++++++++++
     wp-includes/random_compat/random_bytes_mcrypt.php  |  71 +++++++++
     wp-includes/random_compat/random_bytes_openssl.php |  76 +++++++++
     wp-includes/random_compat/random_int.php           | 170 +++++++++++++++++++++
     wp-settings.php                                    |   3 +
     10 files changed, 833 insertions(+)
     create mode 100644 wp-includes/random_compat/byte_safe_strings.php
     create mode 100644 wp-includes/random_compat/error_polyfill.php
     create mode 100644 wp-includes/random_compat/random.php
     create mode 100644 wp-includes/random_compat/random_bytes_com_dotnet.php
     create mode 100644 wp-includes/random_compat/random_bytes_dev_urandom.php
     create mode 100644 wp-includes/random_compat/random_bytes_mcrypt.php
     create mode 100644 wp-includes/random_compat/random_bytes_openssl.php
     create mode 100644 wp-includes/random_compat/random_int.php
    
    diff --git a/wp-includes/pluggable.php b/wp-includes/pluggable.php
    index 5889b5c..f89a81c 100644
    a b if ( !function_exists('wp_rand') ) : 
    21192119function wp_rand( $min = 0, $max = 0 ) {
    21202120        global $rnd_value;
    21212121
     2122        // Use an external source?
     2123        static $external_rand_source_available = true;
     2124        if ( $external_rand_source_available ) {
     2125                try {
     2126                        $val = random_int( $min, $max );
     2127                } catch (Exception $e) {
     2128                        $external_rand_source_available = false;
     2129                }
     2130        }
     2131
    21222132        // Reset $rnd_value after 14 uses
    21232133        // 32(md5) + 40(sha1) + 40(sha1) / 8 = 14 random numbers from $rnd_value
    21242134        if ( strlen($rnd_value) < 8 ) {
  • new file wp-includes/random_compat/byte_safe_strings.php

    diff --git a/wp-includes/random_compat/byte_safe_strings.php b/wp-includes/random_compat/byte_safe_strings.php
    new file mode 100644
    index 0000000..ad45830
    - +  
     1<?php
     2/**
     3 * Random_* Compatibility Library
     4 * for using the new PHP 7 random_* API in PHP 5 projects
     5 *
     6 * The MIT License (MIT)
     7 *
     8 * Copyright (c) 2015 Paragon Initiative Enterprises
     9 *
     10 * Permission is hereby granted, free of charge, to any person obtaining a copy
     11 * of this software and associated documentation files (the "Software"), to deal
     12 * in the Software without restriction, including without limitation the rights
     13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     14 * copies of the Software, and to permit persons to whom the Software is
     15 * furnished to do so, subject to the following conditions:
     16 *
     17 * The above copyright notice and this permission notice shall be included in
     18 * all copies or substantial portions of the Software.
     19 *
     20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     26 * SOFTWARE.
     27 */
     28
     29if (!function_exists('RandomCompat_strlen')) {
     30    if (ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING) {
     31        /**
     32         * strlen() implementation that isn't brittle to mbstring.func_overload
     33         *
     34         * This version uses mb_strlen() in '8bit' mode to treat strings as raw
     35         * binary rather than UTF-8, ISO-8859-1, etc
     36         *
     37         * @param string $binary_string
     38         *
     39         * @throws TypeError
     40         *
     41         * @return int
     42         */
     43        function RandomCompat_strlen($binary_string)
     44        {
     45            if (!is_string($binary_string)) {
     46                throw new TypeError(
     47                    'RandomCompat_strlen() expects a string'
     48                );
     49            }
     50            return mb_strlen($binary_string, '8bit');
     51        }
     52    } else {
     53        /**
     54         * strlen() implementation that isn't brittle to mbstring.func_overload
     55         *
     56         * This version just used the default strlen()
     57         *
     58         * @param string $binary_string
     59         *
     60         * @throws TypeError
     61         *
     62         * @return int
     63         */
     64        function RandomCompat_strlen($binary_string)
     65        {
     66            if (!is_string($binary_string)) {
     67                throw new TypeError(
     68                    'RandomCompat_strlen() expects a string'
     69                );
     70            }
     71            return strlen($binary_string);
     72        }
     73    }
     74}
     75
     76if (!function_exists('RandomCompat_substr')) {
     77    if (ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING) {
     78        /**
     79         * substr() implementation that isn't brittle to mbstring.func_overload
     80         *
     81         * This version uses mb_substr() in '8bit' mode to treat strings as raw
     82         * binary rather than UTF-8, ISO-8859-1, etc
     83         *
     84         * @param string $binary_string
     85         * @param int $start
     86         * @param int $length (optional)
     87         *
     88         * @throws TypeError
     89         *
     90         * @return string
     91         */
     92        function RandomCompat_substr($binary_string, $start, $length = null)
     93        {
     94            if (!is_string($binary_string)) {
     95                throw new TypeError(
     96                    'RandomCompat_substr(): First argument should be a string'
     97                );
     98            }
     99            if (!is_int($start)) {
     100                throw new TypeError(
     101                    'RandomCompat_substr(): Second argument should be an integer'
     102                );
     103            }
     104            if ($length === null) {
     105                /**
     106                 * mb_substr($str, 0, NULL, '8bit') returns an empty string on
     107                 * PHP 5.3, so we have to find the length ourselves.
     108                 */
     109                $length = RandomCompat_strlen($length) - $start;
     110            } elseif (!is_int($length)) {
     111                throw new TypeError(
     112                    'RandomCompat_substr(): Third argument should be an integer, or omitted'
     113                );
     114            }
     115            return mb_substr($binary_string, $start, $length, '8bit');
     116        }
     117    } else {
     118        /**
     119         * substr() implementation that isn't brittle to mbstring.func_overload
     120         *
     121         * This version just uses the default substr()
     122         *
     123         * @param string $binary_string
     124         * @param int $start
     125         * @param int $length (optional)
     126         *
     127         * @throws TypeError
     128         *
     129         * @return string
     130         */
     131        function RandomCompat_substr($binary_string, $start, $length = null)
     132        {
     133            if (!is_string($binary_string)) {
     134                throw new TypeError(
     135                    'RandomCompat_substr(): First argument should be a string'
     136                );
     137            }
     138            if (!is_int($start)) {
     139                throw new TypeError(
     140                    'RandomCompat_substr(): Second argument should be an integer'
     141                );
     142            }
     143            if ($length !== null) {
     144                if (!is_int($length)) {
     145                    throw new TypeError(
     146                        'RandomCompat_substr(): Third argument should be an integer, or omitted'
     147                    );
     148                }
     149                return substr($binary_string, $start, $length);
     150            }
     151            return substr($binary_string, $start);
     152        }
     153    }
     154}
  • new file wp-includes/random_compat/error_polyfill.php

    diff --git a/wp-includes/random_compat/error_polyfill.php b/wp-includes/random_compat/error_polyfill.php
    new file mode 100644
    index 0000000..7253ff7
    - +  
     1<?php
     2/**
     3 * Random_* Compatibility Library
     4 * for using the new PHP 7 random_* API in PHP 5 projects
     5 *
     6 * The MIT License (MIT)
     7 *
     8 * Copyright (c) 2015 Paragon Initiative Enterprises
     9 *
     10 * Permission is hereby granted, free of charge, to any person obtaining a copy
     11 * of this software and associated documentation files (the "Software"), to deal
     12 * in the Software without restriction, including without limitation the rights
     13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     14 * copies of the Software, and to permit persons to whom the Software is
     15 * furnished to do so, subject to the following conditions:
     16 *
     17 * The above copyright notice and this permission notice shall be included in
     18 * all copies or substantial portions of the Software.
     19 *
     20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     26 * SOFTWARE.
     27 */
     28
     29if (!interface_exists('Throwable', false)) {
     30    interface Throwable
     31    {
     32        public function getMessage();
     33        public function getCode();
     34        public function getFile();
     35        public function getLine();
     36        public function getTrace();
     37        public function getTraceAsString();
     38        public function getPrevious();
     39        public function __toString();
     40    }
     41}
     42
     43if (!class_exists('Error', false)) {
     44    // We can't really avoid making this extend Exception in PHP 5.
     45    class Error extends Exception implements Throwable
     46    {
     47       
     48    }
     49}
     50
     51if (!class_exists('TypeError', false)) {
     52    class TypeError extends Error
     53    {
     54       
     55    }
     56}
     57 No newline at end of file
  • new file wp-includes/random_compat/random.php

    diff --git a/wp-includes/random_compat/random.php b/wp-includes/random_compat/random.php
    new file mode 100644
    index 0000000..ca72197
    - +  
     1<?php
     2/**
     3 * Random_* Compatibility Library
     4 * for using the new PHP 7 random_* API in PHP 5 projects
     5 *
     6 * The MIT License (MIT)
     7 *
     8 * Copyright (c) 2015 Paragon Initiative Enterprises
     9 *
     10 * Permission is hereby granted, free of charge, to any person obtaining a copy
     11 * of this software and associated documentation files (the "Software"), to deal
     12 * in the Software without restriction, including without limitation the rights
     13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     14 * copies of the Software, and to permit persons to whom the Software is
     15 * furnished to do so, subject to the following conditions:
     16 *
     17 * The above copyright notice and this permission notice shall be included in
     18 * all copies or substantial portions of the Software.
     19 *
     20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     26 * SOFTWARE.
     27 */
     28
     29if (!defined('PHP_VERSION_ID')) {
     30    // This constant was introduced in PHP 5.2.7
     31    $version = explode('.', PHP_VERSION);
     32    define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2]));
     33}
     34if (PHP_VERSION_ID < 70000) {
     35    if (!defined('RANDOM_COMPAT_READ_BUFFER')) {
     36        define('RANDOM_COMPAT_READ_BUFFER', 8);
     37    }
     38    require_once "byte_safe_strings.php";
     39    require_once "error_polyfill.php";
     40    if (!function_exists('random_bytes')) {
     41        /**
     42         * PHP 5.2.0 - 5.6.x way to implement random_bytes()
     43         *
     44         * We use conditional statements here to define the function in accordance
     45         * to the operating environment. It's a micro-optimization.
     46         *
     47         * In order of preference:
     48         *   1. fread() /dev/urandom if available
     49         *   2. mcrypt_create_iv($bytes, MCRYPT_CREATE_IV)
     50         *   3. COM('CAPICOM.Utilities.1')->GetRandom()
     51         *   4. openssl_random_pseudo_bytes()
     52         *
     53         * See ERRATA.md for our reasoning behind this particular order
     54         */
     55         if (!ini_get('open_basedir') && is_readable('/dev/urandom')) {
     56            // See random_bytes_dev_urandom.php
     57            require_once "random_bytes_dev_urandom.php";
     58        } elseif (PHP_VERSION_ID >= 50307 && function_exists('mcrypt_create_iv')) {
     59            // See random_bytes_mcrypt.php
     60            require_once "random_bytes_mcrypt.php";
     61        } elseif (extension_loaded('com_dotnet')) {
     62            // See random_bytes_com_dotnet.php
     63            require_once "random_bytes_com_dotnet.php";
     64        } elseif (function_exists('openssl_random_pseudo_bytes')) {
     65            // See random_bytes_openssl.php
     66            require_once "random_bytes_openssl.php";
     67        } else {
     68            /**
     69             * We don't have any more options, so let's throw an exception right now
     70             * and hope the developer won't let it fail silently.
     71             */
     72            throw new Exception(
     73                'There is no suitable CSPRNG installed on your system'
     74            );
     75        }
     76    }
     77    if (!function_exists('random_int')) {
     78        require_once "random_int.php";
     79    }
     80}
  • new file wp-includes/random_compat/random_bytes_com_dotnet.php

    diff --git a/wp-includes/random_compat/random_bytes_com_dotnet.php b/wp-includes/random_compat/random_bytes_com_dotnet.php
    new file mode 100644
    index 0000000..241eee0
    - +  
     1<?php
     2/**
     3 * Random_* Compatibility Library
     4 * for using the new PHP 7 random_* API in PHP 5 projects
     5 *
     6 * The MIT License (MIT)
     7 *
     8 * Copyright (c) 2015 Paragon Initiative Enterprises
     9 *
     10 * Permission is hereby granted, free of charge, to any person obtaining a copy
     11 * of this software and associated documentation files (the "Software"), to deal
     12 * in the Software without restriction, including without limitation the rights
     13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     14 * copies of the Software, and to permit persons to whom the Software is
     15 * furnished to do so, subject to the following conditions:
     16 *
     17 * The above copyright notice and this permission notice shall be included in
     18 * all copies or substantial portions of the Software.
     19 *
     20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     26 * SOFTWARE.
     27 */
     28if (!function_exists('random_bytes') && extension_loaded('com_dotnet')) {
     29    /**
     30     * Windows with PHP < 5.3.0 will not have the function
     31     * openssl_random_pseudo_bytes() available, so let's use
     32     * CAPICOM to work around this deficiency.
     33     *
     34     * @param int $bytes
     35     *
     36     * @throws Exception
     37     *
     38     * @return string
     39     */
     40    function random_bytes($bytes)
     41    {
     42        if (!is_int($bytes)) {
     43            throw new TypeError(
     44                'Length must be an integer'
     45            );
     46        }
     47        if ($bytes < 1) {
     48            throw new Error(
     49                'Length must be greater than 0'
     50            );
     51        }
     52        $buf = '';
     53        $util = new COM('CAPICOM.Utilities.1');
     54        $execCount = 0;
     55        /**
     56         * Let's not let it loop forever. If we run N times and fail to
     57         * get N bytes of random data, then CAPICOM has failed us.
     58         */
     59        do {
     60            $buf .= base64_decode($util->GetRandom($bytes, 0));
     61            if (RandomCompat_strlen($buf) >= $bytes) {
     62                /**
     63                 * Return our random entropy buffer here:
     64                 */
     65                return RandomCompat_substr($buf, 0, $bytes);
     66            }
     67            ++$execCount;
     68        } while ($execCount < $bytes);
     69        /**
     70         * If we reach here, PHP has failed us.
     71         */
     72        throw new Exception(
     73            'PHP failed to generate random data.'
     74        );
     75    }
     76}
  • new file wp-includes/random_compat/random_bytes_dev_urandom.php

    diff --git a/wp-includes/random_compat/random_bytes_dev_urandom.php b/wp-includes/random_compat/random_bytes_dev_urandom.php
    new file mode 100644
    index 0000000..e55b66d
    - +  
     1<?php
     2/**
     3 * Random_* Compatibility Library
     4 * for using the new PHP 7 random_* API in PHP 5 projects
     5 *
     6 * The MIT License (MIT)
     7 *
     8 * Copyright (c) 2015 Paragon Initiative Enterprises
     9 *
     10 * Permission is hereby granted, free of charge, to any person obtaining a copy
     11 * of this software and associated documentation files (the "Software"), to deal
     12 * in the Software without restriction, including without limitation the rights
     13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     14 * copies of the Software, and to permit persons to whom the Software is
     15 * furnished to do so, subject to the following conditions:
     16 *
     17 * The above copyright notice and this permission notice shall be included in
     18 * all copies or substantial portions of the Software.
     19 *
     20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     26 * SOFTWARE.
     27 */
     28
     29if (!function_exists('random_bytes') && !ini_get('open_basedir') && is_readable('/dev/urandom')) {
     30    if (!defined('RANDOM_COMPAT_READ_BUFFER')) {
     31        define('RANDOM_COMPAT_READ_BUFFER', 8);
     32    }
     33   
     34    /**
     35     * Unless open_basedir is enabled, use /dev/urandom for
     36     * random numbers in accordance with best practices
     37     *
     38     * Why we use /dev/urandom and not /dev/random
     39     * @ref http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers
     40     *
     41     * @param int $bytes
     42     *
     43     * @throws Exception
     44     *
     45     * @return string
     46     */
     47    function random_bytes($bytes)
     48    {
     49        static $fp = null;
     50        /**
     51         * This block should only be run once
     52         */
     53        if (empty($fp)) {
     54            /**
     55             * We use /dev/urandom if it is a char device.
     56             * We never fall back to /dev/random
     57             */
     58            $fp = fopen('/dev/urandom', 'rb');
     59            if (!empty($fp)) {
     60                $st = fstat($fp);
     61                if (($st['mode'] & 0170000) !== 020000) {
     62                    fclose($fp);
     63                    $fp = false;
     64                }
     65            }
     66            /**
     67             * stream_set_read_buffer() does not exist in HHVM
     68             *
     69             * If we don't set the stream's read buffer to 0, PHP will
     70             * internally buffer 8192 bytes, which can waste entropy
     71             *
     72             * stream_set_read_buffer returns 0 on success
     73             */
     74            if (!empty($fp) && function_exists('stream_set_read_buffer')) {
     75                stream_set_read_buffer($fp, RANDOM_COMPAT_READ_BUFFER);
     76            }
     77        }
     78        if (!is_int($bytes)) {
     79            throw new TypeError(
     80                'Length must be an integer'
     81            );
     82        }
     83        if ($bytes < 1) {
     84            throw new Error(
     85                'Length must be greater than 0'
     86            );
     87        }
     88        /**
     89         * This if() block only runs if we managed to open a file handle
     90         *
     91         * It does not belong in an else {} block, because the above
     92         * if (empty($fp)) line is logic that should only be run once per
     93         * page load.
     94         */
     95        if (!empty($fp)) {
     96            $remaining = $bytes;
     97            $buf = '';
     98            /**
     99             * We use fread() in a loop to protect against partial reads
     100             */
     101            do {
     102                $read = fread($fp, $remaining);
     103                if ($read === false) {
     104                    /**
     105                     * We cannot safely read from the file. Exit the
     106                     * do-while loop and trigger the exception condition
     107                     */
     108                    $buf = false;
     109                    break;
     110                }
     111                /**
     112                 * Decrease the number of bytes returned from remaining
     113                 */
     114                $remaining -= RandomCompat_strlen($read);
     115                $buf .= $read;
     116            } while ($remaining > 0);
     117           
     118            /**
     119             * Is our result valid?
     120             */
     121            if ($buf !== false) {
     122                if (RandomCompat_strlen($buf) === $bytes) {
     123                    /**
     124                     * Return our random entropy buffer here:
     125                     */
     126                    return $buf;
     127                }
     128            }
     129        }
     130        /**
     131         * If we reach here, PHP has failed us.
     132         */
     133        throw new Exception(
     134            'PHP failed to generate random data.'
     135        );
     136    }
     137}
  • new file wp-includes/random_compat/random_bytes_mcrypt.php

    diff --git a/wp-includes/random_compat/random_bytes_mcrypt.php b/wp-includes/random_compat/random_bytes_mcrypt.php
    new file mode 100644
    index 0000000..c58ab99
    - +  
     1<?php
     2/**
     3 * Random_* Compatibility Library
     4 * for using the new PHP 7 random_* API in PHP 5 projects
     5 *
     6 * The MIT License (MIT)
     7 *
     8 * Copyright (c) 2015 Paragon Initiative Enterprises
     9 *
     10 * Permission is hereby granted, free of charge, to any person obtaining a copy
     11 * of this software and associated documentation files (the "Software"), to deal
     12 * in the Software without restriction, including without limitation the rights
     13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     14 * copies of the Software, and to permit persons to whom the Software is
     15 * furnished to do so, subject to the following conditions:
     16 *
     17 * The above copyright notice and this permission notice shall be included in
     18 * all copies or substantial portions of the Software.
     19 *
     20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     26 * SOFTWARE.
     27 */
     28
     29if (!function_exists('random_bytes') && function_exists('mcrypt_create_iv') && version_compare(PHP_VERSION, '5.3.7') >= 0) {
     30    /**
     31     * Powered by ext/mcrypt (and thankfully NOT libmcrypt)
     32     *
     33     * @ref https://bugs.php.net/bug.php?id=55169
     34     * @ref https://github.com/php/php-src/blob/c568ffe5171d942161fc8dda066bce844bdef676/ext/mcrypt/mcrypt.c#L1321-L1386
     35     *
     36     * @param int $bytes
     37     *
     38     * @throws Exception
     39     *
     40     * @return string
     41     */
     42    function random_bytes($bytes)
     43    {
     44        if (!is_int($bytes)) {
     45            throw new TypeError(
     46                'Length must be an integer'
     47            );
     48        }
     49        if ($bytes < 1) {
     50            throw new Error(
     51                'Length must be greater than 0'
     52            );
     53        }
     54       
     55        $buf = mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM);
     56        if ($buf !== false) {
     57            if (RandomCompat_strlen($buf) === $bytes) {
     58                /**
     59                 * Return our random entropy buffer here:
     60                 */
     61                return $buf;
     62            }
     63        }
     64        /**
     65         * If we reach here, PHP has failed us.
     66         */
     67        throw new Exception(
     68            'PHP failed to generate random data.'
     69        );
     70    }
     71}
  • new file wp-includes/random_compat/random_bytes_openssl.php

    diff --git a/wp-includes/random_compat/random_bytes_openssl.php b/wp-includes/random_compat/random_bytes_openssl.php
    new file mode 100644
    index 0000000..5141ef6
    - +  
     1<?php
     2/**
     3 * Random_* Compatibility Library
     4 * for using the new PHP 7 random_* API in PHP 5 projects
     5 *
     6 * The MIT License (MIT)
     7 *
     8 * Copyright (c) 2015 Paragon Initiative Enterprises
     9 *
     10 * Permission is hereby granted, free of charge, to any person obtaining a copy
     11 * of this software and associated documentation files (the "Software"), to deal
     12 * in the Software without restriction, including without limitation the rights
     13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     14 * copies of the Software, and to permit persons to whom the Software is
     15 * furnished to do so, subject to the following conditions:
     16 *
     17 * The above copyright notice and this permission notice shall be included in
     18 * all copies or substantial portions of the Software.
     19 *
     20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     26 * SOFTWARE.
     27 */
     28
     29if (!function_exists('random_bytes') && function_exists('openssl_random_pseudo_bytes')) {
     30    /**
     31     * Since openssl_random_pseudo_bytes() uses openssl's
     32     * RAND_pseudo_bytes() API, which has been marked as deprecated by the
     33     * OpenSSL team, this is our last resort before failure.
     34     *
     35     * @ref https://www.openssl.org/docs/crypto/RAND_bytes.html
     36     *
     37     * @param int $bytes
     38     *
     39     * @throws Exception
     40     *
     41     * @return string
     42     */
     43    function random_bytes($bytes)
     44    {
     45        if (!is_int($bytes)) {
     46            throw new TypeError(
     47                'Length must be an integer'
     48            );
     49        }
     50        if ($bytes < 1) {
     51            throw new Error(
     52                'Length must be greater than 0'
     53            );
     54        }
     55        $secure = true;
     56        /**
     57         * $secure is passed by reference. If it's set to false, fail. Note
     58         * that this will only return false if this function fails to return
     59         * any data.
     60         *
     61         * @ref https://github.com/paragonie/random_compat/issues/6#issuecomment-119564973
     62         */
     63        $buf = openssl_random_pseudo_bytes($bytes, $secure);
     64        if ($buf !== false && $secure) {
     65            if (RandomCompat_strlen($buf) === $bytes) {
     66                return $buf;
     67            }
     68        }
     69        /**
     70         * If we reach here, PHP has failed us.
     71         */
     72        throw new Exception(
     73            'PHP failed to generate random data.'
     74        );
     75    }
     76}
  • new file wp-includes/random_compat/random_int.php

    diff --git a/wp-includes/random_compat/random_int.php b/wp-includes/random_compat/random_int.php
    new file mode 100644
    index 0000000..807ff7a
    - +  
     1<?php
     2/**
     3 * Random_* Compatibility Library
     4 * for using the new PHP 7 random_* API in PHP 5 projects
     5 *
     6 * The MIT License (MIT)
     7 *
     8 * Copyright (c) 2015 Paragon Initiative Enterprises
     9 *
     10 * Permission is hereby granted, free of charge, to any person obtaining a copy
     11 * of this software and associated documentation files (the "Software"), to deal
     12 * in the Software without restriction, including without limitation the rights
     13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     14 * copies of the Software, and to permit persons to whom the Software is
     15 * furnished to do so, subject to the following conditions:
     16 *
     17 * The above copyright notice and this permission notice shall be included in
     18 * all copies or substantial portions of the Software.
     19 *
     20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     26 * SOFTWARE.
     27 */
     28
     29if (!function_exists('random_int')) {
     30    /**
     31     * Fetch a random integer between $min and $max inclusive
     32     *
     33     * @param int $min
     34     * @param int $max
     35     *
     36     * @throws Exception
     37     *
     38     * @return int
     39     */
     40    function random_int($min, $max)
     41    {
     42        /**
     43         * Type and input logic checks
     44         */
     45        if (!is_int($min)) {
     46            throw new TypeError(
     47                'random_int(): $min must be an integer'
     48            );
     49        }
     50        if (!is_int($max)) {
     51            throw new TypeError(
     52                'random_int(): $max must be an integer'
     53            );
     54        }
     55        if ($min > $max) {
     56            throw new Error(
     57                'Minimum value must be less than or equal to the maximum value'
     58            );
     59        }
     60        if ($max === $min) {
     61            return $min;
     62        }
     63
     64        /**
     65         * Initialize variables to 0
     66         *
     67         * We want to store:
     68         * $bytes => the number of random bytes we need
     69         * $mask => an integer bitmask (for use with the &) operator
     70         *          so we can minimize the number of discards
     71         */
     72        $attempts = $bits = $bytes = $mask = $valueShift = 0;
     73
     74        /**
     75         * At this point, $range is a positive number greater than 0. It might
     76         * overflow, however, if $max - $min > PHP_INT_MAX. PHP will cast it to
     77         * a float and we will lose some precision.
     78         */
     79        $range = $max - $min;
     80
     81        /**
     82         * Test for integer overflow:
     83         */
     84        if (!is_int($range)) {
     85            /**
     86             * Still safely calculate wider ranges.
     87             * Provided by @CodesInChaos, @oittaa
     88             *
     89             * @ref https://gist.github.com/CodesInChaos/03f9ea0b58e8b2b8d435
     90             *
     91             * We use ~0 as a mask in this case because it generates all 1s
     92             *
     93             * @ref https://eval.in/400356 (32-bit)
     94             * @ref http://3v4l.org/XX9r5  (64-bit)
     95             */
     96            $bytes = PHP_INT_SIZE;
     97            $mask = ~0;
     98        } else {
     99            /**
     100             * $bits is effectively ceil(log($range, 2)) without dealing with
     101             * type juggling
     102             */
     103            while ($range > 0) {
     104                if ($bits % 8 === 0) {
     105                   ++$bytes;
     106                }
     107                ++$bits;
     108                $range >>= 1;
     109                $mask = $mask << 1 | 1;
     110            }
     111            $valueShift = $min;
     112        }
     113
     114        /**
     115         * Now that we have our parameters set up, let's begin generating
     116         * random integers until one falls between $min and $max
     117         */
     118        do {
     119            /**
     120             * The rejection probability is at most 0.5, so this corresponds
     121             * to a failure probability of 2^-128 for a working RNG
     122             */
     123            if ($attempts > 128) {
     124                throw new Exception(
     125                    'random_int: RNG is broken - too many rejections'
     126                );
     127            }
     128           
     129            /**
     130             * Let's grab the necessary number of random bytes
     131             */
     132            $randomByteString = random_bytes($bytes);
     133            if ($randomByteString === false) {
     134                throw new Exception(
     135                    'Random number generator failure'
     136                );
     137            }
     138
     139            /**
     140             * Let's turn $randomByteString into an integer
     141             *
     142             * This uses bitwise operators (<< and |) to build an integer
     143             * out of the values extracted from ord()
     144             *
     145             * Example: [9F] | [6D] | [32] | [0C] =>
     146             *   159 + 27904 + 3276800 + 201326592 =>
     147             *   204631455
     148             */
     149            $val = 0;
     150            for ($i = 0; $i < $bytes; ++$i) {
     151                $val |= ord($randomByteString[$i]) << ($i * 8);
     152            }
     153
     154            /**
     155             * Apply mask
     156             */
     157            $val &= $mask;
     158            $val += $valueShift;
     159
     160            ++$attempts;
     161            /**
     162             * If $val overflows to a floating point number,
     163             * ... or is larger than $max,
     164             * ... or smaller than $int,
     165             * then try again.
     166             */
     167        } while (!is_int($val) || $val > $max || $val < $min);
     168        return (int) $val;
     169    }
     170}
  • wp-settings.php

    diff --git a/wp-settings.php b/wp-settings.php
    index 993a120..9ba189c 100644
    a b require( ABSPATH . WPINC . '/nav-menu.php' ); 
    153153require( ABSPATH . WPINC . '/nav-menu-template.php' );
    154154require( ABSPATH . WPINC . '/admin-bar.php' );
    155155
     156// random_compat
     157require( ABSPATH . WPINC . '/random_compat/random.php' );
     158
    156159// Load multisite-specific files.
    157160if ( is_multisite() ) {
    158161        require( ABSPATH . WPINC . '/ms-functions.php' );