PluginProbe
ManageWP Worker / 3.9.28
ManageWP Worker v3.9.28
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 / lib / PHPSecLib / Crypt / Random.php

Random.php in ManageWP Worker 3.9.28, at lib/PHPSecLib/Crypt/Random.php

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