You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

218 lines
7.5 KiB

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