annotate vendor/paragonie/random_compat/lib/random.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents c2387f117808
children
rev   line source
Chris@0 1 <?php
Chris@0 2 /**
Chris@0 3 * Random_* Compatibility Library
Chris@0 4 * for using the new PHP 7 random_* API in PHP 5 projects
Chris@0 5 *
Chris@16 6 * @version 2.0.17
Chris@16 7 * @released 2018-07-04
Chris@0 8 *
Chris@0 9 * The MIT License (MIT)
Chris@0 10 *
Chris@16 11 * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
Chris@0 12 *
Chris@0 13 * Permission is hereby granted, free of charge, to any person obtaining a copy
Chris@0 14 * of this software and associated documentation files (the "Software"), to deal
Chris@0 15 * in the Software without restriction, including without limitation the rights
Chris@0 16 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Chris@0 17 * copies of the Software, and to permit persons to whom the Software is
Chris@0 18 * furnished to do so, subject to the following conditions:
Chris@0 19 *
Chris@0 20 * The above copyright notice and this permission notice shall be included in
Chris@0 21 * all copies or substantial portions of the Software.
Chris@0 22 *
Chris@0 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Chris@0 24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Chris@0 25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Chris@0 26 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Chris@0 27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Chris@0 28 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Chris@0 29 * SOFTWARE.
Chris@0 30 */
Chris@0 31
Chris@0 32 if (!defined('PHP_VERSION_ID')) {
Chris@0 33 // This constant was introduced in PHP 5.2.7
Chris@0 34 $RandomCompatversion = array_map('intval', explode('.', PHP_VERSION));
Chris@0 35 define(
Chris@0 36 'PHP_VERSION_ID',
Chris@0 37 $RandomCompatversion[0] * 10000
Chris@0 38 + $RandomCompatversion[1] * 100
Chris@0 39 + $RandomCompatversion[2]
Chris@0 40 );
Chris@0 41 $RandomCompatversion = null;
Chris@0 42 }
Chris@0 43
Chris@0 44 /**
Chris@0 45 * PHP 7.0.0 and newer have these functions natively.
Chris@0 46 */
Chris@0 47 if (PHP_VERSION_ID >= 70000) {
Chris@0 48 return;
Chris@0 49 }
Chris@0 50
Chris@0 51 if (!defined('RANDOM_COMPAT_READ_BUFFER')) {
Chris@0 52 define('RANDOM_COMPAT_READ_BUFFER', 8);
Chris@0 53 }
Chris@0 54
Chris@0 55 $RandomCompatDIR = dirname(__FILE__);
Chris@0 56
Chris@16 57 require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'byte_safe_strings.php';
Chris@16 58 require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'cast_to_int.php';
Chris@16 59 require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'error_polyfill.php';
Chris@0 60
Chris@0 61 if (!is_callable('random_bytes')) {
Chris@0 62 /**
Chris@0 63 * PHP 5.2.0 - 5.6.x way to implement random_bytes()
Chris@0 64 *
Chris@0 65 * We use conditional statements here to define the function in accordance
Chris@0 66 * to the operating environment. It's a micro-optimization.
Chris@0 67 *
Chris@0 68 * In order of preference:
Chris@0 69 * 1. Use libsodium if available.
Chris@0 70 * 2. fread() /dev/urandom if available (never on Windows)
Chris@0 71 * 3. mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM)
Chris@0 72 * 4. COM('CAPICOM.Utilities.1')->GetRandom()
Chris@0 73 *
Chris@0 74 * See RATIONALE.md for our reasoning behind this particular order
Chris@0 75 */
Chris@0 76 if (extension_loaded('libsodium')) {
Chris@0 77 // See random_bytes_libsodium.php
Chris@0 78 if (PHP_VERSION_ID >= 50300 && is_callable('\\Sodium\\randombytes_buf')) {
Chris@16 79 require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium.php';
Chris@0 80 } elseif (method_exists('Sodium', 'randombytes_buf')) {
Chris@16 81 require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium_legacy.php';
Chris@0 82 }
Chris@0 83 }
Chris@0 84
Chris@0 85 /**
Chris@0 86 * Reading directly from /dev/urandom:
Chris@0 87 */
Chris@0 88 if (DIRECTORY_SEPARATOR === '/') {
Chris@0 89 // DIRECTORY_SEPARATOR === '/' on Unix-like OSes -- this is a fast
Chris@0 90 // way to exclude Windows.
Chris@0 91 $RandomCompatUrandom = true;
Chris@0 92 $RandomCompat_basedir = ini_get('open_basedir');
Chris@0 93
Chris@0 94 if (!empty($RandomCompat_basedir)) {
Chris@0 95 $RandomCompat_open_basedir = explode(
Chris@0 96 PATH_SEPARATOR,
Chris@0 97 strtolower($RandomCompat_basedir)
Chris@0 98 );
Chris@0 99 $RandomCompatUrandom = (array() !== array_intersect(
Chris@0 100 array('/dev', '/dev/', '/dev/urandom'),
Chris@0 101 $RandomCompat_open_basedir
Chris@0 102 ));
Chris@0 103 $RandomCompat_open_basedir = null;
Chris@0 104 }
Chris@0 105
Chris@0 106 if (
Chris@0 107 !is_callable('random_bytes')
Chris@0 108 &&
Chris@0 109 $RandomCompatUrandom
Chris@0 110 &&
Chris@0 111 @is_readable('/dev/urandom')
Chris@0 112 ) {
Chris@0 113 // Error suppression on is_readable() in case of an open_basedir
Chris@0 114 // or safe_mode failure. All we care about is whether or not we
Chris@0 115 // can read it at this point. If the PHP environment is going to
Chris@0 116 // panic over trying to see if the file can be read in the first
Chris@0 117 // place, that is not helpful to us here.
Chris@0 118
Chris@0 119 // See random_bytes_dev_urandom.php
Chris@16 120 require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_dev_urandom.php';
Chris@0 121 }
Chris@0 122 // Unset variables after use
Chris@0 123 $RandomCompat_basedir = null;
Chris@0 124 } else {
Chris@0 125 $RandomCompatUrandom = false;
Chris@0 126 }
Chris@0 127
Chris@0 128 /**
Chris@0 129 * mcrypt_create_iv()
Chris@0 130 *
Chris@0 131 * We only want to use mcypt_create_iv() if:
Chris@0 132 *
Chris@0 133 * - random_bytes() hasn't already been defined
Chris@0 134 * - the mcrypt extensions is loaded
Chris@0 135 * - One of these two conditions is true:
Chris@0 136 * - We're on Windows (DIRECTORY_SEPARATOR !== '/')
Chris@0 137 * - We're not on Windows and /dev/urandom is readabale
Chris@0 138 * (i.e. we're not in a chroot jail)
Chris@0 139 * - Special case:
Chris@0 140 * - If we're not on Windows, but the PHP version is between
Chris@0 141 * 5.6.10 and 5.6.12, we don't want to use mcrypt. It will
Chris@0 142 * hang indefinitely. This is bad.
Chris@0 143 * - If we're on Windows, we want to use PHP >= 5.3.7 or else
Chris@0 144 * we get insufficient entropy errors.
Chris@0 145 */
Chris@0 146 if (
Chris@0 147 !is_callable('random_bytes')
Chris@0 148 &&
Chris@0 149 // Windows on PHP < 5.3.7 is broken, but non-Windows is not known to be.
Chris@0 150 (DIRECTORY_SEPARATOR === '/' || PHP_VERSION_ID >= 50307)
Chris@0 151 &&
Chris@0 152 // Prevent this code from hanging indefinitely on non-Windows;
Chris@0 153 // see https://bugs.php.net/bug.php?id=69833
Chris@0 154 (
Chris@0 155 DIRECTORY_SEPARATOR !== '/' ||
Chris@0 156 (PHP_VERSION_ID <= 50609 || PHP_VERSION_ID >= 50613)
Chris@0 157 )
Chris@0 158 &&
Chris@0 159 extension_loaded('mcrypt')
Chris@0 160 ) {
Chris@0 161 // See random_bytes_mcrypt.php
Chris@16 162 require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_mcrypt.php';
Chris@0 163 }
Chris@0 164 $RandomCompatUrandom = null;
Chris@0 165
Chris@0 166 /**
Chris@0 167 * This is a Windows-specific fallback, for when the mcrypt extension
Chris@0 168 * isn't loaded.
Chris@0 169 */
Chris@0 170 if (
Chris@0 171 !is_callable('random_bytes')
Chris@0 172 &&
Chris@0 173 extension_loaded('com_dotnet')
Chris@0 174 &&
Chris@0 175 class_exists('COM')
Chris@0 176 ) {
Chris@0 177 $RandomCompat_disabled_classes = preg_split(
Chris@0 178 '#\s*,\s*#',
Chris@0 179 strtolower(ini_get('disable_classes'))
Chris@0 180 );
Chris@0 181
Chris@0 182 if (!in_array('com', $RandomCompat_disabled_classes)) {
Chris@0 183 try {
Chris@0 184 $RandomCompatCOMtest = new COM('CAPICOM.Utilities.1');
Chris@0 185 if (method_exists($RandomCompatCOMtest, 'GetRandom')) {
Chris@0 186 // See random_bytes_com_dotnet.php
Chris@16 187 require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_com_dotnet.php';
Chris@0 188 }
Chris@0 189 } catch (com_exception $e) {
Chris@0 190 // Don't try to use it.
Chris@0 191 }
Chris@0 192 }
Chris@0 193 $RandomCompat_disabled_classes = null;
Chris@0 194 $RandomCompatCOMtest = null;
Chris@0 195 }
Chris@0 196
Chris@0 197 /**
Chris@0 198 * throw new Exception
Chris@0 199 */
Chris@0 200 if (!is_callable('random_bytes')) {
Chris@0 201 /**
Chris@0 202 * We don't have any more options, so let's throw an exception right now
Chris@0 203 * and hope the developer won't let it fail silently.
Chris@0 204 *
Chris@0 205 * @param mixed $length
Chris@16 206 * @psalm-suppress InvalidReturnType
Chris@0 207 * @throws Exception
Chris@13 208 * @return string
Chris@0 209 */
Chris@0 210 function random_bytes($length)
Chris@0 211 {
Chris@0 212 unset($length); // Suppress "variable not used" warnings.
Chris@0 213 throw new Exception(
Chris@0 214 'There is no suitable CSPRNG installed on your system'
Chris@0 215 );
Chris@13 216 return '';
Chris@0 217 }
Chris@0 218 }
Chris@0 219 }
Chris@0 220
Chris@0 221 if (!is_callable('random_int')) {
Chris@16 222 require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_int.php';
Chris@0 223 }
Chris@0 224
Chris@0 225 $RandomCompatDIR = null;