├── .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.= ''; 529 | } else { 530 | $close = '' . $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 --------------------------------------------------------------------------------