Chris@0: = 70000) { Chris@0: return; Chris@0: } Chris@0: Chris@0: if (!defined('RANDOM_COMPAT_READ_BUFFER')) { Chris@0: define('RANDOM_COMPAT_READ_BUFFER', 8); Chris@0: } Chris@0: Chris@0: $RandomCompatDIR = dirname(__FILE__); Chris@0: Chris@16: require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'byte_safe_strings.php'; Chris@16: require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'cast_to_int.php'; Chris@16: require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'error_polyfill.php'; Chris@0: Chris@0: if (!is_callable('random_bytes')) { Chris@0: /** Chris@0: * PHP 5.2.0 - 5.6.x way to implement random_bytes() Chris@0: * Chris@0: * We use conditional statements here to define the function in accordance Chris@0: * to the operating environment. It's a micro-optimization. Chris@0: * Chris@0: * In order of preference: Chris@0: * 1. Use libsodium if available. Chris@0: * 2. fread() /dev/urandom if available (never on Windows) Chris@0: * 3. mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM) Chris@0: * 4. COM('CAPICOM.Utilities.1')->GetRandom() Chris@0: * Chris@0: * See RATIONALE.md for our reasoning behind this particular order Chris@0: */ Chris@0: if (extension_loaded('libsodium')) { Chris@0: // See random_bytes_libsodium.php Chris@0: if (PHP_VERSION_ID >= 50300 && is_callable('\\Sodium\\randombytes_buf')) { Chris@16: require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium.php'; Chris@0: } elseif (method_exists('Sodium', 'randombytes_buf')) { Chris@16: require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium_legacy.php'; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Reading directly from /dev/urandom: Chris@0: */ Chris@0: if (DIRECTORY_SEPARATOR === '/') { Chris@0: // DIRECTORY_SEPARATOR === '/' on Unix-like OSes -- this is a fast Chris@0: // way to exclude Windows. Chris@0: $RandomCompatUrandom = true; Chris@0: $RandomCompat_basedir = ini_get('open_basedir'); Chris@0: Chris@0: if (!empty($RandomCompat_basedir)) { Chris@0: $RandomCompat_open_basedir = explode( Chris@0: PATH_SEPARATOR, Chris@0: strtolower($RandomCompat_basedir) Chris@0: ); Chris@0: $RandomCompatUrandom = (array() !== array_intersect( Chris@0: array('/dev', '/dev/', '/dev/urandom'), Chris@0: $RandomCompat_open_basedir Chris@0: )); Chris@0: $RandomCompat_open_basedir = null; Chris@0: } Chris@0: Chris@0: if ( Chris@0: !is_callable('random_bytes') Chris@0: && Chris@0: $RandomCompatUrandom Chris@0: && Chris@0: @is_readable('/dev/urandom') Chris@0: ) { Chris@0: // Error suppression on is_readable() in case of an open_basedir Chris@0: // or safe_mode failure. All we care about is whether or not we Chris@0: // can read it at this point. If the PHP environment is going to Chris@0: // panic over trying to see if the file can be read in the first Chris@0: // place, that is not helpful to us here. Chris@0: Chris@0: // See random_bytes_dev_urandom.php Chris@16: require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_dev_urandom.php'; Chris@0: } Chris@0: // Unset variables after use Chris@0: $RandomCompat_basedir = null; Chris@0: } else { Chris@0: $RandomCompatUrandom = false; Chris@0: } Chris@0: Chris@0: /** Chris@0: * mcrypt_create_iv() Chris@0: * Chris@0: * We only want to use mcypt_create_iv() if: Chris@0: * Chris@0: * - random_bytes() hasn't already been defined Chris@0: * - the mcrypt extensions is loaded Chris@0: * - One of these two conditions is true: Chris@0: * - We're on Windows (DIRECTORY_SEPARATOR !== '/') Chris@0: * - We're not on Windows and /dev/urandom is readabale Chris@0: * (i.e. we're not in a chroot jail) Chris@0: * - Special case: Chris@0: * - If we're not on Windows, but the PHP version is between Chris@0: * 5.6.10 and 5.6.12, we don't want to use mcrypt. It will Chris@0: * hang indefinitely. This is bad. Chris@0: * - If we're on Windows, we want to use PHP >= 5.3.7 or else Chris@0: * we get insufficient entropy errors. Chris@0: */ Chris@0: if ( Chris@0: !is_callable('random_bytes') Chris@0: && Chris@0: // Windows on PHP < 5.3.7 is broken, but non-Windows is not known to be. Chris@0: (DIRECTORY_SEPARATOR === '/' || PHP_VERSION_ID >= 50307) Chris@0: && Chris@0: // Prevent this code from hanging indefinitely on non-Windows; Chris@0: // see https://bugs.php.net/bug.php?id=69833 Chris@0: ( Chris@0: DIRECTORY_SEPARATOR !== '/' || Chris@0: (PHP_VERSION_ID <= 50609 || PHP_VERSION_ID >= 50613) Chris@0: ) Chris@0: && Chris@0: extension_loaded('mcrypt') Chris@0: ) { Chris@0: // See random_bytes_mcrypt.php Chris@16: require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_mcrypt.php'; Chris@0: } Chris@0: $RandomCompatUrandom = null; Chris@0: Chris@0: /** Chris@0: * This is a Windows-specific fallback, for when the mcrypt extension Chris@0: * isn't loaded. Chris@0: */ Chris@0: if ( Chris@0: !is_callable('random_bytes') Chris@0: && Chris@0: extension_loaded('com_dotnet') Chris@0: && Chris@0: class_exists('COM') Chris@0: ) { Chris@0: $RandomCompat_disabled_classes = preg_split( Chris@0: '#\s*,\s*#', Chris@0: strtolower(ini_get('disable_classes')) Chris@0: ); Chris@0: Chris@0: if (!in_array('com', $RandomCompat_disabled_classes)) { Chris@0: try { Chris@0: $RandomCompatCOMtest = new COM('CAPICOM.Utilities.1'); Chris@0: if (method_exists($RandomCompatCOMtest, 'GetRandom')) { Chris@0: // See random_bytes_com_dotnet.php Chris@16: require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_com_dotnet.php'; Chris@0: } Chris@0: } catch (com_exception $e) { Chris@0: // Don't try to use it. Chris@0: } Chris@0: } Chris@0: $RandomCompat_disabled_classes = null; Chris@0: $RandomCompatCOMtest = null; Chris@0: } Chris@0: Chris@0: /** Chris@0: * throw new Exception Chris@0: */ Chris@0: if (!is_callable('random_bytes')) { Chris@0: /** Chris@0: * We don't have any more options, so let's throw an exception right now Chris@0: * and hope the developer won't let it fail silently. Chris@0: * Chris@0: * @param mixed $length Chris@16: * @psalm-suppress InvalidReturnType Chris@0: * @throws Exception Chris@13: * @return string Chris@0: */ Chris@0: function random_bytes($length) Chris@0: { Chris@0: unset($length); // Suppress "variable not used" warnings. Chris@0: throw new Exception( Chris@0: 'There is no suitable CSPRNG installed on your system' Chris@0: ); Chris@13: return ''; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: if (!is_callable('random_int')) { Chris@16: require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_int.php'; Chris@0: } Chris@0: Chris@0: $RandomCompatDIR = null;