diff options
author | plegall <plg@piwigo.org> | 2016-04-26 11:07:44 +0200 |
---|---|---|
committer | plegall <plg@piwigo.org> | 2016-04-26 11:07:44 +0200 |
commit | f51ee90c66527fd7ff634f3e8d414cb670da068d (patch) | |
tree | 2550f0753f14ed594dbf99cb65675fa02b49fe21 /include/random_compat/random.php | |
parent | a3c46de7511cb5b66f59375d225b1f0fb66ae988 (diff) |
bug #470, use a dedicated lib to generate random bytes
Diffstat (limited to '')
-rw-r--r-- | include/random_compat/random.php | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/include/random_compat/random.php b/include/random_compat/random.php new file mode 100644 index 000000000..a8802597d --- /dev/null +++ b/include/random_compat/random.php @@ -0,0 +1,197 @@ +<?php +/** + * Random_* Compatibility Library + * for using the new PHP 7 random_* API in PHP 5 projects + * + * @version 2.0.2 + * @released 2016-04-03 + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Paragon Initiative Enterprises + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +if (!defined('PHP_VERSION_ID')) { + // This constant was introduced in PHP 5.2.7 + $RandomCompatversion = explode('.', PHP_VERSION); + define( + 'PHP_VERSION_ID', + $RandomCompatversion[0] * 10000 + + $RandomCompatversion[1] * 100 + + $RandomCompatversion[2] + ); + $RandomCompatversion = null; +} + +if (PHP_VERSION_ID < 70000) { + + if (!defined('RANDOM_COMPAT_READ_BUFFER')) { + define('RANDOM_COMPAT_READ_BUFFER', 8); + } + + $RandomCompatDIR = dirname(__FILE__); + + require_once $RandomCompatDIR.'/byte_safe_strings.php'; + require_once $RandomCompatDIR.'/cast_to_int.php'; + require_once $RandomCompatDIR.'/error_polyfill.php'; + + if (!function_exists('random_bytes')) { + /** + * PHP 5.2.0 - 5.6.x way to implement random_bytes() + * + * We use conditional statements here to define the function in accordance + * to the operating environment. It's a micro-optimization. + * + * In order of preference: + * 1. Use libsodium if available. + * 2. fread() /dev/urandom if available (never on Windows) + * 3. mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM) + * 4. COM('CAPICOM.Utilities.1')->GetRandom() + * 5. openssl_random_pseudo_bytes() (absolute last resort) + * + * See ERRATA.md for our reasoning behind this particular order + */ + if (extension_loaded('libsodium')) { + // See random_bytes_libsodium.php + if (PHP_VERSION_ID >= 50300 && function_exists('\\Sodium\\randombytes_buf')) { + require_once $RandomCompatDIR.'/random_bytes_libsodium.php'; + } elseif (method_exists('Sodium', 'randombytes_buf')) { + require_once $RandomCompatDIR.'/random_bytes_libsodium_legacy.php'; + } + } + + /** + * Reading directly from /dev/urandom: + */ + if (DIRECTORY_SEPARATOR === '/') { + // DIRECTORY_SEPARATOR === '/' on Unix-like OSes -- this is a fast + // way to exclude Windows. + $RandomCompatUrandom = true; + $RandomCompat_basedir = ini_get('open_basedir'); + + if (!empty($RandomCompat_basedir)) { + $RandomCompat_open_basedir = explode( + PATH_SEPARATOR, + strtolower($RandomCompat_basedir) + ); + $RandomCompatUrandom = (array() !== array_intersect( + array('/dev', '/dev/', '/dev/urandom'), + $RandomCompat_open_basedir + )); + $RandomCompat_open_basedir = null; + } + + if ( + !function_exists('random_bytes') + && + $RandomCompatUrandom + && + @is_readable('/dev/urandom') + ) { + // Error suppression on is_readable() in case of an open_basedir + // or safe_mode failure. All we care about is whether or not we + // can read it at this point. If the PHP environment is going to + // panic over trying to see if the file can be read in the first + // place, that is not helpful to us here. + + // See random_bytes_dev_urandom.php + require_once $RandomCompatDIR.'/random_bytes_dev_urandom.php'; + } + // Unset variables after use + $RandomCompat_basedir = null; + } else { + $RandomCompatUrandom = false; + } + + /** + * mcrypt_create_iv() + */ + if ( + !function_exists('random_bytes') + && + PHP_VERSION_ID >= 50307 + && + extension_loaded('mcrypt') + && + (DIRECTORY_SEPARATOR !== '/' || $RandomCompatUrandom) + ) { + // Prevent this code from hanging indefinitely on non-Windows; + // see https://bugs.php.net/bug.php?id=69833 + if ( + DIRECTORY_SEPARATOR !== '/' || + (PHP_VERSION_ID <= 50609 || PHP_VERSION_ID >= 50613) + ) { + // See random_bytes_mcrypt.php + require_once $RandomCompatDIR.'/random_bytes_mcrypt.php'; + } + } + $RandomCompatUrandom = null; + + if ( + !function_exists('random_bytes') + && + extension_loaded('com_dotnet') + && + class_exists('COM') + ) { + $RandomCompat_disabled_classes = preg_split( + '#\s*,\s*#', + strtolower(ini_get('disable_classes')) + ); + + if (!in_array('com', $RandomCompat_disabled_classes)) { + try { + $RandomCompatCOMtest = new COM('CAPICOM.Utilities.1'); + if (method_exists($RandomCompatCOMtest, 'GetRandom')) { + // See random_bytes_com_dotnet.php + require_once $RandomCompatDIR.'/random_bytes_com_dotnet.php'; + } + } catch (com_exception $e) { + // Don't try to use it. + } + } + $RandomCompat_disabled_classes = null; + $RandomCompatCOMtest = null; + } + + /** + * throw new Exception + */ + if (!function_exists('random_bytes')) { + /** + * We don't have any more options, so let's throw an exception right now + * and hope the developer won't let it fail silently. + */ + function random_bytes($length) + { + throw new Exception( + 'There is no suitable CSPRNG installed on your system' + ); + } + } + } + + if (!function_exists('random_int')) { + require_once $RandomCompatDIR.'/random_int.php'; + } + + $RandomCompatDIR = null; +} |