PluginProbe
ManageWP Worker / 4.9.25
ManageWP Worker v4.9.25
4.9.38 4.9.37 4.9.36 4.9.35 4.9.34 3.8.7 3.8.8 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.18 3.9.19 3.9.2 3.9.20 3.9.21 3.9.22 3.9.23 3.9.24 All 73 releases
worker / src / PHPSecLib / Crypt / Random.php

Random.php in ManageWP Worker 4.9.25, at src/PHPSecLib/Crypt/Random.php

323 lines 14.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Random Number Generator
5 *
6 * The idea behind this function is that it can be easily replaced with your own crypt_random_string()
7 * function. eg. maybe you have a better source of entropy for creating the initial states or whatever.
8 *
9 * PHP versions 4 and 5
10 *
11 * Here's a short example of how to use this library:
12 * <code>
13 * <?php
14 * include 'Crypt/Random.php';
15 *
16 * echo bin2hex(crypt_random_string(8));
17 * ?>
18 * </code>
19 *
20 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
21 * of this software and associated documentation files (the "Software"), to deal
22 * in the Software without restriction, including without limitation the rights
23 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24 * copies of the Software, and to permit persons to whom the Software is
25 * furnished to do so, subject to the following conditions:
26 *
27 * The above copyright notice and this permission notice shall be included in
28 * all copies or substantial portions of the Software.
29 *
30 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
36 * THE SOFTWARE.
37 *
38 * @category Crypt
39 * @package Crypt_Random
40 * @author Jim Wigginton <terrafrost@php.net>
41 * @copyright MMVII Jim Wigginton
42 * @license http://www.opensource.org/licenses/mit-license.html MIT License
43 * @link http://phpseclib.sourceforge.net
44 */
45
46 // laravel is a PHP framework that utilizes phpseclib. laravel workbenches may, independently,
47 // have phpseclib as a requirement as well. if you're developing such a program you may encounter
48 // a "Cannot redeclare crypt_random_string()" error.
49 if (!function_exists('crypt_random_string')) {
50 /**
51 * "Is Windows" test
52 *
53 * @access private
54 */
55 define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
56
57 /**
58 * Generate a random string.
59 *
60 * Although microoptimizations are generally discouraged as they impair readability this function is ripe with
61 * microoptimizations because this function has the potential of being called a huge number of times.
62 * eg. for RSA key generation.
63 *
64 * @param Integer $length
65 *
66 * @return String
67 * @access public
68 */
69 function crypt_random_string($length)
70 {
71 if (CRYPT_RANDOM_IS_WINDOWS) {
72 // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
73 // ie. class_alias is a function that was introduced in PHP 5.3
74 if (version_compare(PHP_VERSION, '5.3.6', '!=') && function_exists('mcrypt_create_iv') && function_exists('class_alias')) {
75 return mcrypt_create_iv($length);
76 }
77 // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
78 // to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4
79 // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
80 // call php_win32_get_random_bytes():
81 //
82 // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
83 // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
84 //
85 // php_win32_get_random_bytes() is defined thusly:
86 //
87 // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
88 //
89 // we're calling it, all the same, in the off chance that the mcrypt extension is not available
90 if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
91 return openssl_random_pseudo_bytes($length);
92 }
93 } else {
94 // method 1. the fastest
95 if (function_exists('openssl_random_pseudo_bytes')) {
96 return openssl_random_pseudo_bytes($length);
97 }
98 // method 2
99 static $fp = true;
100 if ($fp === true) {
101 // warning's will be output unles the error suppression operator is used. errors such as
102 // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
103 $fp = @fopen('/dev/urandom', 'rb');
104 }
105 if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
106 return fread($fp, $length);
107 }
108 // method 3. pretty much does the same thing as method 2 per the following url:
109 // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
110 // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
111 // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
112 // restrictions or some such
113 if (function_exists('mcrypt_create_iv')) {
114 return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
115 }
116 }
117 // at this point we have no choice but to use a pure-PHP CSPRNG
118
119 // cascade entropy across multiple PHP instances by fixing the session and collecting all
120 // environmental variables, including the previous session data and the current session
121 // data.
122 //
123 // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
124 // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
125 // PHP isn't low level to be able to use those as sources and on a web server there's not likely
126 // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
127 // however, a ton of people visiting the website. obviously you don't want to base your seeding
128 // soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
129 // by the user and (2) this isn't just looking at the data sent by the current user - it's based
130 // on the data sent by all users. one user requests the page and a hash of their info is saved.
131 // another user visits the page and the serialization of their data is utilized along with the
132 // server envirnment stuff and a hash of the previous http request data (which itself utilizes
133 // a hash of the session data before that). certainly an attacker should be assumed to have
134 // full control over his own http requests. he, however, is not going to have control over
135 // everyone's http requests.
136 static $crypto = false, $v;
137 if ($crypto === false) {
138 // save old session data
139 $old_session_id = session_id();
140 $old_use_cookies = ini_get('session.use_cookies');
141 $old_session_cache_limiter = session_cache_limiter();
142 $_OLD_SESSION = isset($_SESSION) ? $_SESSION : false;
143 if ($old_session_id != '') {
144 session_write_close();
145 }
146
147 session_id(1);
148 ini_set('session.use_cookies', 0);
149 session_cache_limiter('');
150 session_start();
151
152 $v = $seed = $_SESSION['seed'] = pack('H*', sha1(
153 serialize($_SERVER).
154 serialize($_POST).
155 serialize($_GET).
156 serialize($_COOKIE).
157 serialize($_SESSION).
158 serialize($_OLD_SESSION)
159 ));
160 if (!isset($_SESSION['count'])) {
161 $_SESSION['count'] = 0;
162 }
163 $_SESSION['count']++;
164
165 session_write_close();
166
167 // restore old session data
168 if ($old_session_id != '') {
169 session_id($old_session_id);
170 session_start();
171 ini_set('session.use_cookies', $old_use_cookies);
172 session_cache_limiter($old_session_cache_limiter);
173 } else {
174 if ($_OLD_SESSION !== false) {
175 $_SESSION = $_OLD_SESSION;
176 unset($_OLD_SESSION);
177 } else {
178 unset($_SESSION);
179 }
180 }
181
182 // in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
183 // the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C.
184 // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
185 // original hash and the current hash. we'll be emulating that. for more info see the following URL:
186 //
187 // http://tools.ietf.org/html/rfc4253#section-7.2
188 //
189 // see the is_string($crypto) part for an example of how to expand the keys
190 $key = pack('H*', sha1($seed.'A'));
191 $iv = pack('H*', sha1($seed.'C'));
192
193 // ciphers are used as per the nist.gov link below. also, see this link:
194 //
195 // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
196 switch (true) {
197 case mwp_phpseclib_resolve_include_path('Crypt/AES.php'):
198 if (!class_exists('Crypt_AES')) {
199 require_once dirname(__FILE__).'/AES.php';
200 }
201 $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
202 break;
203 case mwp_phpseclib_resolve_include_path('Crypt/Twofish.php'):
204 if (!class_exists('Crypt_Twofish')) {
205 require_once dirname(__FILE__).'/Twofish.php';
206 }
207 $crypto = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR);
208 break;
209 case mwp_phpseclib_resolve_include_path('Crypt/Blowfish.php'):
210 if (!class_exists('Crypt_Blowfish')) {
211 require_once dirname(__FILE__).'/Blowfish.php';
212 }
213 $crypto = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR);
214 break;
215 case mwp_phpseclib_resolve_include_path('Crypt/TripleDES.php'):
216 if (!class_exists('Crypt_TripleDES')) {
217 require_once dirname(__FILE__).'/TripleDES.php';
218 }
219 $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
220 break;
221 case mwp_phpseclib_resolve_include_path('Crypt/DES.php'):
222 if (!class_exists('Crypt_DES')) {
223 require_once dirname(__FILE__).'/DES.php';
224 }
225 $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
226 break;
227 case mwp_phpseclib_resolve_include_path('Crypt/RC4.php'):
228 if (!class_exists('Crypt_RC4')) {
229 require_once dirname(__FILE__).'/RC4.php';
230 }
231 $crypto = new Crypt_RC4();
232 break;
233 default:
234 user_error('crypt_random_string requires at least one symmetric cipher be loaded');
235
236 return false;
237 }
238
239 $crypto->setKey($key);
240 $crypto->setIV($iv);
241 $crypto->enableContinuousBuffer();
242 }
243
244 //return $crypto->encrypt(str_repeat("\0", $length));
245
246 // the following is based off of ANSI X9.31:
247 //
248 // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
249 //
250 // OpenSSL uses that same standard for it's random numbers:
251 //
252 // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
253 // (do a search for "ANS X9.31 A.2.4")
254 $result = '';
255 while (strlen($result) < $length) {
256 $i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21
257 $r = $crypto->encrypt($i ^ $v); // strlen($v) == 20
258 $v = $crypto->encrypt($r ^ $i); // strlen($r) == 20
259 $result .= $r;
260 }
261
262 return substr($result, 0, $length);
263 }
264 }
265
266 if (!function_exists('phpseclib_resolve_include_path')) {
267 /**
268 * Resolve filename against the include path.
269 *
270 * Wrapper around stream_resolve_include_path() (which was introduced in
271 * PHP 5.3.2) with fallback implementation for earlier PHP versions.
272 *
273 * @param string $filename
274 *
275 * @return mixed Filename (string) on success, false otherwise.
276 * @access public
277 */
278 function phpseclib_resolve_include_path($filename)
279 {
280 if (function_exists('stream_resolve_include_path')) {
281 return stream_resolve_include_path($filename);
282 }
283
284 // handle non-relative paths
285 if (file_exists($filename)) {
286 return realpath($filename);
287 }
288
289 $paths = PATH_SEPARATOR == ':' ?
290 preg_split('#(?<!phar):#', get_include_path()) :
291 explode(PATH_SEPARATOR, get_include_path());
292 foreach ($paths as $prefix) {
293 // path's specified in include_path don't always end in /
294 $ds = substr($prefix, -1) == DIRECTORY_SEPARATOR ? '' : DIRECTORY_SEPARATOR;
295 $file = $prefix.$ds.$filename;
296 if (file_exists($file)) {
297 return realpath($file);
298 }
299 }
300
301 return false;
302 }
303 }
304
305 if (!function_exists('mwp_phpseclib_resolve_include_path')) {
306 /**
307 * We don't rely on include_path or PHAR, so support only one option.
308 *
309 * @param string $filename
310 *
311 * @return mixed Filename (string) on success, false otherwise.
312 * @access public
313 */
314 function mwp_phpseclib_resolve_include_path($filename)
315 {
316 if (file_exists(dirname(__FILE__).'/../'.$filename)) {
317 return realpath(dirname(__FILE__).'/../'.$filename);
318 }
319
320 return false;
321 }
322 }
323