├── .gitignore
├── LICENSE
├── README.md
├── clientarea.tpl
├── docs
└── img
│ ├── administrator_area.png
│ └── user_area.png
├── lib
└── phpseclib104
│ ├── Crypt
│ ├── Base.php
│ ├── Hash.php
│ ├── RSA.php
│ └── Random.php
│ ├── File
│ ├── ANSI.php
│ ├── ASN1.php
│ └── X509.php
│ ├── Math
│ └── BigInteger.php
│ ├── Net
│ └── SSH2.php
│ ├── System
│ ├── SSH
│ │ └── Agent.php
│ └── SSH_Agent.php
│ └── openssl.cnf
├── logo.png
└── scaleway.php
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/phpstorm
3 |
4 | ### PhpStorm ###
5 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
6 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
7 |
8 | # User-specific stuff:
9 | .idea/**/workspace.xml
10 | .idea/**/tasks.xml
11 | .idea/dictionaries
12 |
13 | # Sensitive or high-churn files:
14 | .idea/**/dataSources/
15 | .idea/**/dataSources.ids
16 | .idea/**/dataSources.xml
17 | .idea/**/dataSources.local.xml
18 | .idea/**/sqlDataSources.xml
19 | .idea/**/dynamic.xml
20 | .idea/**/uiDesigner.xml
21 |
22 | # Gradle:
23 | .idea/**/gradle.xml
24 | .idea/**/libraries
25 |
26 | # CMake
27 | cmake-build-debug/
28 |
29 | # Mongo Explorer plugin:
30 | .idea/**/mongoSettings.xml
31 |
32 | ## File-based project format:
33 | *.iws
34 |
35 | ## Plugin-specific files:
36 |
37 | # IntelliJ
38 | /out/
39 |
40 | # mpeltonen/sbt-idea plugin
41 | .idea_modules/
42 |
43 | # JIRA plugin
44 | atlassian-ide-plugin.xml
45 |
46 | # Cursive Clojure plugin
47 | .idea/replstate.xml
48 |
49 | # Crashlytics plugin (for Android Studio and IntelliJ)
50 | com_crashlytics_export_strings.xml
51 | crashlytics.properties
52 | crashlytics-build.properties
53 | fabric.properties
54 |
55 | ### PhpStorm Patch ###
56 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
57 |
58 | # *.iml
59 | # modules.xml
60 | # .idea/misc.xml
61 | # *.ipr
62 |
63 | # Sonarlint plugin
64 | .idea/sonarlint
65 |
66 | # End of https://www.gitignore.io/api/phpstorm
67 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 curiosul
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # scaleway-whmcs
2 | A WHMCS Module for automatically provisioning Cloud and VPS Servers provided by Scaleway
3 |
4 | Tested with WHMCS v6 but it should be fine with version 7 too.
5 |
6 | Go to wiki for installation and how to use: https://github.com/caffedrine/scaleway-whmcs/wiki
7 |
8 | Setting up: https://github.com/caffedrine/scaleway-whmcs/wiki/Setting-up-module
9 |
10 | How to use: https://github.com/caffedrine/scaleway-whmcs/wiki/How-to-use
11 |
--------------------------------------------------------------------------------
/clientarea.tpl:
--------------------------------------------------------------------------------
1 |
Server info:
2 |
3 |
4 |
Server ID: {$sid}
5 |
Server name: {$sname}
6 |
Server state: {$sstate}
7 |
Server state detail: {$sstatedetail}
8 |
9 |
Root volume: {$rootvolume}
10 |
Image: {$image}
11 |
Creation: {$creationdate}
12 |
Modification date: {$modificationdate}
13 |
14 |
Public IPv4: {$publicipv4}
15 |
Private IPv4: {$privateipv4}
16 |
IPv6: {$ipv6}
17 |
18 |
Bootscript: {$bootscript}
19 |
Location: {$location}
20 |
Architecture: {$architecture}
21 |
22 |
--------------------------------------------------------------------------------
/docs/img/administrator_area.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caffedrine/scaleway-whmcs/c25a730187f9e5bbe90ebcc5c270b05495e72513/docs/img/administrator_area.png
--------------------------------------------------------------------------------
/docs/img/user_area.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caffedrine/scaleway-whmcs/c25a730187f9e5bbe90ebcc5c270b05495e72513/docs/img/user_area.png
--------------------------------------------------------------------------------
/lib/phpseclib104/Crypt/Hash.php:
--------------------------------------------------------------------------------
1 |
20 | * setKey('abcdefg');
26 | *
27 | * echo base64_encode($hash->hash('abcdefg'));
28 | * ?>
29 | *
30 | *
31 | * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
32 | * of this software and associated documentation files (the "Software"), to deal
33 | * in the Software without restriction, including without limitation the rights
34 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35 | * copies of the Software, and to permit persons to whom the Software is
36 | * furnished to do so, subject to the following conditions:
37 | *
38 | * The above copyright notice and this permission notice shall be included in
39 | * all copies or substantial portions of the Software.
40 | *
41 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
46 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
47 | * THE SOFTWARE.
48 | *
49 | * @category Crypt
50 | * @package Crypt_Hash
51 | * @author Jim Wigginton
52 | * @copyright 2007 Jim Wigginton
53 | * @license http://www.opensource.org/licenses/mit-license.html MIT License
54 | * @link http://phpseclib.sourceforge.net
55 | */
56 |
57 | /**#@+
58 | * @access private
59 | * @see self::Crypt_Hash()
60 | */
61 | /**
62 | * Toggles the internal implementation
63 | */
64 | define('CRYPT_HASH_MODE_INTERNAL', 1);
65 | /**
66 | * Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+.
67 | */
68 | define('CRYPT_HASH_MODE_MHASH', 2);
69 | /**
70 | * Toggles the hash() implementation, which works on PHP 5.1.2+.
71 | */
72 | define('CRYPT_HASH_MODE_HASH', 3);
73 | /**#@-*/
74 |
75 | /**
76 | * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
77 | *
78 | * @package Crypt_Hash
79 | * @author Jim Wigginton
80 | * @access public
81 | */
82 | class Crypt_Hash
83 | {
84 | /**
85 | * Hash Parameter
86 | *
87 | * @see self::setHash()
88 | * @var int
89 | * @access private
90 | */
91 | var $hashParam;
92 |
93 | /**
94 | * Byte-length of compression blocks / key (Internal HMAC)
95 | *
96 | * @see self::setAlgorithm()
97 | * @var int
98 | * @access private
99 | */
100 | var $b;
101 |
102 | /**
103 | * Byte-length of hash output (Internal HMAC)
104 | *
105 | * @see self::setHash()
106 | * @var int
107 | * @access private
108 | */
109 | var $l = false;
110 |
111 | /**
112 | * Hash Algorithm
113 | *
114 | * @see self::setHash()
115 | * @var string
116 | * @access private
117 | */
118 | var $hash;
119 |
120 | /**
121 | * Key
122 | *
123 | * @see self::setKey()
124 | * @var string
125 | * @access private
126 | */
127 | var $key = false;
128 |
129 | /**
130 | * Outer XOR (Internal HMAC)
131 | *
132 | * @see self::setKey()
133 | * @var string
134 | * @access private
135 | */
136 | var $opad;
137 |
138 | /**
139 | * Inner XOR (Internal HMAC)
140 | *
141 | * @see self::setKey()
142 | * @var string
143 | * @access private
144 | */
145 | var $ipad;
146 |
147 | /**
148 | * Default Constructor.
149 | *
150 | * @param string $hash
151 | * @return Crypt_Hash
152 | * @access public
153 | */
154 | function __construct($hash = 'sha1')
155 | {
156 | if (!defined('CRYPT_HASH_MODE')) {
157 | switch (true) {
158 | case extension_loaded('hash'):
159 | define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH);
160 | break;
161 | case extension_loaded('mhash'):
162 | define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH);
163 | break;
164 | default:
165 | define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL);
166 | }
167 | }
168 |
169 | $this->setHash($hash);
170 | }
171 |
172 | /**
173 | * PHP4 compatible Default Constructor.
174 | *
175 | * @see self::__construct()
176 | * @param int $mode
177 | * @access public
178 | */
179 | function Crypt_Hash($hash = 'sha1')
180 | {
181 | $this->__construct($mode);
182 | }
183 |
184 | /**
185 | * Sets the key for HMACs
186 | *
187 | * Keys can be of any length.
188 | *
189 | * @access public
190 | * @param string $key
191 | */
192 | function setKey($key = false)
193 | {
194 | $this->key = $key;
195 | }
196 |
197 | /**
198 | * Gets the hash function.
199 | *
200 | * As set by the constructor or by the setHash() method.
201 | *
202 | * @access public
203 | * @return string
204 | */
205 | function getHash()
206 | {
207 | return $this->hashParam;
208 | }
209 |
210 | /**
211 | * Sets the hash function.
212 | *
213 | * @access public
214 | * @param string $hash
215 | */
216 | function setHash($hash)
217 | {
218 | $this->hashParam = $hash = strtolower($hash);
219 | switch ($hash) {
220 | case 'md5-96':
221 | case 'sha1-96':
222 | case 'sha256-96':
223 | case 'sha512-96':
224 | $hash = substr($hash, 0, -3);
225 | $this->l = 12; // 96 / 8 = 12
226 | break;
227 | case 'md2':
228 | case 'md5':
229 | $this->l = 16;
230 | break;
231 | case 'sha1':
232 | $this->l = 20;
233 | break;
234 | case 'sha256':
235 | $this->l = 32;
236 | break;
237 | case 'sha384':
238 | $this->l = 48;
239 | break;
240 | case 'sha512':
241 | $this->l = 64;
242 | }
243 |
244 | switch ($hash) {
245 | case 'md2':
246 | $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ?
247 | CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL;
248 | break;
249 | case 'sha384':
250 | case 'sha512':
251 | $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
252 | break;
253 | default:
254 | $mode = CRYPT_HASH_MODE;
255 | }
256 |
257 | switch ($mode) {
258 | case CRYPT_HASH_MODE_MHASH:
259 | switch ($hash) {
260 | case 'md5':
261 | $this->hash = MHASH_MD5;
262 | break;
263 | case 'sha256':
264 | $this->hash = MHASH_SHA256;
265 | break;
266 | case 'sha1':
267 | default:
268 | $this->hash = MHASH_SHA1;
269 | }
270 | return;
271 | case CRYPT_HASH_MODE_HASH:
272 | switch ($hash) {
273 | case 'md5':
274 | $this->hash = 'md5';
275 | return;
276 | case 'md2':
277 | case 'sha256':
278 | case 'sha384':
279 | case 'sha512':
280 | $this->hash = $hash;
281 | return;
282 | case 'sha1':
283 | default:
284 | $this->hash = 'sha1';
285 | }
286 | return;
287 | }
288 |
289 | switch ($hash) {
290 | case 'md2':
291 | $this->b = 16;
292 | $this->hash = array($this, '_md2');
293 | break;
294 | case 'md5':
295 | $this->b = 64;
296 | $this->hash = array($this, '_md5');
297 | break;
298 | case 'sha256':
299 | $this->b = 64;
300 | $this->hash = array($this, '_sha256');
301 | break;
302 | case 'sha384':
303 | case 'sha512':
304 | $this->b = 128;
305 | $this->hash = array($this, '_sha512');
306 | break;
307 | case 'sha1':
308 | default:
309 | $this->b = 64;
310 | $this->hash = array($this, '_sha1');
311 | }
312 |
313 | $this->ipad = str_repeat(chr(0x36), $this->b);
314 | $this->opad = str_repeat(chr(0x5C), $this->b);
315 | }
316 |
317 | /**
318 | * Compute the HMAC.
319 | *
320 | * @access public
321 | * @param string $text
322 | * @return string
323 | */
324 | function hash($text)
325 | {
326 | $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
327 |
328 | if (!empty($this->key) || is_string($this->key)) {
329 | switch ($mode) {
330 | case CRYPT_HASH_MODE_MHASH:
331 | $output = mhash($this->hash, $text, $this->key);
332 | break;
333 | case CRYPT_HASH_MODE_HASH:
334 | $output = hash_hmac($this->hash, $text, $this->key, true);
335 | break;
336 | case CRYPT_HASH_MODE_INTERNAL:
337 | /* "Applications that use keys longer than B bytes will first hash the key using H and then use the
338 | resultant L byte string as the actual key to HMAC."
339 |
340 | -- http://tools.ietf.org/html/rfc2104#section-2 */
341 | $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key;
342 |
343 | $key = str_pad($key, $this->b, chr(0)); // step 1
344 | $temp = $this->ipad ^ $key; // step 2
345 | $temp .= $text; // step 3
346 | $temp = call_user_func($this->hash, $temp); // step 4
347 | $output = $this->opad ^ $key; // step 5
348 | $output.= $temp; // step 6
349 | $output = call_user_func($this->hash, $output); // step 7
350 | }
351 | } else {
352 | switch ($mode) {
353 | case CRYPT_HASH_MODE_MHASH:
354 | $output = mhash($this->hash, $text);
355 | break;
356 | case CRYPT_HASH_MODE_HASH:
357 | $output = hash($this->hash, $text, true);
358 | break;
359 | case CRYPT_HASH_MODE_INTERNAL:
360 | $output = call_user_func($this->hash, $text);
361 | }
362 | }
363 |
364 | return substr($output, 0, $this->l);
365 | }
366 |
367 | /**
368 | * Returns the hash length (in bytes)
369 | *
370 | * @access public
371 | * @return int
372 | */
373 | function getLength()
374 | {
375 | return $this->l;
376 | }
377 |
378 | /**
379 | * Wrapper for MD5
380 | *
381 | * @access private
382 | * @param string $m
383 | */
384 | function _md5($m)
385 | {
386 | return pack('H*', md5($m));
387 | }
388 |
389 | /**
390 | * Wrapper for SHA1
391 | *
392 | * @access private
393 | * @param string $m
394 | */
395 | function _sha1($m)
396 | {
397 | return pack('H*', sha1($m));
398 | }
399 |
400 | /**
401 | * Pure-PHP implementation of MD2
402 | *
403 | * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
404 | *
405 | * @access private
406 | * @param string $m
407 | */
408 | function _md2($m)
409 | {
410 | static $s = array(
411 | 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
412 | 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
413 | 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
414 | 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
415 | 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
416 | 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
417 | 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
418 | 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
419 | 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
420 | 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
421 | 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
422 | 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
423 | 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
424 | 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
425 | 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
426 | 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
427 | 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
428 | 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
429 | );
430 |
431 | // Step 1. Append Padding Bytes
432 | $pad = 16 - (strlen($m) & 0xF);
433 | $m.= str_repeat(chr($pad), $pad);
434 |
435 | $length = strlen($m);
436 |
437 | // Step 2. Append Checksum
438 | $c = str_repeat(chr(0), 16);
439 | $l = chr(0);
440 | for ($i = 0; $i < $length; $i+= 16) {
441 | for ($j = 0; $j < 16; $j++) {
442 | // RFC1319 incorrectly states that C[j] should be set to S[c xor L]
443 | //$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]);
444 | // per , however, C[j] should be set to S[c xor L] xor C[j]
445 | $c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j]));
446 | $l = $c[$j];
447 | }
448 | }
449 | $m.= $c;
450 |
451 | $length+= 16;
452 |
453 | // Step 3. Initialize MD Buffer
454 | $x = str_repeat(chr(0), 48);
455 |
456 | // Step 4. Process Message in 16-Byte Blocks
457 | for ($i = 0; $i < $length; $i+= 16) {
458 | for ($j = 0; $j < 16; $j++) {
459 | $x[$j + 16] = $m[$i + $j];
460 | $x[$j + 32] = $x[$j + 16] ^ $x[$j];
461 | }
462 | $t = chr(0);
463 | for ($j = 0; $j < 18; $j++) {
464 | for ($k = 0; $k < 48; $k++) {
465 | $x[$k] = $t = $x[$k] ^ chr($s[ord($t)]);
466 | //$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]);
467 | }
468 | $t = chr(ord($t) + $j);
469 | }
470 | }
471 |
472 | // Step 5. Output
473 | return substr($x, 0, 16);
474 | }
475 |
476 | /**
477 | * Pure-PHP implementation of SHA256
478 | *
479 | * See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}.
480 | *
481 | * @access private
482 | * @param string $m
483 | */
484 | function _sha256($m)
485 | {
486 | if (extension_loaded('suhosin')) {
487 | return pack('H*', sha256($m));
488 | }
489 |
490 | // Initialize variables
491 | $hash = array(
492 | 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
493 | );
494 | // Initialize table of round constants
495 | // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
496 | static $k = array(
497 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
498 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
499 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
500 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
501 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
502 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
503 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
504 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
505 | );
506 |
507 | // Pre-processing
508 | $length = strlen($m);
509 | // to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64
510 | $m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F));
511 | $m[$length] = chr(0x80);
512 | // we don't support hashing strings 512MB long
513 | $m.= pack('N2', 0, $length << 3);
514 |
515 | // Process the message in successive 512-bit chunks
516 | $chunks = str_split($m, 64);
517 | foreach ($chunks as $chunk) {
518 | $w = array();
519 | for ($i = 0; $i < 16; $i++) {
520 | extract(unpack('Ntemp', $this->_string_shift($chunk, 4)));
521 | $w[] = $temp;
522 | }
523 |
524 | // Extend the sixteen 32-bit words into sixty-four 32-bit words
525 | for ($i = 16; $i < 64; $i++) {
526 | // @codingStandardsIgnoreStart
527 | $s0 = $this->_rightRotate($w[$i - 15], 7) ^
528 | $this->_rightRotate($w[$i - 15], 18) ^
529 | $this->_rightShift( $w[$i - 15], 3);
530 | $s1 = $this->_rightRotate($w[$i - 2], 17) ^
531 | $this->_rightRotate($w[$i - 2], 19) ^
532 | $this->_rightShift( $w[$i - 2], 10);
533 | // @codingStandardsIgnoreEnd
534 | $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
535 | }
536 |
537 | // Initialize hash value for this chunk
538 | list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;
539 |
540 | // Main loop
541 | for ($i = 0; $i < 64; $i++) {
542 | $s0 = $this->_rightRotate($a, 2) ^
543 | $this->_rightRotate($a, 13) ^
544 | $this->_rightRotate($a, 22);
545 | $maj = ($a & $b) ^
546 | ($a & $c) ^
547 | ($b & $c);
548 | $t2 = $this->_add($s0, $maj);
549 |
550 | $s1 = $this->_rightRotate($e, 6) ^
551 | $this->_rightRotate($e, 11) ^
552 | $this->_rightRotate($e, 25);
553 | $ch = ($e & $f) ^
554 | ($this->_not($e) & $g);
555 | $t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]);
556 |
557 | $h = $g;
558 | $g = $f;
559 | $f = $e;
560 | $e = $this->_add($d, $t1);
561 | $d = $c;
562 | $c = $b;
563 | $b = $a;
564 | $a = $this->_add($t1, $t2);
565 | }
566 |
567 | // Add this chunk's hash to result so far
568 | $hash = array(
569 | $this->_add($hash[0], $a),
570 | $this->_add($hash[1], $b),
571 | $this->_add($hash[2], $c),
572 | $this->_add($hash[3], $d),
573 | $this->_add($hash[4], $e),
574 | $this->_add($hash[5], $f),
575 | $this->_add($hash[6], $g),
576 | $this->_add($hash[7], $h)
577 | );
578 | }
579 |
580 | // Produce the final hash value (big-endian)
581 | return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]);
582 | }
583 |
584 | /**
585 | * Pure-PHP implementation of SHA384 and SHA512
586 | *
587 | * @access private
588 | * @param string $m
589 | */
590 | function _sha512($m)
591 | {
592 | if (!class_exists('Math_BigInteger')) {
593 | include_once 'Math/BigInteger.php';
594 | }
595 |
596 | static $init384, $init512, $k;
597 |
598 | if (!isset($k)) {
599 | // Initialize variables
600 | $init384 = array( // initial values for SHA384
601 | 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
602 | '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
603 | );
604 | $init512 = array( // initial values for SHA512
605 | '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
606 | '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
607 | );
608 |
609 | for ($i = 0; $i < 8; $i++) {
610 | $init384[$i] = new Math_BigInteger($init384[$i], 16);
611 | $init384[$i]->setPrecision(64);
612 | $init512[$i] = new Math_BigInteger($init512[$i], 16);
613 | $init512[$i]->setPrecision(64);
614 | }
615 |
616 | // Initialize table of round constants
617 | // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
618 | $k = array(
619 | '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
620 | '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
621 | 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
622 | '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
623 | 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
624 | '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
625 | '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
626 | 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
627 | '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
628 | '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
629 | 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
630 | 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
631 | '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
632 | '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
633 | '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
634 | '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
635 | 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
636 | '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
637 | '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
638 | '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817'
639 | );
640 |
641 | for ($i = 0; $i < 80; $i++) {
642 | $k[$i] = new Math_BigInteger($k[$i], 16);
643 | }
644 | }
645 |
646 | $hash = $this->l == 48 ? $init384 : $init512;
647 |
648 | // Pre-processing
649 | $length = strlen($m);
650 | // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
651 | $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
652 | $m[$length] = chr(0x80);
653 | // we don't support hashing strings 512MB long
654 | $m.= pack('N4', 0, 0, 0, $length << 3);
655 |
656 | // Process the message in successive 1024-bit chunks
657 | $chunks = str_split($m, 128);
658 | foreach ($chunks as $chunk) {
659 | $w = array();
660 | for ($i = 0; $i < 16; $i++) {
661 | $temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256);
662 | $temp->setPrecision(64);
663 | $w[] = $temp;
664 | }
665 |
666 | // Extend the sixteen 32-bit words into eighty 32-bit words
667 | for ($i = 16; $i < 80; $i++) {
668 | $temp = array(
669 | $w[$i - 15]->bitwise_rightRotate(1),
670 | $w[$i - 15]->bitwise_rightRotate(8),
671 | $w[$i - 15]->bitwise_rightShift(7)
672 | );
673 | $s0 = $temp[0]->bitwise_xor($temp[1]);
674 | $s0 = $s0->bitwise_xor($temp[2]);
675 | $temp = array(
676 | $w[$i - 2]->bitwise_rightRotate(19),
677 | $w[$i - 2]->bitwise_rightRotate(61),
678 | $w[$i - 2]->bitwise_rightShift(6)
679 | );
680 | $s1 = $temp[0]->bitwise_xor($temp[1]);
681 | $s1 = $s1->bitwise_xor($temp[2]);
682 | $w[$i] = $w[$i - 16]->copy();
683 | $w[$i] = $w[$i]->add($s0);
684 | $w[$i] = $w[$i]->add($w[$i - 7]);
685 | $w[$i] = $w[$i]->add($s1);
686 | }
687 |
688 | // Initialize hash value for this chunk
689 | $a = $hash[0]->copy();
690 | $b = $hash[1]->copy();
691 | $c = $hash[2]->copy();
692 | $d = $hash[3]->copy();
693 | $e = $hash[4]->copy();
694 | $f = $hash[5]->copy();
695 | $g = $hash[6]->copy();
696 | $h = $hash[7]->copy();
697 |
698 | // Main loop
699 | for ($i = 0; $i < 80; $i++) {
700 | $temp = array(
701 | $a->bitwise_rightRotate(28),
702 | $a->bitwise_rightRotate(34),
703 | $a->bitwise_rightRotate(39)
704 | );
705 | $s0 = $temp[0]->bitwise_xor($temp[1]);
706 | $s0 = $s0->bitwise_xor($temp[2]);
707 | $temp = array(
708 | $a->bitwise_and($b),
709 | $a->bitwise_and($c),
710 | $b->bitwise_and($c)
711 | );
712 | $maj = $temp[0]->bitwise_xor($temp[1]);
713 | $maj = $maj->bitwise_xor($temp[2]);
714 | $t2 = $s0->add($maj);
715 |
716 | $temp = array(
717 | $e->bitwise_rightRotate(14),
718 | $e->bitwise_rightRotate(18),
719 | $e->bitwise_rightRotate(41)
720 | );
721 | $s1 = $temp[0]->bitwise_xor($temp[1]);
722 | $s1 = $s1->bitwise_xor($temp[2]);
723 | $temp = array(
724 | $e->bitwise_and($f),
725 | $g->bitwise_and($e->bitwise_not())
726 | );
727 | $ch = $temp[0]->bitwise_xor($temp[1]);
728 | $t1 = $h->add($s1);
729 | $t1 = $t1->add($ch);
730 | $t1 = $t1->add($k[$i]);
731 | $t1 = $t1->add($w[$i]);
732 |
733 | $h = $g->copy();
734 | $g = $f->copy();
735 | $f = $e->copy();
736 | $e = $d->add($t1);
737 | $d = $c->copy();
738 | $c = $b->copy();
739 | $b = $a->copy();
740 | $a = $t1->add($t2);
741 | }
742 |
743 | // Add this chunk's hash to result so far
744 | $hash = array(
745 | $hash[0]->add($a),
746 | $hash[1]->add($b),
747 | $hash[2]->add($c),
748 | $hash[3]->add($d),
749 | $hash[4]->add($e),
750 | $hash[5]->add($f),
751 | $hash[6]->add($g),
752 | $hash[7]->add($h)
753 | );
754 | }
755 |
756 | // Produce the final hash value (big-endian)
757 | // (Crypt_Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here)
758 | $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() .
759 | $hash[4]->toBytes() . $hash[5]->toBytes();
760 | if ($this->l != 48) {
761 | $temp.= $hash[6]->toBytes() . $hash[7]->toBytes();
762 | }
763 |
764 | return $temp;
765 | }
766 |
767 | /**
768 | * Right Rotate
769 | *
770 | * @access private
771 | * @param int $int
772 | * @param int $amt
773 | * @see self::_sha256()
774 | * @return int
775 | */
776 | function _rightRotate($int, $amt)
777 | {
778 | $invamt = 32 - $amt;
779 | $mask = (1 << $invamt) - 1;
780 | return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
781 | }
782 |
783 | /**
784 | * Right Shift
785 | *
786 | * @access private
787 | * @param int $int
788 | * @param int $amt
789 | * @see self::_sha256()
790 | * @return int
791 | */
792 | function _rightShift($int, $amt)
793 | {
794 | $mask = (1 << (32 - $amt)) - 1;
795 | return ($int >> $amt) & $mask;
796 | }
797 |
798 | /**
799 | * Not
800 | *
801 | * @access private
802 | * @param int $int
803 | * @see self::_sha256()
804 | * @return int
805 | */
806 | function _not($int)
807 | {
808 | return ~$int & 0xFFFFFFFF;
809 | }
810 |
811 | /**
812 | * Add
813 | *
814 | * _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the
815 | * possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster.
816 | *
817 | * @param int $...
818 | * @return int
819 | * @see self::_sha256()
820 | * @access private
821 | */
822 | function _add()
823 | {
824 | static $mod;
825 | if (!isset($mod)) {
826 | $mod = pow(2, 32);
827 | }
828 |
829 | $result = 0;
830 | $arguments = func_get_args();
831 | foreach ($arguments as $argument) {
832 | $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
833 | }
834 |
835 | // PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding"
836 | // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
837 | if (is_int($result) || version_compare(PHP_VERSION, '5.3.0') >= 0 || (PHP_OS & "\xDF\xDF\xDF") === 'WIN') {
838 | return fmod($result, $mod);
839 | }
840 |
841 | return (fmod($result, 0x80000000) & 0x7FFFFFFF) |
842 | ((fmod(floor($result / 0x80000000), 2) & 1) << 31);
843 | }
844 |
845 | /**
846 | * String Shift
847 | *
848 | * Inspired by array_shift
849 | *
850 | * @param string $string
851 | * @param int $index
852 | * @return string
853 | * @access private
854 | */
855 | function _string_shift(&$string, $index = 1)
856 | {
857 | $substr = substr($string, 0, $index);
858 | $string = substr($string, $index);
859 | return $substr;
860 | }
861 | }
862 |
--------------------------------------------------------------------------------
/lib/phpseclib104/Crypt/Random.php:
--------------------------------------------------------------------------------
1 |
13 | *
18 | *
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
41 | * @copyright 2007 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 int $length
65 | * @return string
66 | * @access public
67 | */
68 | function crypt_random_string($length)
69 | {
70 | if (CRYPT_RANDOM_IS_WINDOWS) {
71 | // method 1. prior to PHP 5.3, mcrypt_create_iv() would call rand() on windows
72 | if (extension_loaded('mcrypt') && version_compare(PHP_VERSION, '5.3.0', '>=')) {
73 | return mcrypt_create_iv($length);
74 | }
75 | // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
76 | // to quote , "possible blocking behavior". as of 5.3.4
77 | // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
78 | // call php_win32_get_random_bytes():
79 | //
80 | // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
81 | // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
82 | //
83 | // php_win32_get_random_bytes() is defined thusly:
84 | //
85 | // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
86 | //
87 | // we're calling it, all the same, in the off chance that the mcrypt extension is not available
88 | if (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
89 | return openssl_random_pseudo_bytes($length);
90 | }
91 | } else {
92 | // method 1. the fastest
93 | if (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.0', '>=')) {
94 | return openssl_random_pseudo_bytes($length);
95 | }
96 | // method 2
97 | static $fp = true;
98 | if ($fp === true) {
99 | // warning's will be output unles the error suppression operator is used. errors such as
100 | // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
101 | $fp = @fopen('/dev/urandom', 'rb');
102 | }
103 | if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
104 | return fread($fp, $length);
105 | }
106 | // method 3. pretty much does the same thing as method 2 per the following url:
107 | // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
108 | // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
109 | // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
110 | // restrictions or some such
111 | if (extension_loaded('mcrypt')) {
112 | return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
113 | }
114 | }
115 | // at this point we have no choice but to use a pure-PHP CSPRNG
116 |
117 | // cascade entropy across multiple PHP instances by fixing the session and collecting all
118 | // environmental variables, including the previous session data and the current session
119 | // data.
120 | //
121 | // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
122 | // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
123 | // PHP isn't low level to be able to use those as sources and on a web server there's not likely
124 | // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
125 | // however, a ton of people visiting the website. obviously you don't want to base your seeding
126 | // soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
127 | // by the user and (2) this isn't just looking at the data sent by the current user - it's based
128 | // on the data sent by all users. one user requests the page and a hash of their info is saved.
129 | // another user visits the page and the serialization of their data is utilized along with the
130 | // server envirnment stuff and a hash of the previous http request data (which itself utilizes
131 | // a hash of the session data before that). certainly an attacker should be assumed to have
132 | // full control over his own http requests. he, however, is not going to have control over
133 | // everyone's http requests.
134 | static $crypto = false, $v;
135 | if ($crypto === false) {
136 | // save old session data
137 | $old_session_id = session_id();
138 | $old_use_cookies = ini_get('session.use_cookies');
139 | $old_session_cache_limiter = session_cache_limiter();
140 | $_OLD_SESSION = isset($_SESSION) ? $_SESSION : false;
141 | if ($old_session_id != '') {
142 | session_write_close();
143 | }
144 |
145 | session_id(1);
146 | ini_set('session.use_cookies', 0);
147 | session_cache_limiter('');
148 | session_start();
149 |
150 | $v = $seed = $_SESSION['seed'] = pack('H*', sha1(
151 | (isset($_SERVER) ? phpseclib_safe_serialize($_SERVER) : '') .
152 | (isset($_POST) ? phpseclib_safe_serialize($_POST) : '') .
153 | (isset($_GET) ? phpseclib_safe_serialize($_GET) : '') .
154 | (isset($_COOKIE) ? phpseclib_safe_serialize($_COOKIE) : '') .
155 | phpseclib_safe_serialize($GLOBALS) .
156 | phpseclib_safe_serialize($_SESSION) .
157 | phpseclib_safe_serialize($_OLD_SESSION)
158 | ));
159 | if (!isset($_SESSION['count'])) {
160 | $_SESSION['count'] = 0;
161 | }
162 | $_SESSION['count']++;
163 |
164 | session_write_close();
165 |
166 | // restore old session data
167 | if ($old_session_id != '') {
168 | session_id($old_session_id);
169 | session_start();
170 | ini_set('session.use_cookies', $old_use_cookies);
171 | session_cache_limiter($old_session_cache_limiter);
172 | } else {
173 | if ($_OLD_SESSION !== false) {
174 | $_SESSION = $_OLD_SESSION;
175 | unset($_OLD_SESSION);
176 | } else {
177 | unset($_SESSION);
178 | }
179 | }
180 |
181 | // in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
182 | // 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.
183 | // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
184 | // original hash and the current hash. we'll be emulating that. for more info see the following URL:
185 | //
186 | // http://tools.ietf.org/html/rfc4253#section-7.2
187 | //
188 | // see the is_string($crypto) part for an example of how to expand the keys
189 | $key = pack('H*', sha1($seed . 'A'));
190 | $iv = pack('H*', sha1($seed . 'C'));
191 |
192 | // ciphers are used as per the nist.gov link below. also, see this link:
193 | //
194 | // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
195 | switch (true) {
196 | case phpseclib_resolve_include_path('Crypt/AES.php'):
197 | if (!class_exists('Crypt_AES')) {
198 | include_once 'AES.php';
199 | }
200 | $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
201 | break;
202 | case phpseclib_resolve_include_path('Crypt/Twofish.php'):
203 | if (!class_exists('Crypt_Twofish')) {
204 | include_once 'Twofish.php';
205 | }
206 | $crypto = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR);
207 | break;
208 | case phpseclib_resolve_include_path('Crypt/Blowfish.php'):
209 | if (!class_exists('Crypt_Blowfish')) {
210 | include_once 'Blowfish.php';
211 | }
212 | $crypto = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR);
213 | break;
214 | case phpseclib_resolve_include_path('Crypt/TripleDES.php'):
215 | if (!class_exists('Crypt_TripleDES')) {
216 | include_once 'TripleDES.php';
217 | }
218 | $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
219 | break;
220 | case phpseclib_resolve_include_path('Crypt/DES.php'):
221 | if (!class_exists('Crypt_DES')) {
222 | include_once 'DES.php';
223 | }
224 | $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
225 | break;
226 | case phpseclib_resolve_include_path('Crypt/RC4.php'):
227 | if (!class_exists('Crypt_RC4')) {
228 | include_once 'RC4.php';
229 | }
230 | $crypto = new Crypt_RC4();
231 | break;
232 | default:
233 | user_error('crypt_random_string requires at least one symmetric cipher be loaded');
234 | return false;
235 | }
236 |
237 | $crypto->setKey($key);
238 | $crypto->setIV($iv);
239 | $crypto->enableContinuousBuffer();
240 | }
241 |
242 | //return $crypto->encrypt(str_repeat("\0", $length));
243 |
244 | // the following is based off of ANSI X9.31:
245 | //
246 | // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
247 | //
248 | // OpenSSL uses that same standard for it's random numbers:
249 | //
250 | // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
251 | // (do a search for "ANS X9.31 A.2.4")
252 | $result = '';
253 | while (strlen($result) < $length) {
254 | $i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21
255 | $r = $crypto->encrypt($i ^ $v); // strlen($v) == 20
256 | $v = $crypto->encrypt($r ^ $i); // strlen($r) == 20
257 | $result.= $r;
258 | }
259 | return substr($result, 0, $length);
260 | }
261 | }
262 |
263 | if (!function_exists('phpseclib_safe_serialize')) {
264 | /**
265 | * Safely serialize variables
266 | *
267 | * If a class has a private __sleep() method it'll give a fatal error on PHP 5.2 and earlier.
268 | * PHP 5.3 will emit a warning.
269 | *
270 | * @param mixed $arr
271 | * @access public
272 | */
273 | function phpseclib_safe_serialize(&$arr)
274 | {
275 | if (is_object($arr)) {
276 | return '';
277 | }
278 | if (!is_array($arr)) {
279 | return serialize($arr);
280 | }
281 | // prevent circular array recursion
282 | if (isset($arr['__phpseclib_marker'])) {
283 | return '';
284 | }
285 | $safearr = array();
286 | $arr['__phpseclib_marker'] = true;
287 | foreach (array_keys($arr) as $key) {
288 | // do not recurse on the '__phpseclib_marker' key itself, for smaller memory usage
289 | if ($key !== '__phpseclib_marker') {
290 | $safearr[$key] = phpseclib_safe_serialize($arr[$key]);
291 | }
292 | }
293 | unset($arr['__phpseclib_marker']);
294 | return serialize($safearr);
295 | }
296 | }
297 |
298 | if (!function_exists('phpseclib_resolve_include_path')) {
299 | /**
300 | * Resolve filename against the include path.
301 | *
302 | * Wrapper around stream_resolve_include_path() (which was introduced in
303 | * PHP 5.3.2) with fallback implementation for earlier PHP versions.
304 | *
305 | * @param string $filename
306 | * @return string|false
307 | * @access public
308 | */
309 | function phpseclib_resolve_include_path($filename)
310 | {
311 | if (function_exists('stream_resolve_include_path')) {
312 | return stream_resolve_include_path($filename);
313 | }
314 |
315 | // handle non-relative paths
316 | if (file_exists($filename)) {
317 | return realpath($filename);
318 | }
319 |
320 | $paths = PATH_SEPARATOR == ':' ?
321 | preg_split('#(?
34 | * @copyright 2012 Jim Wigginton
35 | * @license http://www.opensource.org/licenses/mit-license.html MIT License
36 | * @link http://phpseclib.sourceforge.net
37 | */
38 |
39 | /**
40 | * Pure-PHP ANSI Decoder
41 | *
42 | * @package File_ANSI
43 | * @author Jim Wigginton
44 | * @access public
45 | */
46 | class File_ANSI
47 | {
48 | /**
49 | * Max Width
50 | *
51 | * @var int
52 | * @access private
53 | */
54 | var $max_x;
55 |
56 | /**
57 | * Max Height
58 | *
59 | * @var int
60 | * @access private
61 | */
62 | var $max_y;
63 |
64 | /**
65 | * Max History
66 | *
67 | * @var int
68 | * @access private
69 | */
70 | var $max_history;
71 |
72 | /**
73 | * History
74 | *
75 | * @var array
76 | * @access private
77 | */
78 | var $history;
79 |
80 | /**
81 | * History Attributes
82 | *
83 | * @var array
84 | * @access private
85 | */
86 | var $history_attrs;
87 |
88 | /**
89 | * Current Column
90 | *
91 | * @var int
92 | * @access private
93 | */
94 | var $x;
95 |
96 | /**
97 | * Current Row
98 | *
99 | * @var int
100 | * @access private
101 | */
102 | var $y;
103 |
104 | /**
105 | * Old Column
106 | *
107 | * @var int
108 | * @access private
109 | */
110 | var $old_x;
111 |
112 | /**
113 | * Old Row
114 | *
115 | * @var int
116 | * @access private
117 | */
118 | var $old_y;
119 |
120 | /**
121 | * An empty attribute cell
122 | *
123 | * @var object
124 | * @access private
125 | */
126 | var $base_attr_cell;
127 |
128 | /**
129 | * The current attribute cell
130 | *
131 | * @var object
132 | * @access private
133 | */
134 | var $attr_cell;
135 |
136 | /**
137 | * An empty attribute row
138 | *
139 | * @var array
140 | * @access private
141 | */
142 | var $attr_row;
143 |
144 | /**
145 | * The current screen text
146 | *
147 | * @var array
148 | * @access private
149 | */
150 | var $screen;
151 |
152 | /**
153 | * The current screen attributes
154 | *
155 | * @var array
156 | * @access private
157 | */
158 | var $attrs;
159 |
160 | /**
161 | * Current ANSI code
162 | *
163 | * @var string
164 | * @access private
165 | */
166 | var $ansi;
167 |
168 | /**
169 | * Tokenization
170 | *
171 | * @var array
172 | * @access private
173 | */
174 | var $tokenization;
175 |
176 | /**
177 | * Default Constructor.
178 | *
179 | * @return File_ANSI
180 | * @access public
181 | */
182 | function __construct()
183 | {
184 | $attr_cell = new stdClass();
185 | $attr_cell->bold = false;
186 | $attr_cell->underline = false;
187 | $attr_cell->blink = false;
188 | $attr_cell->background = 'black';
189 | $attr_cell->foreground = 'white';
190 | $attr_cell->reverse = false;
191 | $this->base_attr_cell = clone($attr_cell);
192 | $this->attr_cell = clone($attr_cell);
193 |
194 | $this->setHistory(200);
195 | $this->setDimensions(80, 24);
196 | }
197 |
198 | /**
199 | * PHP4 compatible Default Constructor.
200 | *
201 | * @see self::__construct()
202 | * @access public
203 | */
204 | function File_ANSI()
205 | {
206 | $this->__construct($mode);
207 | }
208 |
209 | /**
210 | * Set terminal width and height
211 | *
212 | * Resets the screen as well
213 | *
214 | * @param int $x
215 | * @param int $y
216 | * @access public
217 | */
218 | function setDimensions($x, $y)
219 | {
220 | $this->max_x = $x - 1;
221 | $this->max_y = $y - 1;
222 | $this->x = $this->y = 0;
223 | $this->history = $this->history_attrs = array();
224 | $this->attr_row = array_fill(0, $this->max_x + 2, $this->base_attr_cell);
225 | $this->screen = array_fill(0, $this->max_y + 1, '');
226 | $this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row);
227 | $this->ansi = '';
228 | }
229 |
230 | /**
231 | * Set the number of lines that should be logged past the terminal height
232 | *
233 | * @param int $x
234 | * @param int $y
235 | * @access public
236 | */
237 | function setHistory($history)
238 | {
239 | $this->max_history = $history;
240 | }
241 |
242 | /**
243 | * Load a string
244 | *
245 | * @param string $source
246 | * @access public
247 | */
248 | function loadString($source)
249 | {
250 | $this->setDimensions($this->max_x + 1, $this->max_y + 1);
251 | $this->appendString($source);
252 | }
253 |
254 | /**
255 | * Appdend a string
256 | *
257 | * @param string $source
258 | * @access public
259 | */
260 | function appendString($source)
261 | {
262 | $this->tokenization = array('');
263 | for ($i = 0; $i < strlen($source); $i++) {
264 | if (strlen($this->ansi)) {
265 | $this->ansi.= $source[$i];
266 | $chr = ord($source[$i]);
267 | // http://en.wikipedia.org/wiki/ANSI_escape_code#Sequence_elements
268 | // single character CSI's not currently supported
269 | switch (true) {
270 | case $this->ansi == "\x1B=":
271 | $this->ansi = '';
272 | continue 2;
273 | case strlen($this->ansi) == 2 && $chr >= 64 && $chr <= 95 && $chr != ord('['):
274 | case strlen($this->ansi) > 2 && $chr >= 64 && $chr <= 126:
275 | break;
276 | default:
277 | continue 2;
278 | }
279 | $this->tokenization[] = $this->ansi;
280 | $this->tokenization[] = '';
281 | // http://ascii-table.com/ansi-escape-sequences-vt-100.php
282 | switch ($this->ansi) {
283 | case "\x1B[H": // Move cursor to upper left corner
284 | $this->old_x = $this->x;
285 | $this->old_y = $this->y;
286 | $this->x = $this->y = 0;
287 | break;
288 | case "\x1B[J": // Clear screen from cursor down
289 | $this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y));
290 | $this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, ''));
291 |
292 | $this->history_attrs = array_merge($this->history_attrs, array_slice(array_splice($this->attrs, $this->y + 1), 0, $this->old_y));
293 | $this->attrs = array_merge($this->attrs, array_fill($this->y, $this->max_y, $this->attr_row));
294 |
295 | if (count($this->history) == $this->max_history) {
296 | array_shift($this->history);
297 | array_shift($this->history_attrs);
298 | }
299 | case "\x1B[K": // Clear screen from cursor right
300 | $this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x);
301 |
302 | array_splice($this->attrs[$this->y], $this->x + 1, $this->max_x - $this->x, array_fill($this->x, $this->max_x - $this->x - 1, $this->base_attr_cell));
303 | break;
304 | case "\x1B[2K": // Clear entire line
305 | $this->screen[$this->y] = str_repeat(' ', $this->x);
306 | $this->attrs[$this->y] = $this->attr_row;
307 | break;
308 | case "\x1B[?1h": // set cursor key to application
309 | case "\x1B[?25h": // show the cursor
310 | case "\x1B(B": // set united states g0 character set
311 | break;
312 | case "\x1BE": // Move to next line
313 | $this->_newLine();
314 | $this->x = 0;
315 | break;
316 | default:
317 | switch (true) {
318 | case preg_match('#\x1B\[(\d+)B#', $this->ansi, $match): // Move cursor down n lines
319 | $this->old_y = $this->y;
320 | $this->y+= $match[1];
321 | break;
322 | case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h
323 | $this->old_x = $this->x;
324 | $this->old_y = $this->y;
325 | $this->x = $match[2] - 1;
326 | $this->y = $match[1] - 1;
327 | break;
328 | case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines
329 | $this->old_x = $this->x;
330 | $this->x+= $match[1];
331 | break;
332 | case preg_match('#\x1B\[(\d+)D#', $this->ansi, $match): // Move cursor left n lines
333 | $this->old_x = $this->x;
334 | $this->x-= $match[1];
335 | break;
336 | case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window
337 | break;
338 | case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes
339 | $attr_cell = &$this->attr_cell;
340 | $mods = explode(';', $match[1]);
341 | foreach ($mods as $mod) {
342 | switch ($mod) {
343 | case 0: // Turn off character attributes
344 | $attr_cell = clone($this->base_attr_cell);
345 | break;
346 | case 1: // Turn bold mode on
347 | $attr_cell->bold = true;
348 | break;
349 | case 4: // Turn underline mode on
350 | $attr_cell->underline = true;
351 | break;
352 | case 5: // Turn blinking mode on
353 | $attr_cell->blink = true;
354 | break;
355 | case 7: // Turn reverse video on
356 | $attr_cell->reverse = !$attr_cell->reverse;
357 | $temp = $attr_cell->background;
358 | $attr_cell->background = $attr_cell->foreground;
359 | $attr_cell->foreground = $temp;
360 | break;
361 | default: // set colors
362 | //$front = $attr_cell->reverse ? &$attr_cell->background : &$attr_cell->foreground;
363 | $front = &$attr_cell->{ $attr_cell->reverse ? 'background' : 'foreground' };
364 | //$back = $attr_cell->reverse ? &$attr_cell->foreground : &$attr_cell->background;
365 | $back = &$attr_cell->{ $attr_cell->reverse ? 'foreground' : 'background' };
366 | switch ($mod) {
367 | // @codingStandardsIgnoreStart
368 | case 30: $front = 'black'; break;
369 | case 31: $front = 'red'; break;
370 | case 32: $front = 'green'; break;
371 | case 33: $front = 'yellow'; break;
372 | case 34: $front = 'blue'; break;
373 | case 35: $front = 'magenta'; break;
374 | case 36: $front = 'cyan'; break;
375 | case 37: $front = 'white'; break;
376 |
377 | case 40: $back = 'black'; break;
378 | case 41: $back = 'red'; break;
379 | case 42: $back = 'green'; break;
380 | case 43: $back = 'yellow'; break;
381 | case 44: $back = 'blue'; break;
382 | case 45: $back = 'magenta'; break;
383 | case 46: $back = 'cyan'; break;
384 | case 47: $back = 'white'; break;
385 | // @codingStandardsIgnoreEnd
386 |
387 | default:
388 | //user_error('Unsupported attribute: ' . $mod);
389 | $this->ansi = '';
390 | break 2;
391 | }
392 | }
393 | }
394 | break;
395 | default:
396 | //user_error("{$this->ansi} is unsupported\r\n");
397 | }
398 | }
399 | $this->ansi = '';
400 | continue;
401 | }
402 |
403 | $this->tokenization[count($this->tokenization) - 1].= $source[$i];
404 | switch ($source[$i]) {
405 | case "\r":
406 | $this->x = 0;
407 | break;
408 | case "\n":
409 | $this->_newLine();
410 | break;
411 | case "\x08": // backspace
412 | if ($this->x) {
413 | $this->x--;
414 | $this->attrs[$this->y][$this->x] = clone($this->base_attr_cell);
415 | $this->screen[$this->y] = substr_replace(
416 | $this->screen[$this->y],
417 | $source[$i],
418 | $this->x,
419 | 1
420 | );
421 | }
422 | break;
423 | case "\x0F": // shift
424 | break;
425 | case "\x1B": // start ANSI escape code
426 | $this->tokenization[count($this->tokenization) - 1] = substr($this->tokenization[count($this->tokenization) - 1], 0, -1);
427 | //if (!strlen($this->tokenization[count($this->tokenization) - 1])) {
428 | // array_pop($this->tokenization);
429 | //}
430 | $this->ansi.= "\x1B";
431 | break;
432 | default:
433 | $this->attrs[$this->y][$this->x] = clone($this->attr_cell);
434 | if ($this->x > strlen($this->screen[$this->y])) {
435 | $this->screen[$this->y] = str_repeat(' ', $this->x);
436 | }
437 | $this->screen[$this->y] = substr_replace(
438 | $this->screen[$this->y],
439 | $source[$i],
440 | $this->x,
441 | 1
442 | );
443 |
444 | if ($this->x > $this->max_x) {
445 | $this->x = 0;
446 | $this->y++;
447 | } else {
448 | $this->x++;
449 | }
450 | }
451 | }
452 | }
453 |
454 | /**
455 | * Add a new line
456 | *
457 | * Also update the $this->screen and $this->history buffers
458 | *
459 | * @access private
460 | */
461 | function _newLine()
462 | {
463 | //if ($this->y < $this->max_y) {
464 | // $this->y++;
465 | //}
466 |
467 | while ($this->y >= $this->max_y) {
468 | $this->history = array_merge($this->history, array(array_shift($this->screen)));
469 | $this->screen[] = '';
470 |
471 | $this->history_attrs = array_merge($this->history_attrs, array(array_shift($this->attrs)));
472 | $this->attrs[] = $this->attr_row;
473 |
474 | if (count($this->history) >= $this->max_history) {
475 | array_shift($this->history);
476 | array_shift($this->history_attrs);
477 | }
478 |
479 | $this->y--;
480 | }
481 | $this->y++;
482 | }
483 |
484 | /**
485 | * Returns the current coordinate without preformating
486 | *
487 | * @access private
488 | * @return string
489 | */
490 | function _processCoordinate($last_attr, $cur_attr, $char)
491 | {
492 | $output = '';
493 |
494 | if ($last_attr != $cur_attr) {
495 | $close = $open = '';
496 | if ($last_attr->foreground != $cur_attr->foreground) {
497 | if ($cur_attr->foreground != 'white') {
498 | $open.= '';
499 | }
500 | if ($last_attr->foreground != 'white') {
501 | $close = '' . $close;
502 | }
503 | }
504 | if ($last_attr->background != $cur_attr->background) {
505 | if ($cur_attr->background != 'black') {
506 | $open.= '';
507 | }
508 | if ($last_attr->background != 'black') {
509 | $close = '' . $close;
510 | }
511 | }
512 | if ($last_attr->bold != $cur_attr->bold) {
513 | if ($cur_attr->bold) {
514 | $open.= '';
515 | } else {
516 | $close = '' . $close;
517 | }
518 | }
519 | if ($last_attr->underline != $cur_attr->underline) {
520 | if ($cur_attr->underline) {
521 | $open.= '';
522 | } else {
523 | $close = '' . $close;
524 | }
525 | }
526 | if ($last_attr->blink != $cur_attr->blink) {
527 | if ($cur_attr->blink) {
528 | $open.= '' . $close;
531 | }
532 | }
533 | $output.= $close . $open;
534 | }
535 |
536 | $output.= htmlspecialchars($char);
537 |
538 | return $output;
539 | }
540 |
541 | /**
542 | * Returns the current screen without preformating
543 | *
544 | * @access private
545 | * @return string
546 | */
547 | function _getScreen()
548 | {
549 | $output = '';
550 | $last_attr = $this->base_attr_cell;
551 | for ($i = 0; $i <= $this->max_y; $i++) {
552 | for ($j = 0; $j <= $this->max_x; $j++) {
553 | $cur_attr = $this->attrs[$i][$j];
554 | $output.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->screen[$i][$j]) ? $this->screen[$i][$j] : '');
555 | $last_attr = $this->attrs[$i][$j];
556 | }
557 | $output.= "\r\n";
558 | }
559 | $output = substr($output, 0, -2);
560 | // close any remaining open tags
561 | $output.= $this->_processCoordinate($last_attr, $this->base_attr_cell, '');
562 | return rtrim($output);
563 | }
564 |
565 | /**
566 | * Returns the current screen
567 | *
568 | * @access public
569 | * @return string
570 | */
571 | function getScreen()
572 | {
573 | return '' . $this->_getScreen() . '
';
574 | }
575 |
576 | /**
577 | * Returns the current screen and the x previous lines
578 | *
579 | * @access public
580 | * @return string
581 | */
582 | function getHistory()
583 | {
584 | $scrollback = '';
585 | $last_attr = $this->base_attr_cell;
586 | for ($i = 0; $i < count($this->history); $i++) {
587 | for ($j = 0; $j <= $this->max_x + 1; $j++) {
588 | $cur_attr = $this->history_attrs[$i][$j];
589 | $scrollback.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->history[$i][$j]) ? $this->history[$i][$j] : '');
590 | $last_attr = $this->history_attrs[$i][$j];
591 | }
592 | $scrollback.= "\r\n";
593 | }
594 | $base_attr_cell = $this->base_attr_cell;
595 | $this->base_attr_cell = $last_attr;
596 | $scrollback.= $this->_getScreen();
597 | $this->base_attr_cell = $base_attr_cell;
598 |
599 | return '' . $scrollback . '
';
600 | }
601 | }
602 |
--------------------------------------------------------------------------------
/lib/phpseclib104/File/ASN1.php:
--------------------------------------------------------------------------------
1 |
37 | * @copyright 2012 Jim Wigginton
38 | * @license http://www.opensource.org/licenses/mit-license.html MIT License
39 | * @link http://phpseclib.sourceforge.net
40 | */
41 |
42 | /**#@+
43 | * Tag Classes
44 | *
45 | * @access private
46 | * @link http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=12
47 | */
48 | define('FILE_ASN1_CLASS_UNIVERSAL', 0);
49 | define('FILE_ASN1_CLASS_APPLICATION', 1);
50 | define('FILE_ASN1_CLASS_CONTEXT_SPECIFIC', 2);
51 | define('FILE_ASN1_CLASS_PRIVATE', 3);
52 | /**#@-*/
53 |
54 | /**#@+
55 | * Tag Classes
56 | *
57 | * @access private
58 | * @link http://www.obj-sys.com/asn1tutorial/node124.html
59 | */
60 | define('FILE_ASN1_TYPE_BOOLEAN', 1);
61 | define('FILE_ASN1_TYPE_INTEGER', 2);
62 | define('FILE_ASN1_TYPE_BIT_STRING', 3);
63 | define('FILE_ASN1_TYPE_OCTET_STRING', 4);
64 | define('FILE_ASN1_TYPE_NULL', 5);
65 | define('FILE_ASN1_TYPE_OBJECT_IDENTIFIER', 6);
66 | //define('FILE_ASN1_TYPE_OBJECT_DESCRIPTOR', 7);
67 | //define('FILE_ASN1_TYPE_INSTANCE_OF', 8); // EXTERNAL
68 | define('FILE_ASN1_TYPE_REAL', 9);
69 | define('FILE_ASN1_TYPE_ENUMERATED', 10);
70 | //define('FILE_ASN1_TYPE_EMBEDDED', 11);
71 | define('FILE_ASN1_TYPE_UTF8_STRING', 12);
72 | //define('FILE_ASN1_TYPE_RELATIVE_OID', 13);
73 | define('FILE_ASN1_TYPE_SEQUENCE', 16); // SEQUENCE OF
74 | define('FILE_ASN1_TYPE_SET', 17); // SET OF
75 | /**#@-*/
76 | /**#@+
77 | * More Tag Classes
78 | *
79 | * @access private
80 | * @link http://www.obj-sys.com/asn1tutorial/node10.html
81 | */
82 | define('FILE_ASN1_TYPE_NUMERIC_STRING', 18);
83 | define('FILE_ASN1_TYPE_PRINTABLE_STRING', 19);
84 | define('FILE_ASN1_TYPE_TELETEX_STRING', 20); // T61String
85 | define('FILE_ASN1_TYPE_VIDEOTEX_STRING', 21);
86 | define('FILE_ASN1_TYPE_IA5_STRING', 22);
87 | define('FILE_ASN1_TYPE_UTC_TIME', 23);
88 | define('FILE_ASN1_TYPE_GENERALIZED_TIME', 24);
89 | define('FILE_ASN1_TYPE_GRAPHIC_STRING', 25);
90 | define('FILE_ASN1_TYPE_VISIBLE_STRING', 26); // ISO646String
91 | define('FILE_ASN1_TYPE_GENERAL_STRING', 27);
92 | define('FILE_ASN1_TYPE_UNIVERSAL_STRING', 28);
93 | //define('FILE_ASN1_TYPE_CHARACTER_STRING', 29);
94 | define('FILE_ASN1_TYPE_BMP_STRING', 30);
95 | /**#@-*/
96 |
97 | /**#@+
98 | * Tag Aliases
99 | *
100 | * These tags are kinda place holders for other tags.
101 | *
102 | * @access private
103 | */
104 | define('FILE_ASN1_TYPE_CHOICE', -1);
105 | define('FILE_ASN1_TYPE_ANY', -2);
106 | /**#@-*/
107 |
108 | /**
109 | * ASN.1 Element
110 | *
111 | * Bypass normal encoding rules in File_ASN1::encodeDER()
112 | *
113 | * @package File_ASN1
114 | * @author Jim Wigginton
115 | * @access public
116 | */
117 | class File_ASN1_Element
118 | {
119 | /**
120 | * Raw element value
121 | *
122 | * @var string
123 | * @access private
124 | */
125 | var $element;
126 |
127 | /**
128 | * Constructor
129 | *
130 | * @param string $encoded
131 | * @return File_ASN1_Element
132 | * @access public
133 | */
134 | function __construct($encoded)
135 | {
136 | $this->element = $encoded;
137 | }
138 |
139 | /**
140 | * PHP4 compatible Default Constructor.
141 | *
142 | * @see self::__construct()
143 | * @param int $mode
144 | * @access public
145 | */
146 | function File_ASN1_Element($encoded)
147 | {
148 | $this->__construct($encoded);
149 | }
150 | }
151 |
152 | /**
153 | * Pure-PHP ASN.1 Parser
154 | *
155 | * @package File_ASN1
156 | * @author Jim Wigginton
157 | * @access public
158 | */
159 | class File_ASN1
160 | {
161 | /**
162 | * ASN.1 object identifier
163 | *
164 | * @var array
165 | * @access private
166 | * @link http://en.wikipedia.org/wiki/Object_identifier
167 | */
168 | var $oids = array();
169 |
170 | /**
171 | * Default date format
172 | *
173 | * @var string
174 | * @access private
175 | * @link http://php.net/class.datetime
176 | */
177 | var $format = 'D, d M Y H:i:s O';
178 |
179 | /**
180 | * Default date format
181 | *
182 | * @var array
183 | * @access private
184 | * @see self::setTimeFormat()
185 | * @see self::asn1map()
186 | * @link http://php.net/class.datetime
187 | */
188 | var $encoded;
189 |
190 | /**
191 | * Filters
192 | *
193 | * If the mapping type is FILE_ASN1_TYPE_ANY what do we actually encode it as?
194 | *
195 | * @var array
196 | * @access private
197 | * @see self::_encode_der()
198 | */
199 | var $filters;
200 |
201 | /**
202 | * Type mapping table for the ANY type.
203 | *
204 | * Structured or unknown types are mapped to a FILE_ASN1_Element.
205 | * Unambiguous types get the direct mapping (int/real/bool).
206 | * Others are mapped as a choice, with an extra indexing level.
207 | *
208 | * @var array
209 | * @access public
210 | */
211 | var $ANYmap = array(
212 | FILE_ASN1_TYPE_BOOLEAN => true,
213 | FILE_ASN1_TYPE_INTEGER => true,
214 | FILE_ASN1_TYPE_BIT_STRING => 'bitString',
215 | FILE_ASN1_TYPE_OCTET_STRING => 'octetString',
216 | FILE_ASN1_TYPE_NULL => 'null',
217 | FILE_ASN1_TYPE_OBJECT_IDENTIFIER => 'objectIdentifier',
218 | FILE_ASN1_TYPE_REAL => true,
219 | FILE_ASN1_TYPE_ENUMERATED => 'enumerated',
220 | FILE_ASN1_TYPE_UTF8_STRING => 'utf8String',
221 | FILE_ASN1_TYPE_NUMERIC_STRING => 'numericString',
222 | FILE_ASN1_TYPE_PRINTABLE_STRING => 'printableString',
223 | FILE_ASN1_TYPE_TELETEX_STRING => 'teletexString',
224 | FILE_ASN1_TYPE_VIDEOTEX_STRING => 'videotexString',
225 | FILE_ASN1_TYPE_IA5_STRING => 'ia5String',
226 | FILE_ASN1_TYPE_UTC_TIME => 'utcTime',
227 | FILE_ASN1_TYPE_GENERALIZED_TIME => 'generalTime',
228 | FILE_ASN1_TYPE_GRAPHIC_STRING => 'graphicString',
229 | FILE_ASN1_TYPE_VISIBLE_STRING => 'visibleString',
230 | FILE_ASN1_TYPE_GENERAL_STRING => 'generalString',
231 | FILE_ASN1_TYPE_UNIVERSAL_STRING => 'universalString',
232 | //FILE_ASN1_TYPE_CHARACTER_STRING => 'characterString',
233 | FILE_ASN1_TYPE_BMP_STRING => 'bmpString'
234 | );
235 |
236 | /**
237 | * String type to character size mapping table.
238 | *
239 | * Non-convertable types are absent from this table.
240 | * size == 0 indicates variable length encoding.
241 | *
242 | * @var array
243 | * @access public
244 | */
245 | var $stringTypeSize = array(
246 | FILE_ASN1_TYPE_UTF8_STRING => 0,
247 | FILE_ASN1_TYPE_BMP_STRING => 2,
248 | FILE_ASN1_TYPE_UNIVERSAL_STRING => 4,
249 | FILE_ASN1_TYPE_PRINTABLE_STRING => 1,
250 | FILE_ASN1_TYPE_TELETEX_STRING => 1,
251 | FILE_ASN1_TYPE_IA5_STRING => 1,
252 | FILE_ASN1_TYPE_VISIBLE_STRING => 1,
253 | );
254 |
255 | /**
256 | * Default Constructor.
257 | *
258 | * @access public
259 | */
260 | function __construct()
261 | {
262 | static $static_init = null;
263 | if (!$static_init) {
264 | $static_init = true;
265 | if (!class_exists('Math_BigInteger')) {
266 | include_once 'Math/BigInteger.php';
267 | }
268 | }
269 | }
270 |
271 | /**
272 | * PHP4 compatible Default Constructor.
273 | *
274 | * @see self::__construct()
275 | * @access public
276 | */
277 | function File_ASN1()
278 | {
279 | $this->__construct($mode);
280 | }
281 |
282 | /**
283 | * Parse BER-encoding
284 | *
285 | * Serves a similar purpose to openssl's asn1parse
286 | *
287 | * @param string $encoded
288 | * @return array
289 | * @access public
290 | */
291 | function decodeBER($encoded)
292 | {
293 | if (is_object($encoded) && strtolower(get_class($encoded)) == 'file_asn1_element') {
294 | $encoded = $encoded->element;
295 | }
296 |
297 | $this->encoded = $encoded;
298 | // encapsulate in an array for BC with the old decodeBER
299 | return array($this->_decode_ber($encoded));
300 | }
301 |
302 | /**
303 | * Parse BER-encoding (Helper function)
304 | *
305 | * Sometimes we want to get the BER encoding of a particular tag. $start lets us do that without having to reencode.
306 | * $encoded is passed by reference for the recursive calls done for FILE_ASN1_TYPE_BIT_STRING and
307 | * FILE_ASN1_TYPE_OCTET_STRING. In those cases, the indefinite length is used.
308 | *
309 | * @param string $encoded
310 | * @param int $start
311 | * @param int $encoded_pos
312 | * @return array
313 | * @access private
314 | */
315 | function _decode_ber($encoded, $start = 0, $encoded_pos = 0)
316 | {
317 | $current = array('start' => $start);
318 |
319 | $type = ord($encoded[$encoded_pos++]);
320 | $start++;
321 |
322 | $constructed = ($type >> 5) & 1;
323 |
324 | $tag = $type & 0x1F;
325 | if ($tag == 0x1F) {
326 | $tag = 0;
327 | // process septets (since the eighth bit is ignored, it's not an octet)
328 | do {
329 | $loop = ord($encoded[0]) >> 7;
330 | $tag <<= 7;
331 | $tag |= ord($encoded[$encoded_pos++]) & 0x7F;
332 | $start++;
333 | } while ($loop);
334 | }
335 |
336 | // Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13
337 | $length = ord($encoded[$encoded_pos++]);
338 | $start++;
339 | if ($length == 0x80) { // indefinite length
340 | // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all
341 | // immediately available." -- paragraph 8.1.3.2.c
342 | $length = strlen($encoded) - $encoded_pos;
343 | } elseif ($length & 0x80) { // definite length, long form
344 | // technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only
345 | // support it up to four.
346 | $length&= 0x7F;
347 | $temp = substr($encoded, $encoded_pos, $length);
348 | $encoded_pos += $length;
349 | // tags of indefinte length don't really have a header length; this length includes the tag
350 | $current+= array('headerlength' => $length + 2);
351 | $start+= $length;
352 | extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)));
353 | } else {
354 | $current+= array('headerlength' => 2);
355 | }
356 |
357 | if ($length > (strlen($encoded) - $encoded_pos)) {
358 | return false;
359 | }
360 |
361 | $content = substr($encoded, $encoded_pos, $length);
362 | $content_pos = 0;
363 |
364 | // at this point $length can be overwritten. it's only accurate for definite length things as is
365 |
366 | /* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1
367 | built-in types. It defines an application-independent data type that must be distinguishable from all other
368 | data types. The other three classes are user defined. The APPLICATION class distinguishes data types that
369 | have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within
370 | a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the
371 | alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this
372 | data type; the term CONTEXT-SPECIFIC does not appear.
373 |
374 | -- http://www.obj-sys.com/asn1tutorial/node12.html */
375 | $class = ($type >> 6) & 3;
376 | switch ($class) {
377 | case FILE_ASN1_CLASS_APPLICATION:
378 | case FILE_ASN1_CLASS_PRIVATE:
379 | case FILE_ASN1_CLASS_CONTEXT_SPECIFIC:
380 | if (!$constructed) {
381 | return array(
382 | 'type' => $class,
383 | 'constant' => $tag,
384 | 'content' => $content,
385 | 'length' => $length + $start - $current['start']
386 | );
387 | }
388 |
389 | $newcontent = array();
390 | $remainingLength = $length;
391 | while ($remainingLength > 0) {
392 | $temp = $this->_decode_ber($content, $start, $content_pos);
393 | $length = $temp['length'];
394 | // end-of-content octets - see paragraph 8.1.5
395 | if (substr($content, $content_pos + $length, 2) == "\0\0") {
396 | $length+= 2;
397 | $start+= $length;
398 | $newcontent[] = $temp;
399 | break;
400 | }
401 | $start+= $length;
402 | $remainingLength-= $length;
403 | $newcontent[] = $temp;
404 | $content_pos += $length;
405 | }
406 |
407 | return array(
408 | 'type' => $class,
409 | 'constant' => $tag,
410 | // the array encapsulation is for BC with the old format
411 | 'content' => $newcontent,
412 | // the only time when $content['headerlength'] isn't defined is when the length is indefinite.
413 | // the absence of $content['headerlength'] is how we know if something is indefinite or not.
414 | // technically, it could be defined to be 2 and then another indicator could be used but whatever.
415 | 'length' => $start - $current['start']
416 | ) + $current;
417 | }
418 |
419 | $current+= array('type' => $tag);
420 |
421 | // decode UNIVERSAL tags
422 | switch ($tag) {
423 | case FILE_ASN1_TYPE_BOOLEAN:
424 | // "The contents octets shall consist of a single octet." -- paragraph 8.2.1
425 | //if (strlen($content) != 1) {
426 | // return false;
427 | //}
428 | $current['content'] = (bool) ord($content[$content_pos]);
429 | break;
430 | case FILE_ASN1_TYPE_INTEGER:
431 | case FILE_ASN1_TYPE_ENUMERATED:
432 | $current['content'] = new Math_BigInteger(substr($content, $content_pos), -256);
433 | break;
434 | case FILE_ASN1_TYPE_REAL: // not currently supported
435 | return false;
436 | case FILE_ASN1_TYPE_BIT_STRING:
437 | // The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
438 | // the number of unused bits in the final subsequent octet. The number shall be in the range zero to
439 | // seven.
440 | if (!$constructed) {
441 | $current['content'] = substr($content, $content_pos);
442 | } else {
443 | $temp = $this->_decode_ber($content, $start, $content_pos);
444 | $length-= (strlen($content) - $content_pos);
445 | $last = count($temp) - 1;
446 | for ($i = 0; $i < $last; $i++) {
447 | // all subtags should be bit strings
448 | //if ($temp[$i]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
449 | // return false;
450 | //}
451 | $current['content'].= substr($temp[$i]['content'], 1);
452 | }
453 | // all subtags should be bit strings
454 | //if ($temp[$last]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
455 | // return false;
456 | //}
457 | $current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1);
458 | }
459 | break;
460 | case FILE_ASN1_TYPE_OCTET_STRING:
461 | if (!$constructed) {
462 | $current['content'] = substr($content, $content_pos);
463 | } else {
464 | $current['content'] = '';
465 | $length = 0;
466 | while (substr($content, $content_pos, 2) != "\0\0") {
467 | $temp = $this->_decode_ber($content, $length + $start, $content_pos);
468 | $content_pos += $temp['length'];
469 | // all subtags should be octet strings
470 | //if ($temp['type'] != FILE_ASN1_TYPE_OCTET_STRING) {
471 | // return false;
472 | //}
473 | $current['content'].= $temp['content'];
474 | $length+= $temp['length'];
475 | }
476 | if (substr($content, $content_pos, 2) == "\0\0") {
477 | $length+= 2; // +2 for the EOC
478 | }
479 | }
480 | break;
481 | case FILE_ASN1_TYPE_NULL:
482 | // "The contents octets shall not contain any octets." -- paragraph 8.8.2
483 | //if (strlen($content)) {
484 | // return false;
485 | //}
486 | break;
487 | case FILE_ASN1_TYPE_SEQUENCE:
488 | case FILE_ASN1_TYPE_SET:
489 | $offset = 0;
490 | $current['content'] = array();
491 | $content_len = strlen($content);
492 | while ($content_pos < $content_len) {
493 | // if indefinite length construction was used and we have an end-of-content string next
494 | // see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2
495 | if (!isset($current['headerlength']) && substr($content, $content_pos, 2) == "\0\0") {
496 | $length = $offset + 2; // +2 for the EOC
497 | break 2;
498 | }
499 | $temp = $this->_decode_ber($content, $start + $offset, $content_pos);
500 | $content_pos += $temp['length'];
501 | $current['content'][] = $temp;
502 | $offset+= $temp['length'];
503 | }
504 | break;
505 | case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
506 | $temp = ord($content[$content_pos++]);
507 | $current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40);
508 | $valuen = 0;
509 | // process septets
510 | $content_len = strlen($content);
511 | while ($content_pos < $content_len) {
512 | $temp = ord($content[$content_pos++]);
513 | $valuen <<= 7;
514 | $valuen |= $temp & 0x7F;
515 | if (~$temp & 0x80) {
516 | $current['content'].= ".$valuen";
517 | $valuen = 0;
518 | }
519 | }
520 | // the eighth bit of the last byte should not be 1
521 | //if ($temp >> 7) {
522 | // return false;
523 | //}
524 | break;
525 | /* Each character string type shall be encoded as if it had been declared:
526 | [UNIVERSAL x] IMPLICIT OCTET STRING
527 |
528 | -- X.690-0207.pdf#page=23 (paragraph 8.21.3)
529 |
530 | Per that, we're not going to do any validation. If there are any illegal characters in the string,
531 | we don't really care */
532 | case FILE_ASN1_TYPE_NUMERIC_STRING:
533 | // 0,1,2,3,4,5,6,7,8,9, and space
534 | case FILE_ASN1_TYPE_PRINTABLE_STRING:
535 | // Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma,
536 | // hyphen, full stop, solidus, colon, equal sign, question mark
537 | case FILE_ASN1_TYPE_TELETEX_STRING:
538 | // The Teletex character set in CCITT's T61, space, and delete
539 | // see http://en.wikipedia.org/wiki/Teletex#Character_sets
540 | case FILE_ASN1_TYPE_VIDEOTEX_STRING:
541 | // The Videotex character set in CCITT's T.100 and T.101, space, and delete
542 | case FILE_ASN1_TYPE_VISIBLE_STRING:
543 | // Printing character sets of international ASCII, and space
544 | case FILE_ASN1_TYPE_IA5_STRING:
545 | // International Alphabet 5 (International ASCII)
546 | case FILE_ASN1_TYPE_GRAPHIC_STRING:
547 | // All registered G sets, and space
548 | case FILE_ASN1_TYPE_GENERAL_STRING:
549 | // All registered C and G sets, space and delete
550 | case FILE_ASN1_TYPE_UTF8_STRING:
551 | // ????
552 | case FILE_ASN1_TYPE_BMP_STRING:
553 | $current['content'] = substr($content, $content_pos);
554 | break;
555 | case FILE_ASN1_TYPE_UTC_TIME:
556 | case FILE_ASN1_TYPE_GENERALIZED_TIME:
557 | $current['content'] = $this->_decodeTime(substr($content, $content_pos), $tag);
558 | default:
559 | }
560 |
561 | $start+= $length;
562 |
563 | // ie. length is the length of the full TLV encoding - it's not just the length of the value
564 | return $current + array('length' => $start - $current['start']);
565 | }
566 |
567 | /**
568 | * ASN.1 Map
569 | *
570 | * Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format.
571 | *
572 | * "Special" mappings may be applied on a per tag-name basis via $special.
573 | *
574 | * @param array $decoded
575 | * @param array $mapping
576 | * @param array $special
577 | * @return array
578 | * @access public
579 | */
580 | function asn1map($decoded, $mapping, $special = array())
581 | {
582 | if (isset($mapping['explicit']) && is_array($decoded['content'])) {
583 | $decoded = $decoded['content'][0];
584 | }
585 |
586 | switch (true) {
587 | case $mapping['type'] == FILE_ASN1_TYPE_ANY:
588 | $intype = $decoded['type'];
589 | if (isset($decoded['constant']) || !isset($this->ANYmap[$intype]) || (ord($this->encoded[$decoded['start']]) & 0x20)) {
590 | return new File_ASN1_Element(substr($this->encoded, $decoded['start'], $decoded['length']));
591 | }
592 | $inmap = $this->ANYmap[$intype];
593 | if (is_string($inmap)) {
594 | return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping, $special));
595 | }
596 | break;
597 | case $mapping['type'] == FILE_ASN1_TYPE_CHOICE:
598 | foreach ($mapping['children'] as $key => $option) {
599 | switch (true) {
600 | case isset($option['constant']) && $option['constant'] == $decoded['constant']:
601 | case !isset($option['constant']) && $option['type'] == $decoded['type']:
602 | $value = $this->asn1map($decoded, $option, $special);
603 | break;
604 | case !isset($option['constant']) && $option['type'] == FILE_ASN1_TYPE_CHOICE:
605 | $v = $this->asn1map($decoded, $option, $special);
606 | if (isset($v)) {
607 | $value = $v;
608 | }
609 | }
610 | if (isset($value)) {
611 | if (isset($special[$key])) {
612 | $value = call_user_func($special[$key], $value);
613 | }
614 | return array($key => $value);
615 | }
616 | }
617 | return null;
618 | case isset($mapping['implicit']):
619 | case isset($mapping['explicit']):
620 | case $decoded['type'] == $mapping['type']:
621 | break;
622 | default:
623 | // if $decoded['type'] and $mapping['type'] are both strings, but different types of strings,
624 | // let it through
625 | switch (true) {
626 | case $decoded['type'] < 18: // FILE_ASN1_TYPE_NUMERIC_STRING == 18
627 | case $decoded['type'] > 30: // FILE_ASN1_TYPE_BMP_STRING == 30
628 | case $mapping['type'] < 18:
629 | case $mapping['type'] > 30:
630 | return null;
631 | }
632 | }
633 |
634 | if (isset($mapping['implicit'])) {
635 | $decoded['type'] = $mapping['type'];
636 | }
637 |
638 | switch ($decoded['type']) {
639 | case FILE_ASN1_TYPE_SEQUENCE:
640 | $map = array();
641 |
642 | // ignore the min and max
643 | if (isset($mapping['min']) && isset($mapping['max'])) {
644 | $child = $mapping['children'];
645 | foreach ($decoded['content'] as $content) {
646 | if (($map[] = $this->asn1map($content, $child, $special)) === null) {
647 | return null;
648 | }
649 | }
650 |
651 | return $map;
652 | }
653 |
654 | $n = count($decoded['content']);
655 | $i = 0;
656 |
657 | foreach ($mapping['children'] as $key => $child) {
658 | $maymatch = $i < $n; // Match only existing input.
659 | if ($maymatch) {
660 | $temp = $decoded['content'][$i];
661 |
662 | if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
663 | // Get the mapping and input class & constant.
664 | $childClass = $tempClass = FILE_ASN1_CLASS_UNIVERSAL;
665 | $constant = null;
666 | if (isset($temp['constant'])) {
667 | $tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
668 | }
669 | if (isset($child['class'])) {
670 | $childClass = $child['class'];
671 | $constant = $child['cast'];
672 | } elseif (isset($child['constant'])) {
673 | $childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
674 | $constant = $child['constant'];
675 | }
676 |
677 | if (isset($constant) && isset($temp['constant'])) {
678 | // Can only match if constants and class match.
679 | $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
680 | } else {
681 | // Can only match if no constant expected and type matches or is generic.
682 | $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
683 | }
684 | }
685 | }
686 |
687 | if ($maymatch) {
688 | // Attempt submapping.
689 | $candidate = $this->asn1map($temp, $child, $special);
690 | $maymatch = $candidate !== null;
691 | }
692 |
693 | if ($maymatch) {
694 | // Got the match: use it.
695 | if (isset($special[$key])) {
696 | $candidate = call_user_func($special[$key], $candidate);
697 | }
698 | $map[$key] = $candidate;
699 | $i++;
700 | } elseif (isset($child['default'])) {
701 | $map[$key] = $child['default']; // Use default.
702 | } elseif (!isset($child['optional'])) {
703 | return null; // Syntax error.
704 | }
705 | }
706 |
707 | // Fail mapping if all input items have not been consumed.
708 | return $i < $n ? null: $map;
709 |
710 | // the main diff between sets and sequences is the encapsulation of the foreach in another for loop
711 | case FILE_ASN1_TYPE_SET:
712 | $map = array();
713 |
714 | // ignore the min and max
715 | if (isset($mapping['min']) && isset($mapping['max'])) {
716 | $child = $mapping['children'];
717 | foreach ($decoded['content'] as $content) {
718 | if (($map[] = $this->asn1map($content, $child, $special)) === null) {
719 | return null;
720 | }
721 | }
722 |
723 | return $map;
724 | }
725 |
726 | for ($i = 0; $i < count($decoded['content']); $i++) {
727 | $temp = $decoded['content'][$i];
728 | $tempClass = FILE_ASN1_CLASS_UNIVERSAL;
729 | if (isset($temp['constant'])) {
730 | $tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
731 | }
732 |
733 | foreach ($mapping['children'] as $key => $child) {
734 | if (isset($map[$key])) {
735 | continue;
736 | }
737 | $maymatch = true;
738 | if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
739 | $childClass = FILE_ASN1_CLASS_UNIVERSAL;
740 | $constant = null;
741 | if (isset($child['class'])) {
742 | $childClass = $child['class'];
743 | $constant = $child['cast'];
744 | } elseif (isset($child['constant'])) {
745 | $childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
746 | $constant = $child['constant'];
747 | }
748 |
749 | if (isset($constant) && isset($temp['constant'])) {
750 | // Can only match if constants and class match.
751 | $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
752 | } else {
753 | // Can only match if no constant expected and type matches or is generic.
754 | $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
755 | }
756 | }
757 |
758 | if ($maymatch) {
759 | // Attempt submapping.
760 | $candidate = $this->asn1map($temp, $child, $special);
761 | $maymatch = $candidate !== null;
762 | }
763 |
764 | if (!$maymatch) {
765 | break;
766 | }
767 |
768 | // Got the match: use it.
769 | if (isset($special[$key])) {
770 | $candidate = call_user_func($special[$key], $candidate);
771 | }
772 | $map[$key] = $candidate;
773 | break;
774 | }
775 | }
776 |
777 | foreach ($mapping['children'] as $key => $child) {
778 | if (!isset($map[$key])) {
779 | if (isset($child['default'])) {
780 | $map[$key] = $child['default'];
781 | } elseif (!isset($child['optional'])) {
782 | return null;
783 | }
784 | }
785 | }
786 | return $map;
787 | case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
788 | return isset($this->oids[$decoded['content']]) ? $this->oids[$decoded['content']] : $decoded['content'];
789 | case FILE_ASN1_TYPE_UTC_TIME:
790 | case FILE_ASN1_TYPE_GENERALIZED_TIME:
791 | if (isset($mapping['implicit'])) {
792 | $decoded['content'] = $this->_decodeTime($decoded['content'], $decoded['type']);
793 | }
794 | return @date($this->format, $decoded['content']);
795 | case FILE_ASN1_TYPE_BIT_STRING:
796 | if (isset($mapping['mapping'])) {
797 | $offset = ord($decoded['content'][0]);
798 | $size = (strlen($decoded['content']) - 1) * 8 - $offset;
799 | /*
800 | From X.680-0207.pdf#page=46 (21.7):
801 |
802 | "When a "NamedBitList" is used in defining a bitstring type ASN.1 encoding rules are free to add (or remove)
803 | arbitrarily any trailing 0 bits to (or from) values that are being encoded or decoded. Application designers should
804 | therefore ensure that different semantics are not associated with such values which differ only in the number of trailing
805 | 0 bits."
806 | */
807 | $bits = count($mapping['mapping']) == $size ? array() : array_fill(0, count($mapping['mapping']) - $size, false);
808 | for ($i = strlen($decoded['content']) - 1; $i > 0; $i--) {
809 | $current = ord($decoded['content'][$i]);
810 | for ($j = $offset; $j < 8; $j++) {
811 | $bits[] = (bool) ($current & (1 << $j));
812 | }
813 | $offset = 0;
814 | }
815 | $values = array();
816 | $map = array_reverse($mapping['mapping']);
817 | foreach ($map as $i => $value) {
818 | if ($bits[$i]) {
819 | $values[] = $value;
820 | }
821 | }
822 | return $values;
823 | }
824 | case FILE_ASN1_TYPE_OCTET_STRING:
825 | return base64_encode($decoded['content']);
826 | case FILE_ASN1_TYPE_NULL:
827 | return '';
828 | case FILE_ASN1_TYPE_BOOLEAN:
829 | return $decoded['content'];
830 | case FILE_ASN1_TYPE_NUMERIC_STRING:
831 | case FILE_ASN1_TYPE_PRINTABLE_STRING:
832 | case FILE_ASN1_TYPE_TELETEX_STRING:
833 | case FILE_ASN1_TYPE_VIDEOTEX_STRING:
834 | case FILE_ASN1_TYPE_IA5_STRING:
835 | case FILE_ASN1_TYPE_GRAPHIC_STRING:
836 | case FILE_ASN1_TYPE_VISIBLE_STRING:
837 | case FILE_ASN1_TYPE_GENERAL_STRING:
838 | case FILE_ASN1_TYPE_UNIVERSAL_STRING:
839 | case FILE_ASN1_TYPE_UTF8_STRING:
840 | case FILE_ASN1_TYPE_BMP_STRING:
841 | return $decoded['content'];
842 | case FILE_ASN1_TYPE_INTEGER:
843 | case FILE_ASN1_TYPE_ENUMERATED:
844 | $temp = $decoded['content'];
845 | if (isset($mapping['implicit'])) {
846 | $temp = new Math_BigInteger($decoded['content'], -256);
847 | }
848 | if (isset($mapping['mapping'])) {
849 | $temp = (int) $temp->toString();
850 | return isset($mapping['mapping'][$temp]) ?
851 | $mapping['mapping'][$temp] :
852 | false;
853 | }
854 | return $temp;
855 | }
856 | }
857 |
858 | /**
859 | * ASN.1 Encode
860 | *
861 | * DER-encodes an ASN.1 semantic mapping ($mapping). Some libraries would probably call this function
862 | * an ASN.1 compiler.
863 | *
864 | * "Special" mappings can be applied via $special.
865 | *
866 | * @param string $source
867 | * @param string $mapping
868 | * @param int $idx
869 | * @return string
870 | * @access public
871 | */
872 | function encodeDER($source, $mapping, $special = array())
873 | {
874 | $this->location = array();
875 | return $this->_encode_der($source, $mapping, null, $special);
876 | }
877 |
878 | /**
879 | * ASN.1 Encode (Helper function)
880 | *
881 | * @param string $source
882 | * @param string $mapping
883 | * @param int $idx
884 | * @return string
885 | * @access private
886 | */
887 | function _encode_der($source, $mapping, $idx = null, $special = array())
888 | {
889 | if (is_object($source) && strtolower(get_class($source)) == 'file_asn1_element') {
890 | return $source->element;
891 | }
892 |
893 | // do not encode (implicitly optional) fields with value set to default
894 | if (isset($mapping['default']) && $source === $mapping['default']) {
895 | return '';
896 | }
897 |
898 | if (isset($idx)) {
899 | if (isset($special[$idx])) {
900 | $source = call_user_func($special[$idx], $source);
901 | }
902 | $this->location[] = $idx;
903 | }
904 |
905 | $tag = $mapping['type'];
906 |
907 | switch ($tag) {
908 | case FILE_ASN1_TYPE_SET: // Children order is not important, thus process in sequence.
909 | case FILE_ASN1_TYPE_SEQUENCE:
910 | $tag|= 0x20; // set the constructed bit
911 |
912 | // ignore the min and max
913 | if (isset($mapping['min']) && isset($mapping['max'])) {
914 | $value = array();
915 | $child = $mapping['children'];
916 |
917 | foreach ($source as $content) {
918 | $temp = $this->_encode_der($content, $child, null, $special);
919 | if ($temp === false) {
920 | return false;
921 | }
922 | $value[]= $temp;
923 | }
924 | /* "The encodings of the component values of a set-of value shall appear in ascending order, the encodings being compared
925 | as octet strings with the shorter components being padded at their trailing end with 0-octets.
926 | NOTE - The padding octets are for comparison purposes only and do not appear in the encodings."
927 |
928 | -- sec 11.6 of http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf */
929 | if ($mapping['type'] == FILE_ASN1_TYPE_SET) {
930 | sort($value);
931 | }
932 | $value = implode($value, '');
933 | break;
934 | }
935 |
936 | $value = '';
937 | foreach ($mapping['children'] as $key => $child) {
938 | if (!array_key_exists($key, $source)) {
939 | if (!isset($child['optional'])) {
940 | return false;
941 | }
942 | continue;
943 | }
944 |
945 | $temp = $this->_encode_der($source[$key], $child, $key, $special);
946 | if ($temp === false) {
947 | return false;
948 | }
949 |
950 | // An empty child encoding means it has been optimized out.
951 | // Else we should have at least one tag byte.
952 | if ($temp === '') {
953 | continue;
954 | }
955 |
956 | // if isset($child['constant']) is true then isset($child['optional']) should be true as well
957 | if (isset($child['constant'])) {
958 | /*
959 | From X.680-0207.pdf#page=58 (30.6):
960 |
961 | "The tagging construction specifies explicit tagging if any of the following holds:
962 | ...
963 | c) the "Tag Type" alternative is used and the value of "TagDefault" for the module is IMPLICIT TAGS or
964 | AUTOMATIC TAGS, but the type defined by "Type" is an untagged choice type, an untagged open type, or
965 | an untagged "DummyReference" (see ITU-T Rec. X.683 | ISO/IEC 8824-4, 8.3)."
966 | */
967 | if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
968 | $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
969 | $temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
970 | } else {
971 | $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
972 | $temp = $subtag . substr($temp, 1);
973 | }
974 | }
975 | $value.= $temp;
976 | }
977 | break;
978 | case FILE_ASN1_TYPE_CHOICE:
979 | $temp = false;
980 |
981 | foreach ($mapping['children'] as $key => $child) {
982 | if (!isset($source[$key])) {
983 | continue;
984 | }
985 |
986 | $temp = $this->_encode_der($source[$key], $child, $key, $special);
987 | if ($temp === false) {
988 | return false;
989 | }
990 |
991 | // An empty child encoding means it has been optimized out.
992 | // Else we should have at least one tag byte.
993 | if ($temp === '') {
994 | continue;
995 | }
996 |
997 | $tag = ord($temp[0]);
998 |
999 | // if isset($child['constant']) is true then isset($child['optional']) should be true as well
1000 | if (isset($child['constant'])) {
1001 | if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
1002 | $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
1003 | $temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
1004 | } else {
1005 | $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
1006 | $temp = $subtag . substr($temp, 1);
1007 | }
1008 | }
1009 | }
1010 |
1011 | if (isset($idx)) {
1012 | array_pop($this->location);
1013 | }
1014 |
1015 | if ($temp && isset($mapping['cast'])) {
1016 | $temp[0] = chr(($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast']);
1017 | }
1018 |
1019 | return $temp;
1020 | case FILE_ASN1_TYPE_INTEGER:
1021 | case FILE_ASN1_TYPE_ENUMERATED:
1022 | if (!isset($mapping['mapping'])) {
1023 | if (is_numeric($source)) {
1024 | $source = new Math_BigInteger($source);
1025 | }
1026 | $value = $source->toBytes(true);
1027 | } else {
1028 | $value = array_search($source, $mapping['mapping']);
1029 | if ($value === false) {
1030 | return false;
1031 | }
1032 | $value = new Math_BigInteger($value);
1033 | $value = $value->toBytes(true);
1034 | }
1035 | if (!strlen($value)) {
1036 | $value = chr(0);
1037 | }
1038 | break;
1039 | case FILE_ASN1_TYPE_UTC_TIME:
1040 | case FILE_ASN1_TYPE_GENERALIZED_TIME:
1041 | $format = $mapping['type'] == FILE_ASN1_TYPE_UTC_TIME ? 'y' : 'Y';
1042 | $format.= 'mdHis';
1043 | $value = @gmdate($format, strtotime($source)) . 'Z';
1044 | break;
1045 | case FILE_ASN1_TYPE_BIT_STRING:
1046 | if (isset($mapping['mapping'])) {
1047 | $bits = array_fill(0, count($mapping['mapping']), 0);
1048 | $size = 0;
1049 | for ($i = 0; $i < count($mapping['mapping']); $i++) {
1050 | if (in_array($mapping['mapping'][$i], $source)) {
1051 | $bits[$i] = 1;
1052 | $size = $i;
1053 | }
1054 | }
1055 |
1056 | if (isset($mapping['min']) && $mapping['min'] >= 1 && $size < $mapping['min']) {
1057 | $size = $mapping['min'] - 1;
1058 | }
1059 |
1060 | $offset = 8 - (($size + 1) & 7);
1061 | $offset = $offset !== 8 ? $offset : 0;
1062 |
1063 | $value = chr($offset);
1064 |
1065 | for ($i = $size + 1; $i < count($mapping['mapping']); $i++) {
1066 | unset($bits[$i]);
1067 | }
1068 |
1069 | $bits = implode('', array_pad($bits, $size + $offset + 1, 0));
1070 | $bytes = explode(' ', rtrim(chunk_split($bits, 8, ' ')));
1071 | foreach ($bytes as $byte) {
1072 | $value.= chr(bindec($byte));
1073 | }
1074 |
1075 | break;
1076 | }
1077 | case FILE_ASN1_TYPE_OCTET_STRING:
1078 | /* The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
1079 | the number of unused bits in the final subsequent octet. The number shall be in the range zero to seven.
1080 |
1081 | -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=16 */
1082 | $value = base64_decode($source);
1083 | break;
1084 | case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
1085 | $oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
1086 | if ($oid === false) {
1087 | user_error('Invalid OID');
1088 | return false;
1089 | }
1090 | $value = '';
1091 | $parts = explode('.', $oid);
1092 | $value = chr(40 * $parts[0] + $parts[1]);
1093 | for ($i = 2; $i < count($parts); $i++) {
1094 | $temp = '';
1095 | if (!$parts[$i]) {
1096 | $temp = "\0";
1097 | } else {
1098 | while ($parts[$i]) {
1099 | $temp = chr(0x80 | ($parts[$i] & 0x7F)) . $temp;
1100 | $parts[$i] >>= 7;
1101 | }
1102 | $temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
1103 | }
1104 | $value.= $temp;
1105 | }
1106 | break;
1107 | case FILE_ASN1_TYPE_ANY:
1108 | $loc = $this->location;
1109 | if (isset($idx)) {
1110 | array_pop($this->location);
1111 | }
1112 |
1113 | switch (true) {
1114 | case !isset($source):
1115 | return $this->_encode_der(null, array('type' => FILE_ASN1_TYPE_NULL) + $mapping, null, $special);
1116 | case is_int($source):
1117 | case is_object($source) && strtolower(get_class($source)) == 'math_biginteger':
1118 | return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_INTEGER) + $mapping, null, $special);
1119 | case is_float($source):
1120 | return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_REAL) + $mapping, null, $special);
1121 | case is_bool($source):
1122 | return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_BOOLEAN) + $mapping, null, $special);
1123 | case is_array($source) && count($source) == 1:
1124 | $typename = implode('', array_keys($source));
1125 | $outtype = array_search($typename, $this->ANYmap, true);
1126 | if ($outtype !== false) {
1127 | return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping, null, $special);
1128 | }
1129 | }
1130 |
1131 | $filters = $this->filters;
1132 | foreach ($loc as $part) {
1133 | if (!isset($filters[$part])) {
1134 | $filters = false;
1135 | break;
1136 | }
1137 | $filters = $filters[$part];
1138 | }
1139 | if ($filters === false) {
1140 | user_error('No filters defined for ' . implode('/', $loc));
1141 | return false;
1142 | }
1143 | return $this->_encode_der($source, $filters + $mapping, null, $special);
1144 | case FILE_ASN1_TYPE_NULL:
1145 | $value = '';
1146 | break;
1147 | case FILE_ASN1_TYPE_NUMERIC_STRING:
1148 | case FILE_ASN1_TYPE_TELETEX_STRING:
1149 | case FILE_ASN1_TYPE_PRINTABLE_STRING:
1150 | case FILE_ASN1_TYPE_UNIVERSAL_STRING:
1151 | case FILE_ASN1_TYPE_UTF8_STRING:
1152 | case FILE_ASN1_TYPE_BMP_STRING:
1153 | case FILE_ASN1_TYPE_IA5_STRING:
1154 | case FILE_ASN1_TYPE_VISIBLE_STRING:
1155 | case FILE_ASN1_TYPE_VIDEOTEX_STRING:
1156 | case FILE_ASN1_TYPE_GRAPHIC_STRING:
1157 | case FILE_ASN1_TYPE_GENERAL_STRING:
1158 | $value = $source;
1159 | break;
1160 | case FILE_ASN1_TYPE_BOOLEAN:
1161 | $value = $source ? "\xFF" : "\x00";
1162 | break;
1163 | default:
1164 | user_error('Mapping provides no type definition for ' . implode('/', $this->location));
1165 | return false;
1166 | }
1167 |
1168 | if (isset($idx)) {
1169 | array_pop($this->location);
1170 | }
1171 |
1172 | if (isset($mapping['cast'])) {
1173 | if (isset($mapping['explicit']) || $mapping['type'] == FILE_ASN1_TYPE_CHOICE) {
1174 | $value = chr($tag) . $this->_encodeLength(strlen($value)) . $value;
1175 | $tag = ($mapping['class'] << 6) | 0x20 | $mapping['cast'];
1176 | } else {
1177 | $tag = ($mapping['class'] << 6) | (ord($temp[0]) & 0x20) | $mapping['cast'];
1178 | }
1179 | }
1180 |
1181 | return chr($tag) . $this->_encodeLength(strlen($value)) . $value;
1182 | }
1183 |
1184 | /**
1185 | * DER-encode the length
1186 | *
1187 | * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
1188 | * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
1189 | *
1190 | * @access private
1191 | * @param int $length
1192 | * @return string
1193 | */
1194 | function _encodeLength($length)
1195 | {
1196 | if ($length <= 0x7F) {
1197 | return chr($length);
1198 | }
1199 |
1200 | $temp = ltrim(pack('N', $length), chr(0));
1201 | return pack('Ca*', 0x80 | strlen($temp), $temp);
1202 | }
1203 |
1204 | /**
1205 | * BER-decode the time
1206 | *
1207 | * Called by _decode_ber() and in the case of implicit tags asn1map().
1208 | *
1209 | * @access private
1210 | * @param string $content
1211 | * @param int $tag
1212 | * @return string
1213 | */
1214 | function _decodeTime($content, $tag)
1215 | {
1216 | /* UTCTime:
1217 | http://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
1218 | http://www.obj-sys.com/asn1tutorial/node15.html
1219 |
1220 | GeneralizedTime:
1221 | http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
1222 | http://www.obj-sys.com/asn1tutorial/node14.html */
1223 |
1224 | $pattern = $tag == FILE_ASN1_TYPE_UTC_TIME ?
1225 | '#(..)(..)(..)(..)(..)(..)(.*)#' :
1226 | '#(....)(..)(..)(..)(..)(..).*([Z+-].*)$#';
1227 |
1228 | preg_match($pattern, $content, $matches);
1229 |
1230 | list(, $year, $month, $day, $hour, $minute, $second, $timezone) = $matches;
1231 |
1232 | if ($tag == FILE_ASN1_TYPE_UTC_TIME) {
1233 | $year = $year >= 50 ? "19$year" : "20$year";
1234 | }
1235 |
1236 | if ($timezone == 'Z') {
1237 | $mktime = 'gmmktime';
1238 | $timezone = 0;
1239 | } elseif (preg_match('#([+-])(\d\d)(\d\d)#', $timezone, $matches)) {
1240 | $mktime = 'gmmktime';
1241 | $timezone = 60 * $matches[3] + 3600 * $matches[2];
1242 | if ($matches[1] == '-') {
1243 | $timezone = -$timezone;
1244 | }
1245 | } else {
1246 | $mktime = 'mktime';
1247 | $timezone = 0;
1248 | }
1249 |
1250 | return @$mktime($hour, $minute, $second, $month, $day, $year) + $timezone;
1251 | }
1252 |
1253 | /**
1254 | * Set the time format
1255 | *
1256 | * Sets the time / date format for asn1map().
1257 | *
1258 | * @access public
1259 | * @param string $format
1260 | */
1261 | function setTimeFormat($format)
1262 | {
1263 | $this->format = $format;
1264 | }
1265 |
1266 | /**
1267 | * Load OIDs
1268 | *
1269 | * Load the relevant OIDs for a particular ASN.1 semantic mapping.
1270 | *
1271 | * @access public
1272 | * @param array $oids
1273 | */
1274 | function loadOIDs($oids)
1275 | {
1276 | $this->oids = $oids;
1277 | }
1278 |
1279 | /**
1280 | * Load filters
1281 | *
1282 | * See File_X509, etc, for an example.
1283 | *
1284 | * @access public
1285 | * @param array $filters
1286 | */
1287 | function loadFilters($filters)
1288 | {
1289 | $this->filters = $filters;
1290 | }
1291 |
1292 | /**
1293 | * String Shift
1294 | *
1295 | * Inspired by array_shift
1296 | *
1297 | * @param string $string
1298 | * @param int $index
1299 | * @return string
1300 | * @access private
1301 | */
1302 | function _string_shift(&$string, $index = 1)
1303 | {
1304 | $substr = substr($string, 0, $index);
1305 | $string = substr($string, $index);
1306 | return $substr;
1307 | }
1308 |
1309 | /**
1310 | * String type conversion
1311 | *
1312 | * This is a lazy conversion, dealing only with character size.
1313 | * No real conversion table is used.
1314 | *
1315 | * @param string $in
1316 | * @param int $from
1317 | * @param int $to
1318 | * @return string
1319 | * @access public
1320 | */
1321 | function convert($in, $from = FILE_ASN1_TYPE_UTF8_STRING, $to = FILE_ASN1_TYPE_UTF8_STRING)
1322 | {
1323 | if (!isset($this->stringTypeSize[$from]) || !isset($this->stringTypeSize[$to])) {
1324 | return false;
1325 | }
1326 | $insize = $this->stringTypeSize[$from];
1327 | $outsize = $this->stringTypeSize[$to];
1328 | $inlength = strlen($in);
1329 | $out = '';
1330 |
1331 | for ($i = 0; $i < $inlength;) {
1332 | if ($inlength - $i < $insize) {
1333 | return false;
1334 | }
1335 |
1336 | // Get an input character as a 32-bit value.
1337 | $c = ord($in[$i++]);
1338 | switch (true) {
1339 | case $insize == 4:
1340 | $c = ($c << 8) | ord($in[$i++]);
1341 | $c = ($c << 8) | ord($in[$i++]);
1342 | case $insize == 2:
1343 | $c = ($c << 8) | ord($in[$i++]);
1344 | case $insize == 1:
1345 | break;
1346 | case ($c & 0x80) == 0x00:
1347 | break;
1348 | case ($c & 0x40) == 0x00:
1349 | return false;
1350 | default:
1351 | $bit = 6;
1352 | do {
1353 | if ($bit > 25 || $i >= $inlength || (ord($in[$i]) & 0xC0) != 0x80) {
1354 | return false;
1355 | }
1356 | $c = ($c << 6) | (ord($in[$i++]) & 0x3F);
1357 | $bit += 5;
1358 | $mask = 1 << $bit;
1359 | } while ($c & $bit);
1360 | $c &= $mask - 1;
1361 | break;
1362 | }
1363 |
1364 | // Convert and append the character to output string.
1365 | $v = '';
1366 | switch (true) {
1367 | case $outsize == 4:
1368 | $v .= chr($c & 0xFF);
1369 | $c >>= 8;
1370 | $v .= chr($c & 0xFF);
1371 | $c >>= 8;
1372 | case $outsize == 2:
1373 | $v .= chr($c & 0xFF);
1374 | $c >>= 8;
1375 | case $outsize == 1:
1376 | $v .= chr($c & 0xFF);
1377 | $c >>= 8;
1378 | if ($c) {
1379 | return false;
1380 | }
1381 | break;
1382 | case ($c & 0x80000000) != 0:
1383 | return false;
1384 | case $c >= 0x04000000:
1385 | $v .= chr(0x80 | ($c & 0x3F));
1386 | $c = ($c >> 6) | 0x04000000;
1387 | case $c >= 0x00200000:
1388 | $v .= chr(0x80 | ($c & 0x3F));
1389 | $c = ($c >> 6) | 0x00200000;
1390 | case $c >= 0x00010000:
1391 | $v .= chr(0x80 | ($c & 0x3F));
1392 | $c = ($c >> 6) | 0x00010000;
1393 | case $c >= 0x00000800:
1394 | $v .= chr(0x80 | ($c & 0x3F));
1395 | $c = ($c >> 6) | 0x00000800;
1396 | case $c >= 0x00000080:
1397 | $v .= chr(0x80 | ($c & 0x3F));
1398 | $c = ($c >> 6) | 0x000000C0;
1399 | default:
1400 | $v .= chr($c);
1401 | break;
1402 | }
1403 | $out .= strrev($v);
1404 | }
1405 | return $out;
1406 | }
1407 | }
1408 |
--------------------------------------------------------------------------------
/lib/phpseclib104/System/SSH/Agent.php:
--------------------------------------------------------------------------------
1 |
10 | * login('username', $agent)) {
18 | * exit('Login Failed');
19 | * }
20 | *
21 | * echo $ssh->exec('pwd');
22 | * echo $ssh->exec('ls -la');
23 | * ?>
24 | *
25 | *
26 | * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
27 | * of this software and associated documentation files (the "Software"), to deal
28 | * in the Software without restriction, including without limitation the rights
29 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30 | * copies of the Software, and to permit persons to whom the Software is
31 | * furnished to do so, subject to the following conditions:
32 | *
33 | * The above copyright notice and this permission notice shall be included in
34 | * all copies or substantial portions of the Software.
35 | *
36 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
39 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
42 | * THE SOFTWARE.
43 | *
44 | * @category System
45 | * @package System_SSH_Agent
46 | * @author Jim Wigginton
47 | * @copyright 2014 Jim Wigginton
48 | * @license http://www.opensource.org/licenses/mit-license.html MIT License
49 | * @link http://phpseclib.sourceforge.net
50 | * @internal See http://api.libssh.org/rfc/PROTOCOL.agent
51 | */
52 |
53 | /**#@+
54 | * Message numbers
55 | *
56 | * @access private
57 | */
58 | // to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1)
59 | define('SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES', 11);
60 | // this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2).
61 | define('SYSTEM_SSH_AGENT_IDENTITIES_ANSWER', 12);
62 | define('SYSTEM_SSH_AGENT_FAILURE', 5);
63 | // the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3)
64 | define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13);
65 | // the SSH1 response is SSH_AGENT_RSA_RESPONSE (4)
66 | define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14);
67 |
68 |
69 | /**@+
70 | * Agent forwarding status
71 | *
72 | * @access private
73 | */
74 | // no forwarding requested and not active
75 | define('SYSTEM_SSH_AGENT_FORWARD_NONE', 0);
76 | // request agent forwarding when opportune
77 | define('SYSTEM_SSH_AGENT_FORWARD_REQUEST', 1);
78 | // forwarding has been request and is active
79 | define('SYSTEM_SSH_AGENT_FORWARD_ACTIVE', 2);
80 |
81 | /**#@-*/
82 |
83 | /**
84 | * Pure-PHP ssh-agent client identity object
85 | *
86 | * Instantiation should only be performed by System_SSH_Agent class.
87 | * This could be thought of as implementing an interface that Crypt_RSA
88 | * implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something.
89 | * The methods in this interface would be getPublicKey, setSignatureMode
90 | * and sign since those are the methods phpseclib looks for to perform
91 | * public key authentication.
92 | *
93 | * @package System_SSH_Agent
94 | * @author Jim Wigginton
95 | * @access internal
96 | */
97 | class System_SSH_Agent_Identity
98 | {
99 | /**
100 | * Key Object
101 | *
102 | * @var Crypt_RSA
103 | * @access private
104 | * @see self::getPublicKey()
105 | */
106 | var $key;
107 |
108 | /**
109 | * Key Blob
110 | *
111 | * @var string
112 | * @access private
113 | * @see self::sign()
114 | */
115 | var $key_blob;
116 |
117 | /**
118 | * Socket Resource
119 | *
120 | * @var resource
121 | * @access private
122 | * @see self::sign()
123 | */
124 | var $fsock;
125 |
126 | /**
127 | * Default Constructor.
128 | *
129 | * @param resource $fsock
130 | * @return System_SSH_Agent_Identity
131 | * @access private
132 | */
133 | function __construct($fsock)
134 | {
135 | $this->fsock = $fsock;
136 | }
137 |
138 | /**
139 | * PHP4 compatible Default Constructor.
140 | *
141 | * @see self::__construct()
142 | * @param resource $fsock
143 | * @access public
144 | */
145 | function System_SSH_Agent_Identity($fsock)
146 | {
147 | $this->__construct($fsock);
148 | }
149 |
150 | /**
151 | * Set Public Key
152 | *
153 | * Called by System_SSH_Agent::requestIdentities()
154 | *
155 | * @param Crypt_RSA $key
156 | * @access private
157 | */
158 | function setPublicKey($key)
159 | {
160 | $this->key = $key;
161 | $this->key->setPublicKey();
162 | }
163 |
164 | /**
165 | * Set Public Key
166 | *
167 | * Called by System_SSH_Agent::requestIdentities(). The key blob could be extracted from $this->key
168 | * but this saves a small amount of computation.
169 | *
170 | * @param string $key_blob
171 | * @access private
172 | */
173 | function setPublicKeyBlob($key_blob)
174 | {
175 | $this->key_blob = $key_blob;
176 | }
177 |
178 | /**
179 | * Get Public Key
180 | *
181 | * Wrapper for $this->key->getPublicKey()
182 | *
183 | * @param int $format optional
184 | * @return mixed
185 | * @access public
186 | */
187 | function getPublicKey($format = null)
188 | {
189 | return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format);
190 | }
191 |
192 | /**
193 | * Set Signature Mode
194 | *
195 | * Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie.
196 | * ssh-agent's only supported mode is CRYPT_RSA_SIGNATURE_PKCS1
197 | *
198 | * @param int $mode
199 | * @access public
200 | */
201 | function setSignatureMode($mode)
202 | {
203 | }
204 |
205 | /**
206 | * Create a signature
207 | *
208 | * See "2.6.2 Protocol 2 private key signature request"
209 | *
210 | * @param string $message
211 | * @return string
212 | * @access public
213 | */
214 | function sign($message)
215 | {
216 | // the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE
217 | $packet = pack('CNa*Na*N', SYSTEM_SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0);
218 | $packet = pack('Na*', strlen($packet), $packet);
219 | if (strlen($packet) != fputs($this->fsock, $packet)) {
220 | user_error('Connection closed during signing');
221 | }
222 |
223 | $length = current(unpack('N', fread($this->fsock, 4)));
224 | $type = ord(fread($this->fsock, 1));
225 | if ($type != SYSTEM_SSH_AGENT_SIGN_RESPONSE) {
226 | user_error('Unable to retreive signature');
227 | }
228 |
229 | $signature_blob = fread($this->fsock, $length - 1);
230 | // the only other signature format defined - ssh-dss - is the same length as ssh-rsa
231 | // the + 12 is for the other various SSH added length fields
232 | return substr($signature_blob, strlen('ssh-rsa') + 12);
233 | }
234 | }
235 |
236 | /**
237 | * Pure-PHP ssh-agent client identity factory
238 | *
239 | * requestIdentities() method pumps out System_SSH_Agent_Identity objects
240 | *
241 | * @package System_SSH_Agent
242 | * @author Jim Wigginton
243 | * @access internal
244 | */
245 | class System_SSH_Agent
246 | {
247 | /**
248 | * Socket Resource
249 | *
250 | * @var resource
251 | * @access private
252 | */
253 | var $fsock;
254 |
255 | /**
256 | * Agent forwarding status
257 | *
258 | * @access private
259 | */
260 | var $forward_status = SYSTEM_SSH_AGENT_FORWARD_NONE;
261 |
262 | /**
263 | * Buffer for accumulating forwarded authentication
264 | * agent data arriving on SSH data channel destined
265 | * for agent unix socket
266 | *
267 | * @access private
268 | */
269 | var $socket_buffer = '';
270 |
271 | /**
272 | * Tracking the number of bytes we are expecting
273 | * to arrive for the agent socket on the SSH data
274 | * channel
275 | */
276 | var $expected_bytes = 0;
277 |
278 | /**
279 | * Default Constructor
280 | *
281 | * @return System_SSH_Agent
282 | * @access public
283 | */
284 | function __construct()
285 | {
286 | switch (true) {
287 | case isset($_SERVER['SSH_AUTH_SOCK']):
288 | $address = $_SERVER['SSH_AUTH_SOCK'];
289 | break;
290 | case isset($_ENV['SSH_AUTH_SOCK']):
291 | $address = $_ENV['SSH_AUTH_SOCK'];
292 | break;
293 | default:
294 | user_error('SSH_AUTH_SOCK not found');
295 | return false;
296 | }
297 |
298 | $this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
299 | if (!$this->fsock) {
300 | user_error("Unable to connect to ssh-agent (Error $errno: $errstr)");
301 | }
302 | }
303 |
304 | /**
305 | * PHP4 compatible Default Constructor.
306 | *
307 | * @see self::__construct()
308 | * @access public
309 | */
310 | function System_SSH_Agent()
311 | {
312 | $this->__construct();
313 | }
314 |
315 | /**
316 | * Request Identities
317 | *
318 | * See "2.5.2 Requesting a list of protocol 2 keys"
319 | * Returns an array containing zero or more System_SSH_Agent_Identity objects
320 | *
321 | * @return array
322 | * @access public
323 | */
324 | function requestIdentities()
325 | {
326 | if (!$this->fsock) {
327 | return array();
328 | }
329 |
330 | $packet = pack('NC', 1, SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES);
331 | if (strlen($packet) != fputs($this->fsock, $packet)) {
332 | user_error('Connection closed while requesting identities');
333 | }
334 |
335 | $length = current(unpack('N', fread($this->fsock, 4)));
336 | $type = ord(fread($this->fsock, 1));
337 | if ($type != SYSTEM_SSH_AGENT_IDENTITIES_ANSWER) {
338 | user_error('Unable to request identities');
339 | }
340 |
341 | $identities = array();
342 | $keyCount = current(unpack('N', fread($this->fsock, 4)));
343 | for ($i = 0; $i < $keyCount; $i++) {
344 | $length = current(unpack('N', fread($this->fsock, 4)));
345 | $key_blob = fread($this->fsock, $length);
346 | $key_str = 'ssh-rsa ' . base64_encode($key_blob);
347 | $length = current(unpack('N', fread($this->fsock, 4)));
348 | if ($length) {
349 | $key_str.= ' ' . fread($this->fsock, $length);
350 | }
351 | $length = current(unpack('N', substr($key_blob, 0, 4)));
352 | $key_type = substr($key_blob, 4, $length);
353 | switch ($key_type) {
354 | case 'ssh-rsa':
355 | if (!class_exists('Crypt_RSA')) {
356 | include_once 'Crypt/RSA.php';
357 | }
358 | $key = new Crypt_RSA();
359 | $key->loadKey($key_str);
360 | break;
361 | case 'ssh-dss':
362 | // not currently supported
363 | break;
364 | }
365 | // resources are passed by reference by default
366 | if (isset($key)) {
367 | $identity = new System_SSH_Agent_Identity($this->fsock);
368 | $identity->setPublicKey($key);
369 | $identity->setPublicKeyBlob($key_blob);
370 | $identities[] = $identity;
371 | unset($key);
372 | }
373 | }
374 |
375 | return $identities;
376 | }
377 |
378 | /**
379 | * Signal that agent forwarding should
380 | * be requested when a channel is opened
381 | *
382 | * @param Net_SSH2 $ssh
383 | * @return bool
384 | * @access public
385 | */
386 | function startSSHForwarding($ssh)
387 | {
388 | if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_NONE) {
389 | $this->forward_status = SYSTEM_SSH_AGENT_FORWARD_REQUEST;
390 | }
391 | }
392 |
393 | /**
394 | * Request agent forwarding of remote server
395 | *
396 | * @param Net_SSH2 $ssh
397 | * @return bool
398 | * @access private
399 | */
400 | function _request_forwarding($ssh)
401 | {
402 | $request_channel = $ssh->_get_open_channel();
403 | if ($request_channel === false) {
404 | return false;
405 | }
406 |
407 | $packet = pack(
408 | 'CNNa*C',
409 | NET_SSH2_MSG_CHANNEL_REQUEST,
410 | $ssh->server_channels[$request_channel],
411 | strlen('auth-agent-req@openssh.com'),
412 | 'auth-agent-req@openssh.com',
413 | 1
414 | );
415 |
416 | $ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_REQUEST;
417 |
418 | if (!$ssh->_send_binary_packet($packet)) {
419 | return false;
420 | }
421 |
422 | $response = $ssh->_get_channel_packet($request_channel);
423 | if ($response === false) {
424 | return false;
425 | }
426 |
427 | $ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_OPEN;
428 | $this->forward_status = SYSTEM_SSH_AGENT_FORWARD_ACTIVE;
429 |
430 | return true;
431 | }
432 |
433 | /**
434 | * On successful channel open
435 | *
436 | * This method is called upon successful channel
437 | * open to give the SSH Agent an opportunity
438 | * to take further action. i.e. request agent forwarding
439 | *
440 | * @param Net_SSH2 $ssh
441 | * @access private
442 | */
443 | function _on_channel_open($ssh)
444 | {
445 | if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_REQUEST) {
446 | $this->_request_forwarding($ssh);
447 | }
448 | }
449 |
450 | /**
451 | * Forward data to SSH Agent and return data reply
452 | *
453 | * @param string $data
454 | * @return data from SSH Agent
455 | * @access private
456 | */
457 | function _forward_data($data)
458 | {
459 | if ($this->expected_bytes > 0) {
460 | $this->socket_buffer.= $data;
461 | $this->expected_bytes -= strlen($data);
462 | } else {
463 | $agent_data_bytes = current(unpack('N', $data));
464 | $current_data_bytes = strlen($data);
465 | $this->socket_buffer = $data;
466 | if ($current_data_bytes != $agent_data_bytes + 4) {
467 | $this->expected_bytes = ($agent_data_bytes + 4) - $current_data_bytes;
468 | return false;
469 | }
470 | }
471 |
472 | if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) {
473 | user_error('Connection closed attempting to forward data to SSH agent');
474 | }
475 |
476 | $this->socket_buffer = '';
477 | $this->expected_bytes = 0;
478 |
479 | $agent_reply_bytes = current(unpack('N', fread($this->fsock, 4)));
480 |
481 | $agent_reply_data = fread($this->fsock, $agent_reply_bytes);
482 | $agent_reply_data = current(unpack('a*', $agent_reply_data));
483 |
484 | return pack('Na*', $agent_reply_bytes, $agent_reply_data);
485 | }
486 | }
487 |
--------------------------------------------------------------------------------
/lib/phpseclib104/System/SSH_Agent.php:
--------------------------------------------------------------------------------
1 |
33 | * @copyright 2014 Jim Wigginton
34 | * @license http://www.opensource.org/licenses/mit-license.html MIT License
35 | * @link http://phpseclib.sourceforge.net
36 | * @internal See http://api.libssh.org/rfc/PROTOCOL.agent
37 | */
38 |
39 | require_once 'SSH/Agent.php';
40 |
--------------------------------------------------------------------------------
/lib/phpseclib104/openssl.cnf:
--------------------------------------------------------------------------------
1 | # minimalist openssl.cnf file for use with phpseclib
2 |
3 | HOME = .
4 | RANDFILE = $ENV::HOME/.rnd
5 |
6 | [ v3_ca ]
7 |
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caffedrine/scaleway-whmcs/c25a730187f9e5bbe90ebcc5c270b05495e72513/logo.png
--------------------------------------------------------------------------------