File modules/phpseclib/Crypt/RSA.class.php

Last commit: Sat Oct 31 00:43:29 2020 +0100	Jan Dankert	New: Support for OpenId Connect; Removed: Support for LDAP.
1 <?php 2 3 /** 4 * Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA. 5 * 6 * PHP version 5 7 * 8 * Here's an example of how to encrypt and decrypt text with this library: 9 * <code> 10 * <?php 11 * include 'vendor/autoload.php'; 12 * 13 * $rsa = new \phpseclib\Crypt\RSA(); 14 * extract($rsa->createKey()); 15 * 16 * $plaintext = 'terrafrost'; 17 * 18 * $rsa->loadKey($privatekey); 19 * $ciphertext = $rsa->encrypt($plaintext); 20 * 21 * $rsa->loadKey($publickey); 22 * echo $rsa->decrypt($ciphertext); 23 * ?> 24 * </code> 25 * 26 * Here's an example of how to create signatures and verify signatures with this library: 27 * <code> 28 * <?php 29 * include 'vendor/autoload.php'; 30 * 31 * $rsa = new \phpseclib\Crypt\RSA(); 32 * extract($rsa->createKey()); 33 * 34 * $plaintext = 'terrafrost'; 35 * 36 * $rsa->loadKey($privatekey); 37 * $signature = $rsa->sign($plaintext); 38 * 39 * $rsa->loadKey($publickey); 40 * echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified'; 41 * ?> 42 * </code> 43 * 44 * @category Crypt 45 * @package RSA 46 * @author Jim Wigginton <terrafrost@php.net> 47 * @copyright 2009 Jim Wigginton 48 * @license http://www.opensource.org/licenses/mit-license.html MIT License 49 * @link http://phpseclib.sourceforge.net 50 */ 51 52 namespace phpseclib\Crypt; 53 54 use phpseclib\Math\BigInteger; 55 56 /** 57 * Pure-PHP PKCS#1 compliant implementation of RSA. 58 * 59 * @package RSA 60 * @author Jim Wigginton <terrafrost@php.net> 61 * @access public 62 */ 63 class RSA 64 { 65 /**#@+ 66 * @access public 67 * @see self::encrypt() 68 * @see self::decrypt() 69 */ 70 /** 71 * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding} 72 * (OAEP) for encryption / decryption. 73 * 74 * Uses sha1 by default. 75 * 76 * @see self::setHash() 77 * @see self::setMGFHash() 78 */ 79 const ENCRYPTION_OAEP = 1; 80 /** 81 * Use PKCS#1 padding. 82 * 83 * Although self::ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards 84 * compatibility with protocols (like SSH-1) written before OAEP's introduction. 85 */ 86 const ENCRYPTION_PKCS1 = 2; 87 /** 88 * Do not use any padding 89 * 90 * Although this method is not recommended it can none-the-less sometimes be useful if you're trying to decrypt some legacy 91 * stuff, if you're trying to diagnose why an encrypted message isn't decrypting, etc. 92 */ 93 const ENCRYPTION_NONE = 3; 94 /**#@-*/ 95 96 /**#@+ 97 * @access public 98 * @see self::sign() 99 * @see self::verify() 100 * @see self::setHash() 101 */ 102 /** 103 * Use the Probabilistic Signature Scheme for signing 104 * 105 * Uses sha1 by default. 106 * 107 * @see self::setSaltLength() 108 * @see self::setMGFHash() 109 */ 110 const SIGNATURE_PSS = 1; 111 /** 112 * Use the PKCS#1 scheme by default. 113 * 114 * Although self::SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards 115 * compatibility with protocols (like SSH-2) written before PSS's introduction. 116 */ 117 const SIGNATURE_PKCS1 = 2; 118 /**#@-*/ 119 120 /**#@+ 121 * @access private 122 * @see \phpseclib\Crypt\RSA::createKey() 123 */ 124 /** 125 * ASN1 Integer 126 */ 127 const ASN1_INTEGER = 2; 128 /** 129 * ASN1 Bit String 130 */ 131 const ASN1_BITSTRING = 3; 132 /** 133 * ASN1 Octet String 134 */ 135 const ASN1_OCTETSTRING = 4; 136 /** 137 * ASN1 Object Identifier 138 */ 139 const ASN1_OBJECT = 6; 140 /** 141 * ASN1 Sequence (with the constucted bit set) 142 */ 143 const ASN1_SEQUENCE = 48; 144 /**#@-*/ 145 146 /**#@+ 147 * @access private 148 * @see \phpseclib\Crypt\RSA::__construct() 149 */ 150 /** 151 * To use the pure-PHP implementation 152 */ 153 const MODE_INTERNAL = 1; 154 /** 155 * To use the OpenSSL library 156 * 157 * (if enabled; otherwise, the internal implementation will be used) 158 */ 159 const MODE_OPENSSL = 2; 160 /**#@-*/ 161 162 /**#@+ 163 * @access public 164 * @see \phpseclib\Crypt\RSA::createKey() 165 * @see \phpseclib\Crypt\RSA::setPrivateKeyFormat() 166 */ 167 /** 168 * PKCS#1 formatted private key 169 * 170 * Used by OpenSSH 171 */ 172 const PRIVATE_FORMAT_PKCS1 = 0; 173 /** 174 * PuTTY formatted private key 175 */ 176 const PRIVATE_FORMAT_PUTTY = 1; 177 /** 178 * XML formatted private key 179 */ 180 const PRIVATE_FORMAT_XML = 2; 181 /** 182 * PKCS#8 formatted private key 183 */ 184 const PRIVATE_FORMAT_PKCS8 = 8; 185 /** 186 * OpenSSH formatted private key 187 */ 188 const PRIVATE_FORMAT_OPENSSH = 9; 189 /**#@-*/ 190 191 /**#@+ 192 * @access public 193 * @see \phpseclib\Crypt\RSA::createKey() 194 * @see \phpseclib\Crypt\RSA::setPublicKeyFormat() 195 */ 196 /** 197 * Raw public key 198 * 199 * An array containing two \phpseclib\Math\BigInteger objects. 200 * 201 * The exponent can be indexed with any of the following: 202 * 203 * 0, e, exponent, publicExponent 204 * 205 * The modulus can be indexed with any of the following: 206 * 207 * 1, n, modulo, modulus 208 */ 209 const PUBLIC_FORMAT_RAW = 3; 210 /** 211 * PKCS#1 formatted public key (raw) 212 * 213 * Used by File/X509.php 214 * 215 * Has the following header: 216 * 217 * -----BEGIN RSA PUBLIC KEY----- 218 * 219 * Analogous to ssh-keygen's pem format (as specified by -m) 220 */ 221 const PUBLIC_FORMAT_PKCS1 = 4; 222 const PUBLIC_FORMAT_PKCS1_RAW = 4; 223 /** 224 * XML formatted public key 225 */ 226 const PUBLIC_FORMAT_XML = 5; 227 /** 228 * OpenSSH formatted public key 229 * 230 * Place in $HOME/.ssh/authorized_keys 231 */ 232 const PUBLIC_FORMAT_OPENSSH = 6; 233 /** 234 * PKCS#1 formatted public key (encapsulated) 235 * 236 * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set) 237 * 238 * Has the following header: 239 * 240 * -----BEGIN PUBLIC KEY----- 241 * 242 * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8 243 * is specific to private keys it's basically creating a DER-encoded wrapper 244 * for keys. This just extends that same concept to public keys (much like ssh-keygen) 245 */ 246 const PUBLIC_FORMAT_PKCS8 = 7; 247 /**#@-*/ 248 249 /** 250 * Precomputed Zero 251 * 252 * @var \phpseclib\Math\BigInteger 253 * @access private 254 */ 255 var $zero; 256 257 /** 258 * Precomputed One 259 * 260 * @var \phpseclib\Math\BigInteger 261 * @access private 262 */ 263 var $one; 264 265 /** 266 * Private Key Format 267 * 268 * @var int 269 * @access private 270 */ 271 var $privateKeyFormat = self::PRIVATE_FORMAT_PKCS1; 272 273 /** 274 * Public Key Format 275 * 276 * @var int 277 * @access public 278 */ 279 var $publicKeyFormat = self::PUBLIC_FORMAT_PKCS8; 280 281 /** 282 * Modulus (ie. n) 283 * 284 * @var \phpseclib\Math\BigInteger 285 * @access private 286 */ 287 var $modulus; 288 289 /** 290 * Modulus length 291 * 292 * @var \phpseclib\Math\BigInteger 293 * @access private 294 */ 295 var $k; 296 297 /** 298 * Exponent (ie. e or d) 299 * 300 * @var \phpseclib\Math\BigInteger 301 * @access private 302 */ 303 var $exponent; 304 305 /** 306 * Primes for Chinese Remainder Theorem (ie. p and q) 307 * 308 * @var array 309 * @access private 310 */ 311 var $primes; 312 313 /** 314 * Exponents for Chinese Remainder Theorem (ie. dP and dQ) 315 * 316 * @var array 317 * @access private 318 */ 319 var $exponents; 320 321 /** 322 * Coefficients for Chinese Remainder Theorem (ie. qInv) 323 * 324 * @var array 325 * @access private 326 */ 327 var $coefficients; 328 329 /** 330 * Hash name 331 * 332 * @var string 333 * @access private 334 */ 335 var $hashName; 336 337 /** 338 * Hash function 339 * 340 * @var \phpseclib\Crypt\Hash 341 * @access private 342 */ 343 var $hash; 344 345 /** 346 * Length of hash function output 347 * 348 * @var int 349 * @access private 350 */ 351 var $hLen; 352 353 /** 354 * Length of salt 355 * 356 * @var int 357 * @access private 358 */ 359 var $sLen; 360 361 /** 362 * Hash function for the Mask Generation Function 363 * 364 * @var \phpseclib\Crypt\Hash 365 * @access private 366 */ 367 var $mgfHash; 368 369 /** 370 * Length of MGF hash function output 371 * 372 * @var int 373 * @access private 374 */ 375 var $mgfHLen; 376 377 /** 378 * Encryption mode 379 * 380 * @var int 381 * @access private 382 */ 383 var $encryptionMode = self::ENCRYPTION_OAEP; 384 385 /** 386 * Signature mode 387 * 388 * @var int 389 * @access private 390 */ 391 var $signatureMode = self::SIGNATURE_PSS; 392 393 /** 394 * Public Exponent 395 * 396 * @var mixed 397 * @access private 398 */ 399 var $publicExponent = false; 400 401 /** 402 * Password 403 * 404 * @var string 405 * @access private 406 */ 407 var $password = false; 408 409 /** 410 * Components 411 * 412 * For use with parsing XML formatted keys. PHP's XML Parser functions use utilized - instead of PHP's DOM functions - 413 * because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't. 414 * 415 * @see self::_start_element_handler() 416 * @var array 417 * @access private 418 */ 419 var $components = array(); 420 421 /** 422 * Current String 423 * 424 * For use with parsing XML formatted keys. 425 * 426 * @see self::_character_handler() 427 * @see self::_stop_element_handler() 428 * @var mixed 429 * @access private 430 */ 431 var $current; 432 433 /** 434 * OpenSSL configuration file name. 435 * 436 * Set to null to use system configuration file. 437 * @see self::createKey() 438 * @var mixed 439 * @Access public 440 */ 441 var $configFile; 442 443 /** 444 * Public key comment field. 445 * 446 * @var string 447 * @access private 448 */ 449 var $comment = 'phpseclib-generated-key'; 450 451 /** 452 * The constructor 453 * 454 * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason 455 * \phpseclib\Crypt\RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires 456 * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late. 457 * 458 * @return \phpseclib\Crypt\RSA 459 * @access public 460 */ 461 function __construct() 462 { 463 $this->configFile = dirname(__FILE__) . '/../openssl.cnf'; 464 465 if (!defined('CRYPT_RSA_MODE')) { 466 switch (true) { 467 // Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular, 468 // Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger 469 // can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either. 470 case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'): 471 define('CRYPT_RSA_MODE', self::MODE_INTERNAL); 472 break; 473 case extension_loaded('openssl') && file_exists($this->configFile): 474 // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work 475 $versions = array(); 476 477 // avoid generating errors (even with suppression) when phpinfo() is disabled (common in production systems) 478 if (strpos(ini_get('disable_functions'), 'phpinfo') === false) { 479 ob_start(); 480 @phpinfo(); 481 $content = ob_get_contents(); 482 ob_end_clean(); 483 484 preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches); 485 486 if (!empty($matches[1])) { 487 for ($i = 0; $i < count($matches[1]); $i++) { 488 $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); 489 490 // Remove letter part in OpenSSL version 491 if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) { 492 $versions[$matches[1][$i]] = $fullVersion; 493 } else { 494 $versions[$matches[1][$i]] = $m[0]; 495 } 496 } 497 } 498 } 499 500 // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+ 501 switch (true) { 502 case !isset($versions['Header']): 503 case !isset($versions['Library']): 504 case $versions['Header'] == $versions['Library']: 505 case version_compare($versions['Header'], '1.0.0') >= 0 && version_compare($versions['Library'], '1.0.0') >= 0: 506 define('CRYPT_RSA_MODE', self::MODE_OPENSSL); 507 break; 508 default: 509 define('CRYPT_RSA_MODE', self::MODE_INTERNAL); 510 define('MATH_BIGINTEGER_OPENSSL_DISABLE', true); 511 } 512 break; 513 default: 514 define('CRYPT_RSA_MODE', self::MODE_INTERNAL); 515 } 516 } 517 518 $this->zero = new BigInteger(); 519 $this->one = new BigInteger(1); 520 521 $this->hash = new Hash('sha1'); 522 $this->hLen = $this->hash->getLength(); 523 $this->hashName = 'sha1'; 524 $this->mgfHash = new Hash('sha1'); 525 $this->mgfHLen = $this->mgfHash->getLength(); 526 } 527 528 /** 529 * Create public / private key pair 530 * 531 * Returns an array with the following three elements: 532 * - 'privatekey': The private key. 533 * - 'publickey': The public key. 534 * - 'partialkey': A partially computed key (if the execution time exceeded $timeout). 535 * Will need to be passed back to \phpseclib\Crypt\RSA::createKey() as the third parameter for further processing. 536 * 537 * @access public 538 * @param int $bits 539 * @param int $timeout 540 * @param array $p 541 */ 542 function createKey($bits = 1024, $timeout = false, $partial = array()) 543 { 544 if (!defined('CRYPT_RSA_EXPONENT')) { 545 // http://en.wikipedia.org/wiki/65537_%28number%29 546 define('CRYPT_RSA_EXPONENT', '65537'); 547 } 548 // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller 549 // than 256 bits. as a consequence if the key you're trying to create is 1024 bits and you've set CRYPT_RSA_SMALLEST_PRIME 550 // to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if 551 // CRYPT_RSA_MODE is set to self::MODE_INTERNAL. if CRYPT_RSA_MODE is set to self::MODE_OPENSSL then 552 // CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key 553 // generation when there's a chance neither gmp nor OpenSSL are installed) 554 if (!defined('CRYPT_RSA_SMALLEST_PRIME')) { 555 define('CRYPT_RSA_SMALLEST_PRIME', 4096); 556 } 557 558 // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum 559 if (CRYPT_RSA_MODE == self::MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) { 560 $config = array(); 561 if (isset($this->configFile)) { 562 $config['config'] = $this->configFile; 563 } 564 $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config); 565 openssl_pkey_export($rsa, $privatekey, null, $config); 566 $publickey = openssl_pkey_get_details($rsa); 567 $publickey = $publickey['key']; 568 569 $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, self::PRIVATE_FORMAT_PKCS1))); 570 $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, self::PUBLIC_FORMAT_PKCS1))); 571 572 // clear the buffer of error strings stemming from a minimalistic openssl.cnf 573 while (openssl_error_string() !== false) { 574 } 575 576 return array( 577 'privatekey' => $privatekey, 578 'publickey' => $publickey, 579 'partialkey' => false 580 ); 581 } 582 583 static $e; 584 if (!isset($e)) { 585 $e = new BigInteger(CRYPT_RSA_EXPONENT); 586 } 587 588 extract($this->_generateMinMax($bits)); 589 $absoluteMin = $min; 590 $temp = $bits >> 1; // divide by two to see how many bits P and Q would be 591 if ($temp > CRYPT_RSA_SMALLEST_PRIME) { 592 $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME); 593 $temp = CRYPT_RSA_SMALLEST_PRIME; 594 } else { 595 $num_primes = 2; 596 } 597 extract($this->_generateMinMax($temp + $bits % $temp)); 598 $finalMax = $max; 599 extract($this->_generateMinMax($temp)); 600 601 $generator = new BigInteger(); 602 603 $n = $this->one->copy(); 604 if (!empty($partial)) { 605 extract(unserialize($partial)); 606 } else { 607 $exponents = $coefficients = $primes = array(); 608 $lcm = array( 609 'top' => $this->one->copy(), 610 'bottom' => false 611 ); 612 } 613 614 $start = time(); 615 $i0 = count($primes) + 1; 616 617 do { 618 for ($i = $i0; $i <= $num_primes; $i++) { 619 if ($timeout !== false) { 620 $timeout-= time() - $start; 621 $start = time(); 622 if ($timeout <= 0) { 623 return array( 624 'privatekey' => '', 625 'publickey' => '', 626 'partialkey' => serialize(array( 627 'primes' => $primes, 628 'coefficients' => $coefficients, 629 'lcm' => $lcm, 630 'exponents' => $exponents 631 )) 632 ); 633 } 634 } 635 636 if ($i == $num_primes) { 637 list($min, $temp) = $absoluteMin->divide($n); 638 if (!$temp->equals($this->zero)) { 639 $min = $min->add($this->one); // ie. ceil() 640 } 641 $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout); 642 } else { 643 $primes[$i] = $generator->randomPrime($min, $max, $timeout); 644 } 645 646 if ($primes[$i] === false) { // if we've reached the timeout 647 if (count($primes) > 1) { 648 $partialkey = ''; 649 } else { 650 array_pop($primes); 651 $partialkey = serialize(array( 652 'primes' => $primes, 653 'coefficients' => $coefficients, 654 'lcm' => $lcm, 655 'exponents' => $exponents 656 )); 657 } 658 659 return array( 660 'privatekey' => '', 661 'publickey' => '', 662 'partialkey' => $partialkey 663 ); 664 } 665 666 // the first coefficient is calculated differently from the rest 667 // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1]) 668 if ($i > 2) { 669 $coefficients[$i] = $n->modInverse($primes[$i]); 670 } 671 672 $n = $n->multiply($primes[$i]); 673 674 $temp = $primes[$i]->subtract($this->one); 675 676 // textbook RSA implementations use Euler's totient function instead of the least common multiple. 677 // see http://en.wikipedia.org/wiki/Euler%27s_totient_function 678 $lcm['top'] = $lcm['top']->multiply($temp); 679 $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp); 680 681 $exponents[$i] = $e->modInverse($temp); 682 } 683 684 list($temp) = $lcm['top']->divide($lcm['bottom']); 685 $gcd = $temp->gcd($e); 686 $i0 = 1; 687 } while (!$gcd->equals($this->one)); 688 689 $d = $e->modInverse($temp); 690 691 $coefficients[2] = $primes[2]->modInverse($primes[1]); 692 693 // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>: 694 // RSAPrivateKey ::= SEQUENCE { 695 // version Version, 696 // modulus INTEGER, -- n 697 // publicExponent INTEGER, -- e 698 // privateExponent INTEGER, -- d 699 // prime1 INTEGER, -- p 700 // prime2 INTEGER, -- q 701 // exponent1 INTEGER, -- d mod (p-1) 702 // exponent2 INTEGER, -- d mod (q-1) 703 // coefficient INTEGER, -- (inverse of q) mod p 704 // otherPrimeInfos OtherPrimeInfos OPTIONAL 705 // } 706 707 return array( 708 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients), 709 'publickey' => $this->_convertPublicKey($n, $e), 710 'partialkey' => false 711 ); 712 } 713 714 /** 715 * Convert a private key to the appropriate format. 716 * 717 * @access private 718 * @see self::setPrivateKeyFormat() 719 * @param string $RSAPrivateKey 720 * @return string 721 */ 722 function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients) 723 { 724 $signed = $this->privateKeyFormat != self::PRIVATE_FORMAT_XML; 725 $num_primes = count($primes); 726 $raw = array( 727 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi 728 'modulus' => $n->toBytes($signed), 729 'publicExponent' => $e->toBytes($signed), 730 'privateExponent' => $d->toBytes($signed), 731 'prime1' => $primes[1]->toBytes($signed), 732 'prime2' => $primes[2]->toBytes($signed), 733 'exponent1' => $exponents[1]->toBytes($signed), 734 'exponent2' => $exponents[2]->toBytes($signed), 735 'coefficient' => $coefficients[2]->toBytes($signed) 736 ); 737 738 // if the format in question does not support multi-prime rsa and multi-prime rsa was used, 739 // call _convertPublicKey() instead. 740 switch ($this->privateKeyFormat) { 741 case self::PRIVATE_FORMAT_XML: 742 if ($num_primes != 2) { 743 return false; 744 } 745 return "<RSAKeyValue>\r\n" . 746 ' <Modulus>' . base64_encode($raw['modulus']) . "</Modulus>\r\n" . 747 ' <Exponent>' . base64_encode($raw['publicExponent']) . "</Exponent>\r\n" . 748 ' <P>' . base64_encode($raw['prime1']) . "</P>\r\n" . 749 ' <Q>' . base64_encode($raw['prime2']) . "</Q>\r\n" . 750 ' <DP>' . base64_encode($raw['exponent1']) . "</DP>\r\n" . 751 ' <DQ>' . base64_encode($raw['exponent2']) . "</DQ>\r\n" . 752 ' <InverseQ>' . base64_encode($raw['coefficient']) . "</InverseQ>\r\n" . 753 ' <D>' . base64_encode($raw['privateExponent']) . "</D>\r\n" . 754 '</RSAKeyValue>'; 755 break; 756 case self::PRIVATE_FORMAT_PUTTY: 757 if ($num_primes != 2) { 758 return false; 759 } 760 $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: "; 761 $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none'; 762 $key.= $encryption; 763 $key.= "\r\nComment: " . $this->comment . "\r\n"; 764 $public = pack( 765 'Na*Na*Na*', 766 strlen('ssh-rsa'), 767 'ssh-rsa', 768 strlen($raw['publicExponent']), 769 $raw['publicExponent'], 770 strlen($raw['modulus']), 771 $raw['modulus'] 772 ); 773 $source = pack( 774 'Na*Na*Na*Na*', 775 strlen('ssh-rsa'), 776 'ssh-rsa', 777 strlen($encryption), 778 $encryption, 779 strlen($this->comment), 780 $this->comment, 781 strlen($public), 782 $public 783 ); 784 $public = base64_encode($public); 785 $key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n"; 786 $key.= chunk_split($public, 64); 787 $private = pack( 788 'Na*Na*Na*Na*', 789 strlen($raw['privateExponent']), 790 $raw['privateExponent'], 791 strlen($raw['prime1']), 792 $raw['prime1'], 793 strlen($raw['prime2']), 794 $raw['prime2'], 795 strlen($raw['coefficient']), 796 $raw['coefficient'] 797 ); 798 if (empty($this->password) && !is_string($this->password)) { 799 $source.= pack('Na*', strlen($private), $private); 800 $hashkey = 'putty-private-key-file-mac-key'; 801 } else { 802 $private.= Random::string(16 - (strlen($private) & 15)); 803 $source.= pack('Na*', strlen($private), $private); 804 $sequence = 0; 805 $symkey = ''; 806 while (strlen($symkey) < 32) { 807 $temp = pack('Na*', $sequence++, $this->password); 808 $symkey.= pack('H*', sha1($temp)); 809 } 810 $symkey = substr($symkey, 0, 32); 811 $crypto = new AES(); 812 813 $crypto->setKey($symkey); 814 $crypto->disablePadding(); 815 $private = $crypto->encrypt($private); 816 $hashkey = 'putty-private-key-file-mac-key' . $this->password; 817 } 818 819 $private = base64_encode($private); 820 $key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n"; 821 $key.= chunk_split($private, 64); 822 $hash = new Hash('sha1'); 823 $hash->setKey(pack('H*', sha1($hashkey))); 824 $key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n"; 825 826 return $key; 827 case self::PRIVATE_FORMAT_OPENSSH: 828 if ($num_primes != 2) { 829 return false; 830 } 831 $publicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus']); 832 $privateKey = pack( 833 'Na*Na*Na*Na*Na*Na*Na*', 834 strlen('ssh-rsa'), 835 'ssh-rsa', 836 strlen($raw['modulus']), 837 $raw['modulus'], 838 strlen($raw['publicExponent']), 839 $raw['publicExponent'], 840 strlen($raw['privateExponent']), 841 $raw['privateExponent'], 842 strlen($raw['coefficient']), 843 $raw['coefficient'], 844 strlen($raw['prime1']), 845 $raw['prime1'], 846 strlen($raw['prime2']), 847 $raw['prime2'] 848 ); 849 $checkint = Random::string(4); 850 $paddedKey = pack( 851 'a*Na*', 852 $checkint . $checkint . $privateKey, 853 strlen($this->comment), 854 $this->comment 855 ); 856 $paddingLength = (7 * strlen($paddedKey)) % 8; 857 for ($i = 1; $i <= $paddingLength; $i++) { 858 $paddedKey.= chr($i); 859 } 860 $key = pack( 861 'Na*Na*Na*NNa*Na*', 862 strlen('none'), 863 'none', 864 strlen('none'), 865 'none', 866 0, 867 '', 868 1, 869 strlen($publicKey), 870 $publicKey, 871 strlen($paddedKey), 872 $paddedKey 873 ); 874 $key = "openssh-key-v1\0$key"; 875 876 return "-----BEGIN OPENSSH PRIVATE KEY-----\r\n" . 877 chunk_split(base64_encode($key), 70) . 878 "-----END OPENSSH PRIVATE KEY-----"; 879 default: // eg. self::PRIVATE_FORMAT_PKCS1 880 $components = array(); 881 foreach ($raw as $name => $value) { 882 $components[$name] = pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value); 883 } 884 885 $RSAPrivateKey = implode('', $components); 886 887 if ($num_primes > 2) { 888 $OtherPrimeInfos = ''; 889 for ($i = 3; $i <= $num_primes; $i++) { 890 // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo 891 // 892 // OtherPrimeInfo ::= SEQUENCE { 893 // prime INTEGER, -- ri 894 // exponent INTEGER, -- di 895 // coefficient INTEGER -- ti 896 // } 897 $OtherPrimeInfo = pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true)); 898 $OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true)); 899 $OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true)); 900 $OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo); 901 } 902 $RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos); 903 } 904 905 $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); 906 907 if ($this->privateKeyFormat == self::PRIVATE_FORMAT_PKCS8) { 908 $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA 909 $RSAPrivateKey = pack( 910 'Ca*a*Ca*a*', 911 self::ASN1_INTEGER, 912 "\01\00", 913 $rsaOID, 914 4, 915 $this->_encodeLength(strlen($RSAPrivateKey)), 916 $RSAPrivateKey 917 ); 918 $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); 919 if (!empty($this->password) || is_string($this->password)) { 920 $salt = Random::string(8); 921 $iterationCount = 2048; 922 923 $crypto = new DES(); 924 $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount); 925 $RSAPrivateKey = $crypto->encrypt($RSAPrivateKey); 926 927 $parameters = pack( 928 'Ca*a*Ca*N', 929 self::ASN1_OCTETSTRING, 930 $this->_encodeLength(strlen($salt)), 931 $salt, 932 self::ASN1_INTEGER, 933 $this->_encodeLength(4), 934 $iterationCount 935 ); 936 $pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03"; 937 938 $encryptionAlgorithm = pack( 939 'Ca*a*Ca*a*', 940 self::ASN1_OBJECT, 941 $this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)), 942 $pbeWithMD5AndDES_CBC, 943 self::ASN1_SEQUENCE, 944 $this->_encodeLength(strlen($parameters)), 945 $parameters 946 ); 947 948 $RSAPrivateKey = pack( 949 'Ca*a*Ca*a*', 950 self::ASN1_SEQUENCE, 951 $this->_encodeLength(strlen($encryptionAlgorithm)), 952 $encryptionAlgorithm, 953 self::ASN1_OCTETSTRING, 954 $this->_encodeLength(strlen($RSAPrivateKey)), 955 $RSAPrivateKey 956 ); 957 958 $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); 959 960 $RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" . 961 chunk_split(base64_encode($RSAPrivateKey), 64) . 962 '-----END ENCRYPTED PRIVATE KEY-----'; 963 } else { 964 $RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" . 965 chunk_split(base64_encode($RSAPrivateKey), 64) . 966 '-----END PRIVATE KEY-----'; 967 } 968 return $RSAPrivateKey; 969 } 970 971 if (!empty($this->password) || is_string($this->password)) { 972 $iv = Random::string(8); 973 $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key 974 $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8); 975 $des = new TripleDES(); 976 $des->setKey($symkey); 977 $des->setIV($iv); 978 $iv = strtoupper(bin2hex($iv)); 979 $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" . 980 "Proc-Type: 4,ENCRYPTED\r\n" . 981 "DEK-Info: DES-EDE3-CBC,$iv\r\n" . 982 "\r\n" . 983 chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) . 984 '-----END RSA PRIVATE KEY-----'; 985 } else { 986 $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" . 987 chunk_split(base64_encode($RSAPrivateKey), 64) . 988 '-----END RSA PRIVATE KEY-----'; 989 } 990 991 return $RSAPrivateKey; 992 } 993 } 994 995 /** 996 * Convert a public key to the appropriate format 997 * 998 * @access private 999 * @see self::setPublicKeyFormat() 1000 * @param string $RSAPrivateKey 1001 * @return string 1002 */ 1003 function _convertPublicKey($n, $e) 1004 { 1005 $signed = $this->publicKeyFormat != self::PUBLIC_FORMAT_XML; 1006 1007 $modulus = $n->toBytes($signed); 1008 $publicExponent = $e->toBytes($signed); 1009 1010 switch ($this->publicKeyFormat) { 1011 case self::PUBLIC_FORMAT_RAW: 1012 return array('e' => $e->copy(), 'n' => $n->copy()); 1013 case self::PUBLIC_FORMAT_XML: 1014 return "<RSAKeyValue>\r\n" . 1015 ' <Modulus>' . base64_encode($modulus) . "</Modulus>\r\n" . 1016 ' <Exponent>' . base64_encode($publicExponent) . "</Exponent>\r\n" . 1017 '</RSAKeyValue>'; 1018 break; 1019 case self::PUBLIC_FORMAT_OPENSSH: 1020 // from <http://tools.ietf.org/html/rfc4253#page-15>: 1021 // string "ssh-rsa" 1022 // mpint e 1023 // mpint n 1024 $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus); 1025 $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $this->comment; 1026 1027 return $RSAPublicKey; 1028 default: // eg. self::PUBLIC_FORMAT_PKCS1_RAW or self::PUBLIC_FORMAT_PKCS1 1029 // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>: 1030 // RSAPublicKey ::= SEQUENCE { 1031 // modulus INTEGER, -- n 1032 // publicExponent INTEGER -- e 1033 // } 1034 $components = array( 1035 'modulus' => pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus), 1036 'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent) 1037 ); 1038 1039 $RSAPublicKey = pack( 1040 'Ca*a*a*', 1041 self::ASN1_SEQUENCE, 1042 $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])), 1043 $components['modulus'], 1044 $components['publicExponent'] 1045 ); 1046 1047 if ($this->publicKeyFormat == self::PUBLIC_FORMAT_PKCS1_RAW) { 1048 $RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" . 1049 chunk_split(base64_encode($RSAPublicKey), 64) . 1050 '-----END RSA PUBLIC KEY-----'; 1051 } else { 1052 // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption. 1053 $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA 1054 $RSAPublicKey = chr(0) . $RSAPublicKey; 1055 $RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey; 1056 1057 $RSAPublicKey = pack( 1058 'Ca*a*', 1059 self::ASN1_SEQUENCE, 1060 $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)), 1061 $rsaOID . $RSAPublicKey 1062 ); 1063 1064 $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . 1065 chunk_split(base64_encode($RSAPublicKey), 64) . 1066 '-----END PUBLIC KEY-----'; 1067 } 1068 1069 return $RSAPublicKey; 1070 } 1071 } 1072 1073 /** 1074 * Break a public or private key down into its constituant components 1075 * 1076 * @access private 1077 * @see self::_convertPublicKey() 1078 * @see self::_convertPrivateKey() 1079 * @param string|array $key 1080 * @param int $type 1081 * @return array|bool 1082 */ 1083 function _parseKey($key, $type) 1084 { 1085 if ($type != self::PUBLIC_FORMAT_RAW && !is_string($key)) { 1086 return false; 1087 } 1088 1089 switch ($type) { 1090 case self::PUBLIC_FORMAT_RAW: 1091 if (!is_array($key)) { 1092 return false; 1093 } 1094 $components = array(); 1095 switch (true) { 1096 case isset($key['e']): 1097 $components['publicExponent'] = $key['e']->copy(); 1098 break; 1099 case isset($key['exponent']): 1100 $components['publicExponent'] = $key['exponent']->copy(); 1101 break; 1102 case isset($key['publicExponent']): 1103 $components['publicExponent'] = $key['publicExponent']->copy(); 1104 break; 1105 case isset($key[0]): 1106 $components['publicExponent'] = $key[0]->copy(); 1107 } 1108 switch (true) { 1109 case isset($key['n']): 1110 $components['modulus'] = $key['n']->copy(); 1111 break; 1112 case isset($key['modulo']): 1113 $components['modulus'] = $key['modulo']->copy(); 1114 break; 1115 case isset($key['modulus']): 1116 $components['modulus'] = $key['modulus']->copy(); 1117 break; 1118 case isset($key[1]): 1119 $components['modulus'] = $key[1]->copy(); 1120 } 1121 return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false; 1122 case self::PRIVATE_FORMAT_PKCS1: 1123 case self::PRIVATE_FORMAT_PKCS8: 1124 case self::PUBLIC_FORMAT_PKCS1: 1125 /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is 1126 "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to 1127 protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding 1128 two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here: 1129 1130 http://tools.ietf.org/html/rfc1421#section-4.6.1.1 1131 http://tools.ietf.org/html/rfc1421#section-4.6.1.3 1132 1133 DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell. 1134 DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation 1135 function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's 1136 own implementation. ie. the implementation *is* the standard and any bugs that may exist in that 1137 implementation are part of the standard, as well. 1138 1139 * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */ 1140 if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) { 1141 $iv = pack('H*', trim($matches[2])); 1142 $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key 1143 $symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8))); 1144 // remove the Proc-Type / DEK-Info sections as they're no longer needed 1145 $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key); 1146 $ciphertext = $this->_extractBER($key); 1147 if ($ciphertext === false) { 1148 $ciphertext = $key; 1149 } 1150 switch ($matches[1]) { 1151 case 'AES-256-CBC': 1152 $crypto = new AES(); 1153 break; 1154 case 'AES-128-CBC': 1155 $symkey = substr($symkey, 0, 16); 1156 $crypto = new AES(); 1157 break; 1158 case 'DES-EDE3-CFB': 1159 $crypto = new TripleDES(Base::MODE_CFB); 1160 break; 1161 case 'DES-EDE3-CBC': 1162 $symkey = substr($symkey, 0, 24); 1163 $crypto = new TripleDES(); 1164 break; 1165 case 'DES-CBC': 1166 $crypto = new DES(); 1167 break; 1168 default: 1169 return false; 1170 } 1171 $crypto->setKey($symkey); 1172 $crypto->setIV($iv); 1173 $decoded = $crypto->decrypt($ciphertext); 1174 } else { 1175 $decoded = $this->_extractBER($key); 1176 } 1177 1178 if ($decoded !== false) { 1179 $key = $decoded; 1180 } 1181 1182 $components = array(); 1183 1184 if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) { 1185 return false; 1186 } 1187 if ($this->_decodeLength($key) != strlen($key)) { 1188 return false; 1189 } 1190 1191 $tag = ord($this->_string_shift($key)); 1192 /* intended for keys for which OpenSSL's asn1parse returns the following: 1193 1194 0:d=0 hl=4 l= 631 cons: SEQUENCE 1195 4:d=1 hl=2 l= 1 prim: INTEGER :00 1196 7:d=1 hl=2 l= 13 cons: SEQUENCE 1197 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 1198 20:d=2 hl=2 l= 0 prim: NULL 1199 22:d=1 hl=4 l= 609 prim: OCTET STRING 1200 1201 ie. PKCS8 keys*/ 1202 1203 if ($tag == self::ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") { 1204 $this->_string_shift($key, 3); 1205 $tag = self::ASN1_SEQUENCE; 1206 } 1207 1208 if ($tag == self::ASN1_SEQUENCE) { 1209 $temp = $this->_string_shift($key, $this->_decodeLength($key)); 1210 if (ord($this->_string_shift($temp)) != self::ASN1_OBJECT) { 1211 return false; 1212 } 1213 $length = $this->_decodeLength($temp); 1214 switch ($this->_string_shift($temp, $length)) { 1215 case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption 1216 break; 1217 case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC 1218 /* 1219 PBEParameter ::= SEQUENCE { 1220 salt OCTET STRING (SIZE(8)), 1221 iterationCount INTEGER } 1222 */ 1223 if (ord($this->_string_shift($temp)) != self::ASN1_SEQUENCE) { 1224 return false; 1225 } 1226 if ($this->_decodeLength($temp) != strlen($temp)) { 1227 return false; 1228 } 1229 $this->_string_shift($temp); // assume it's an octet string 1230 $salt = $this->_string_shift($temp, $this->_decodeLength($temp)); 1231 if (ord($this->_string_shift($temp)) != self::ASN1_INTEGER) { 1232 return false; 1233 } 1234 $this->_decodeLength($temp); 1235 list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT)); 1236 $this->_string_shift($key); // assume it's an octet string 1237 $length = $this->_decodeLength($key); 1238 if (strlen($key) != $length) { 1239 return false; 1240 } 1241 1242 $crypto = new DES(); 1243 $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount); 1244 $key = $crypto->decrypt($key); 1245 if ($key === false) { 1246 return false; 1247 } 1248 return $this->_parseKey($key, self::PRIVATE_FORMAT_PKCS1); 1249 default: 1250 return false; 1251 } 1252 /* intended for keys for which OpenSSL's asn1parse returns the following: 1253 1254 0:d=0 hl=4 l= 290 cons: SEQUENCE 1255 4:d=1 hl=2 l= 13 cons: SEQUENCE 1256 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 1257 17:d=2 hl=2 l= 0 prim: NULL 1258 19:d=1 hl=4 l= 271 prim: BIT STRING */ 1259 $tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag 1260 $this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length 1261 // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of 1262 // unused bits in the final subsequent octet. The number shall be in the range zero to seven." 1263 // -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2) 1264 if ($tag == self::ASN1_BITSTRING) { 1265 $this->_string_shift($key); 1266 } 1267 if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) { 1268 return false; 1269 } 1270 if ($this->_decodeLength($key) != strlen($key)) { 1271 return false; 1272 } 1273 $tag = ord($this->_string_shift($key)); 1274 } 1275 if ($tag != self::ASN1_INTEGER) { 1276 return false; 1277 } 1278 1279 $length = $this->_decodeLength($key); 1280 $temp = $this->_string_shift($key, $length); 1281 if (strlen($temp) != 1 || ord($temp) > 2) { 1282 $components['modulus'] = new BigInteger($temp, 256); 1283 $this->_string_shift($key); // skip over self::ASN1_INTEGER 1284 $length = $this->_decodeLength($key); 1285 $components[$type == self::PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new BigInteger($this->_string_shift($key, $length), 256); 1286 1287 return $components; 1288 } 1289 if (ord($this->_string_shift($key)) != self::ASN1_INTEGER) { 1290 return false; 1291 } 1292 $length = $this->_decodeLength($key); 1293 $components['modulus'] = new BigInteger($this->_string_shift($key, $length), 256); 1294 $this->_string_shift($key); 1295 $length = $this->_decodeLength($key); 1296 $components['publicExponent'] = new BigInteger($this->_string_shift($key, $length), 256); 1297 $this->_string_shift($key); 1298 $length = $this->_decodeLength($key); 1299 $components['privateExponent'] = new BigInteger($this->_string_shift($key, $length), 256); 1300 $this->_string_shift($key); 1301 $length = $this->_decodeLength($key); 1302 $components['primes'] = array(1 => new BigInteger($this->_string_shift($key, $length), 256)); 1303 $this->_string_shift($key); 1304 $length = $this->_decodeLength($key); 1305 $components['primes'][] = new BigInteger($this->_string_shift($key, $length), 256); 1306 $this->_string_shift($key); 1307 $length = $this->_decodeLength($key); 1308 $components['exponents'] = array(1 => new BigInteger($this->_string_shift($key, $length), 256)); 1309 $this->_string_shift($key); 1310 $length = $this->_decodeLength($key); 1311 $components['exponents'][] = new BigInteger($this->_string_shift($key, $length), 256); 1312 $this->_string_shift($key); 1313 $length = $this->_decodeLength($key); 1314 $components['coefficients'] = array(2 => new BigInteger($this->_string_shift($key, $length), 256)); 1315 1316 if (!empty($key)) { 1317 if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) { 1318 return false; 1319 } 1320 $this->_decodeLength($key); 1321 while (!empty($key)) { 1322 if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) { 1323 return false; 1324 } 1325 $this->_decodeLength($key); 1326 $key = substr($key, 1); 1327 $length = $this->_decodeLength($key); 1328 $components['primes'][] = new BigInteger($this->_string_shift($key, $length), 256); 1329 $this->_string_shift($key); 1330 $length = $this->_decodeLength($key); 1331 $components['exponents'][] = new BigInteger($this->_string_shift($key, $length), 256); 1332 $this->_string_shift($key); 1333 $length = $this->_decodeLength($key); 1334 $components['coefficients'][] = new BigInteger($this->_string_shift($key, $length), 256); 1335 } 1336 } 1337 1338 return $components; 1339 case self::PUBLIC_FORMAT_OPENSSH: 1340 $parts = explode(' ', $key, 3); 1341 1342 $key = isset($parts[1]) ? base64_decode($parts[1]) : false; 1343 if ($key === false) { 1344 return false; 1345 } 1346 1347 $comment = isset($parts[2]) ? $parts[2] : false; 1348 1349 $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa"; 1350 1351 if (strlen($key) <= 4) { 1352 return false; 1353 } 1354 extract(unpack('Nlength', $this->_string_shift($key, 4))); 1355 $publicExponent = new BigInteger($this->_string_shift($key, $length), -256); 1356 if (strlen($key) <= 4) { 1357 return false; 1358 } 1359 extract(unpack('Nlength', $this->_string_shift($key, 4))); 1360 $modulus = new BigInteger($this->_string_shift($key, $length), -256); 1361 1362 if ($cleanup && strlen($key)) { 1363 if (strlen($key) <= 4) { 1364 return false; 1365 } 1366 extract(unpack('Nlength', $this->_string_shift($key, 4))); 1367 $realModulus = new BigInteger($this->_string_shift($key, $length), -256); 1368 return strlen($key) ? false : array( 1369 'modulus' => $realModulus, 1370 'publicExponent' => $modulus, 1371 'comment' => $comment 1372 ); 1373 } else { 1374 return strlen($key) ? false : array( 1375 'modulus' => $modulus, 1376 'publicExponent' => $publicExponent, 1377 'comment' => $comment 1378 ); 1379 } 1380 // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue 1381 // http://en.wikipedia.org/wiki/XML_Signature 1382 case self::PRIVATE_FORMAT_XML: 1383 case self::PUBLIC_FORMAT_XML: 1384 $this->components = array(); 1385 1386 $xml = xml_parser_create('UTF-8'); 1387 xml_set_object($xml, $this); 1388 xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler'); 1389 xml_set_character_data_handler($xml, '_data_handler'); 1390 // add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added 1391 if (!xml_parse($xml, '<xml>' . $key . '</xml>')) { 1392 xml_parser_free($xml); 1393 unset($xml); 1394 return false; 1395 } 1396 1397 xml_parser_free($xml); 1398 unset($xml); 1399 1400 return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false; 1401 // from PuTTY's SSHPUBK.C 1402 case self::PRIVATE_FORMAT_PUTTY: 1403 $components = array(); 1404 $key = preg_split('#\r\n|\r|\n#', $key); 1405 $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0])); 1406 if ($type != 'ssh-rsa') { 1407 return false; 1408 } 1409 $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1])); 1410 $comment = trim(preg_replace('#Comment: (.+)#', '$1', $key[2])); 1411 1412 $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3])); 1413 $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength)))); 1414 $public = substr($public, 11); 1415 extract(unpack('Nlength', $this->_string_shift($public, 4))); 1416 $components['publicExponent'] = new BigInteger($this->_string_shift($public, $length), -256); 1417 extract(unpack('Nlength', $this->_string_shift($public, 4))); 1418 $components['modulus'] = new BigInteger($this->_string_shift($public, $length), -256); 1419 1420 $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4])); 1421 $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength)))); 1422 1423 switch ($encryption) { 1424 case 'aes256-cbc': 1425 $symkey = ''; 1426 $sequence = 0; 1427 while (strlen($symkey) < 32) { 1428 $temp = pack('Na*', $sequence++, $this->password); 1429 $symkey.= pack('H*', sha1($temp)); 1430 } 1431 $symkey = substr($symkey, 0, 32); 1432 $crypto = new AES(); 1433 } 1434 1435 if ($encryption != 'none') { 1436 $crypto->setKey($symkey); 1437 $crypto->disablePadding(); 1438 $private = $crypto->decrypt($private); 1439 if ($private === false) { 1440 return false; 1441 } 1442 } 1443 1444 extract(unpack('Nlength', $this->_string_shift($private, 4))); 1445 if (strlen($private) < $length) { 1446 return false; 1447 } 1448 $components['privateExponent'] = new BigInteger($this->_string_shift($private, $length), -256); 1449 extract(unpack('Nlength', $this->_string_shift($private, 4))); 1450 if (strlen($private) < $length) { 1451 return false; 1452 } 1453 $components['primes'] = array(1 => new BigInteger($this->_string_shift($private, $length), -256)); 1454 extract(unpack('Nlength', $this->_string_shift($private, 4))); 1455 if (strlen($private) < $length) { 1456 return false; 1457 } 1458 $components['primes'][] = new BigInteger($this->_string_shift($private, $length), -256); 1459 1460 $temp = $components['primes'][1]->subtract($this->one); 1461 $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp)); 1462 $temp = $components['primes'][2]->subtract($this->one); 1463 $components['exponents'][] = $components['publicExponent']->modInverse($temp); 1464 1465 extract(unpack('Nlength', $this->_string_shift($private, 4))); 1466 if (strlen($private) < $length) { 1467 return false; 1468 } 1469 $components['coefficients'] = array(2 => new BigInteger($this->_string_shift($private, $length), -256)); 1470 1471 return $components; 1472 case self::PRIVATE_FORMAT_OPENSSH: 1473 $components = array(); 1474 $decoded = $this->_extractBER($key); 1475 $magic = $this->_string_shift($decoded, 15); 1476 if ($magic !== "openssh-key-v1\0") { 1477 return false; 1478 } 1479 $options = $this->_string_shift($decoded, 24); 1480 // \0\0\0\4none = ciphername 1481 // \0\0\0\4none = kdfname 1482 // \0\0\0\0 = kdfoptions 1483 // \0\0\0\1 = numkeys 1484 if ($options != "\0\0\0\4none\0\0\0\4none\0\0\0\0\0\0\0\1") { 1485 return false; 1486 } 1487 extract(unpack('Nlength', $this->_string_shift($decoded, 4))); 1488 if (strlen($decoded) < $length) { 1489 return false; 1490 } 1491 $publicKey = $this->_string_shift($decoded, $length); 1492 extract(unpack('Nlength', $this->_string_shift($decoded, 4))); 1493 if (strlen($decoded) < $length) { 1494 return false; 1495 } 1496 $paddedKey = $this->_string_shift($decoded, $length); 1497 1498 if ($this->_string_shift($publicKey, 11) !== "\0\0\0\7ssh-rsa") { 1499 return false; 1500 } 1501 1502 $checkint1 = $this->_string_shift($paddedKey, 4); 1503 $checkint2 = $this->_string_shift($paddedKey, 4); 1504 if (strlen($checkint1) != 4 || $checkint1 !== $checkint2) { 1505 return false; 1506 } 1507 1508 if ($this->_string_shift($paddedKey, 11) !== "\0\0\0\7ssh-rsa") { 1509 return false; 1510 } 1511 1512 $values = array( 1513 &$components['modulus'], 1514 &$components['publicExponent'], 1515 &$components['privateExponent'], 1516 &$components['coefficients'][2], 1517 &$components['primes'][1], 1518 &$components['primes'][2] 1519 ); 1520 1521 foreach ($values as &$value) { 1522 extract(unpack('Nlength', $this->_string_shift($paddedKey, 4))); 1523 if (strlen($paddedKey) < $length) { 1524 return false; 1525 } 1526 $value = new BigInteger($this->_string_shift($paddedKey, $length), -256); 1527 } 1528 1529 extract(unpack('Nlength', $this->_string_shift($paddedKey, 4))); 1530 if (strlen($paddedKey) < $length) { 1531 return false; 1532 } 1533 $components['comment'] = $this->_string_shift($decoded, $length); 1534 1535 $temp = $components['primes'][1]->subtract($this->one); 1536 $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp)); 1537 $temp = $components['primes'][2]->subtract($this->one); 1538 $components['exponents'][] = $components['publicExponent']->modInverse($temp); 1539 1540 return $components; 1541 } 1542 1543 return false; 1544 } 1545 1546 /** 1547 * Returns the key size 1548 * 1549 * More specifically, this returns the size of the modulo in bits. 1550 * 1551 * @access public 1552 * @return int 1553 */ 1554 function getSize() 1555 { 1556 return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits()); 1557 } 1558 1559 /** 1560 * Start Element Handler 1561 * 1562 * Called by xml_set_element_handler() 1563 * 1564 * @access private 1565 * @param resource $parser 1566 * @param string $name 1567 * @param array $attribs 1568 */ 1569 function _start_element_handler($parser, $name, $attribs) 1570 { 1571 //$name = strtoupper($name); 1572 switch ($name) { 1573 case 'MODULUS': 1574 $this->current = &$this->components['modulus']; 1575 break; 1576 case 'EXPONENT': 1577 $this->current = &$this->components['publicExponent']; 1578 break; 1579 case 'P': 1580 $this->current = &$this->components['primes'][1]; 1581 break; 1582 case 'Q': 1583 $this->current = &$this->components['primes'][2]; 1584 break; 1585 case 'DP': 1586 $this->current = &$this->components['exponents'][1]; 1587 break; 1588 case 'DQ': 1589 $this->current = &$this->components['exponents'][2]; 1590 break; 1591 case 'INVERSEQ': 1592 $this->current = &$this->components['coefficients'][2]; 1593 break; 1594 case 'D': 1595 $this->current = &$this->components['privateExponent']; 1596 } 1597 $this->current = ''; 1598 } 1599 1600 /** 1601 * Stop Element Handler 1602 * 1603 * Called by xml_set_element_handler() 1604 * 1605 * @access private 1606 * @param resource $parser 1607 * @param string $name 1608 */ 1609 function _stop_element_handler($parser, $name) 1610 { 1611 if (isset($this->current)) { 1612 $this->current = new BigInteger(base64_decode($this->current), 256); 1613 unset($this->current); 1614 } 1615 } 1616 1617 /** 1618 * Data Handler 1619 * 1620 * Called by xml_set_character_data_handler() 1621 * 1622 * @access private 1623 * @param resource $parser 1624 * @param string $data 1625 */ 1626 function _data_handler($parser, $data) 1627 { 1628 if (!isset($this->current) || is_object($this->current)) { 1629 return; 1630 } 1631 $this->current.= trim($data); 1632 } 1633 1634 /** 1635 * Loads a public or private key 1636 * 1637 * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed) 1638 * 1639 * @access public 1640 * @param string|RSA|array $key 1641 * @param bool|int $type optional 1642 * @return bool 1643 */ 1644 function loadKey($key, $type = false) 1645 { 1646 if ($key instanceof RSA) { 1647 $this->privateKeyFormat = $key->privateKeyFormat; 1648 $this->publicKeyFormat = $key->publicKeyFormat; 1649 $this->k = $key->k; 1650 $this->hLen = $key->hLen; 1651 $this->sLen = $key->sLen; 1652 $this->mgfHLen = $key->mgfHLen; 1653 $this->encryptionMode = $key->encryptionMode; 1654 $this->signatureMode = $key->signatureMode; 1655 $this->password = $key->password; 1656 $this->configFile = $key->configFile; 1657 $this->comment = $key->comment; 1658 1659 if (is_object($key->hash)) { 1660 $this->hash = new Hash($key->hash->getHash()); 1661 } 1662 if (is_object($key->mgfHash)) { 1663 $this->mgfHash = new Hash($key->mgfHash->getHash()); 1664 } 1665 1666 if (is_object($key->modulus)) { 1667 $this->modulus = $key->modulus->copy(); 1668 } 1669 if (is_object($key->exponent)) { 1670 $this->exponent = $key->exponent->copy(); 1671 } 1672 if (is_object($key->publicExponent)) { 1673 $this->publicExponent = $key->publicExponent->copy(); 1674 } 1675 1676 $this->primes = array(); 1677 $this->exponents = array(); 1678 $this->coefficients = array(); 1679 1680 foreach ($this->primes as $prime) { 1681 $this->primes[] = $prime->copy(); 1682 } 1683 foreach ($this->exponents as $exponent) { 1684 $this->exponents[] = $exponent->copy(); 1685 } 1686 foreach ($this->coefficients as $coefficient) { 1687 $this->coefficients[] = $coefficient->copy(); 1688 } 1689 1690 return true; 1691 } 1692 1693 if ($type === false) { 1694 $types = array( 1695 self::PUBLIC_FORMAT_RAW, 1696 self::PRIVATE_FORMAT_PKCS1, 1697 self::PRIVATE_FORMAT_XML, 1698 self::PRIVATE_FORMAT_PUTTY, 1699 self::PUBLIC_FORMAT_OPENSSH, 1700 self::PRIVATE_FORMAT_OPENSSH 1701 ); 1702 foreach ($types as $type) { 1703 $components = $this->_parseKey($key, $type); 1704 if ($components !== false) { 1705 break; 1706 } 1707 } 1708 } else { 1709 $components = $this->_parseKey($key, $type); 1710 } 1711 1712 if ($components === false) { 1713 $this->comment = null; 1714 $this->modulus = null; 1715 $this->k = null; 1716 $this->exponent = null; 1717 $this->primes = null; 1718 $this->exponents = null; 1719 $this->coefficients = null; 1720 $this->publicExponent = null; 1721 1722 return false; 1723 } 1724 1725 if (isset($components['comment']) && $components['comment'] !== false) { 1726 $this->comment = $components['comment']; 1727 } 1728 $this->modulus = $components['modulus']; 1729 $this->k = strlen($this->modulus->toBytes()); 1730 $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent']; 1731 if (isset($components['primes'])) { 1732 $this->primes = $components['primes']; 1733 $this->exponents = $components['exponents']; 1734 $this->coefficients = $components['coefficients']; 1735 $this->publicExponent = $components['publicExponent']; 1736 } else { 1737 $this->primes = array(); 1738 $this->exponents = array(); 1739 $this->coefficients = array(); 1740 $this->publicExponent = false; 1741 } 1742 1743 switch ($type) { 1744 case self::PUBLIC_FORMAT_OPENSSH: 1745 case self::PUBLIC_FORMAT_RAW: 1746 $this->setPublicKey(); 1747 break; 1748 case self::PRIVATE_FORMAT_PKCS1: 1749 switch (true) { 1750 case strpos($key, '-BEGIN PUBLIC KEY-') !== false: 1751 case strpos($key, '-BEGIN RSA PUBLIC KEY-') !== false: 1752 $this->setPublicKey(); 1753 } 1754 } 1755 1756 return true; 1757 } 1758 1759 /** 1760 * Sets the password 1761 * 1762 * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false. 1763 * Or rather, pass in $password such that empty($password) && !is_string($password) is true. 1764 * 1765 * @see self::createKey() 1766 * @see self::loadKey() 1767 * @access public 1768 * @param string $password 1769 */ 1770 function setPassword($password = false) 1771 { 1772 $this->password = $password; 1773 } 1774 1775 /** 1776 * Defines the public key 1777 * 1778 * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when 1779 * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a 1780 * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys 1781 * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public 1782 * exponent this won't work unless you manually add the public exponent. phpseclib tries to guess if the key being used 1783 * is the public key but in the event that it guesses incorrectly you might still want to explicitly set the key as being 1784 * public. 1785 * 1786 * Do note that when a new key is loaded the index will be cleared. 1787 * 1788 * Returns true on success, false on failure 1789 * 1790 * @see self::getPublicKey() 1791 * @access public 1792 * @param string $key optional 1793 * @param int $type optional 1794 * @return bool 1795 */ 1796 function setPublicKey($key = false, $type = false) 1797 { 1798 // if a public key has already been loaded return false 1799 if (!empty($this->publicExponent)) { 1800 return false; 1801 } 1802 1803 if ($key === false && !empty($this->modulus)) { 1804 $this->publicExponent = $this->exponent; 1805 return true; 1806 } 1807 1808 if ($type === false) { 1809 $types = array( 1810 self::PUBLIC_FORMAT_RAW, 1811 self::PUBLIC_FORMAT_PKCS1, 1812 self::PUBLIC_FORMAT_XML, 1813 self::PUBLIC_FORMAT_OPENSSH 1814 ); 1815 foreach ($types as $type) { 1816 $components = $this->_parseKey($key, $type); 1817 if ($components !== false) { 1818 break; 1819 } 1820 } 1821 } else { 1822 $components = $this->_parseKey($key, $type); 1823 } 1824 1825 if ($components === false) { 1826 return false; 1827 } 1828 1829 if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) { 1830 $this->modulus = $components['modulus']; 1831 $this->exponent = $this->publicExponent = $components['publicExponent']; 1832 return true; 1833 } 1834 1835 $this->publicExponent = $components['publicExponent']; 1836 1837 return true; 1838 } 1839 1840 /** 1841 * Defines the private key 1842 * 1843 * If phpseclib guessed a private key was a public key and loaded it as such it might be desirable to force 1844 * phpseclib to treat the key as a private key. This function will do that. 1845 * 1846 * Do note that when a new key is loaded the index will be cleared. 1847 * 1848 * Returns true on success, false on failure 1849 * 1850 * @see self::getPublicKey() 1851 * @access public 1852 * @param string $key optional 1853 * @param int $type optional 1854 * @return bool 1855 */ 1856 function setPrivateKey($key = false, $type = false) 1857 { 1858 if ($key === false && !empty($this->publicExponent)) { 1859 $this->publicExponent = false; 1860 return true; 1861 } 1862 1863 $rsa = new RSA(); 1864 if (!$rsa->loadKey($key, $type)) { 1865 return false; 1866 } 1867 $rsa->publicExponent = false; 1868 1869 // don't overwrite the old key if the new key is invalid 1870 $this->loadKey($rsa); 1871 return true; 1872 } 1873 1874 /** 1875 * Returns the public key 1876 * 1877 * The public key is only returned under two circumstances - if the private key had the public key embedded within it 1878 * or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this 1879 * function won't return it since this library, for the most part, doesn't distinguish between public and private keys. 1880 * 1881 * @see self::getPublicKey() 1882 * @access public 1883 * @param string $key 1884 * @param int $type optional 1885 */ 1886 function getPublicKey($type = self::PUBLIC_FORMAT_PKCS8) 1887 { 1888 if (empty($this->modulus) || empty($this->publicExponent)) { 1889 return false; 1890 } 1891 1892 $oldFormat = $this->publicKeyFormat; 1893 $this->publicKeyFormat = $type; 1894 $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent); 1895 $this->publicKeyFormat = $oldFormat; 1896 return $temp; 1897 } 1898 1899 /** 1900 * Returns the public key's fingerprint 1901 * 1902 * The public key's fingerprint is returned, which is equivalent to running `ssh-keygen -lf rsa.pub`. If there is 1903 * no public key currently loaded, false is returned. 1904 * Example output (md5): "c1:b1:30:29:d7:b8:de:6c:97:77:10:d7:46:41:63:87" (as specified by RFC 4716) 1905 * 1906 * @access public 1907 * @param string $algorithm The hashing algorithm to be used. Valid options are 'md5' and 'sha256'. False is returned 1908 * for invalid values. 1909 * @return mixed 1910 */ 1911 function getPublicKeyFingerprint($algorithm = 'md5') 1912 { 1913 if (empty($this->modulus) || empty($this->publicExponent)) { 1914 return false; 1915 } 1916 1917 $modulus = $this->modulus->toBytes(true); 1918 $publicExponent = $this->publicExponent->toBytes(true); 1919 1920 $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus); 1921 1922 switch ($algorithm) { 1923 case 'sha256': 1924 $hash = new Hash('sha256'); 1925 $base = base64_encode($hash->hash($RSAPublicKey)); 1926 return substr($base, 0, strlen($base) - 1); 1927 case 'md5': 1928 return substr(chunk_split(md5($RSAPublicKey), 2, ':'), 0, -1); 1929 default: 1930 return false; 1931 } 1932 } 1933 1934 /** 1935 * Returns the private key 1936 * 1937 * The private key is only returned if the currently loaded key contains the constituent prime numbers. 1938 * 1939 * @see self::getPublicKey() 1940 * @access public 1941 * @param string $key 1942 * @param int $type optional 1943 * @return mixed 1944 */ 1945 function getPrivateKey($type = self::PUBLIC_FORMAT_PKCS1) 1946 { 1947 if (empty($this->primes)) { 1948 return false; 1949 } 1950 1951 $oldFormat = $this->privateKeyFormat; 1952 $this->privateKeyFormat = $type; 1953 $temp = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients); 1954 $this->privateKeyFormat = $oldFormat; 1955 return $temp; 1956 } 1957 1958 /** 1959 * Returns a minimalistic private key 1960 * 1961 * Returns the private key without the prime number constituants. Structurally identical to a public key that 1962 * hasn't been set as the public key 1963 * 1964 * @see self::getPrivateKey() 1965 * @access private 1966 * @param string $key 1967 * @param int $type optional 1968 */ 1969 function _getPrivatePublicKey($mode = self::PUBLIC_FORMAT_PKCS8) 1970 { 1971 if (empty($this->modulus) || empty($this->exponent)) { 1972 return false; 1973 } 1974 1975 $oldFormat = $this->publicKeyFormat; 1976 $this->publicKeyFormat = $mode; 1977 $temp = $this->_convertPublicKey($this->modulus, $this->exponent); 1978 $this->publicKeyFormat = $oldFormat; 1979 return $temp; 1980 } 1981 1982 /** 1983 * __toString() magic method 1984 * 1985 * @access public 1986 * @return string 1987 */ 1988 function __toString() 1989 { 1990 $key = $this->getPrivateKey($this->privateKeyFormat); 1991 if ($key !== false) { 1992 return $key; 1993 } 1994 $key = $this->_getPrivatePublicKey($this->publicKeyFormat); 1995 return $key !== false ? $key : ''; 1996 } 1997 1998 /** 1999 * __clone() magic method 2000 * 2001 * @access public 2002 * @return Crypt_RSA 2003 */ 2004 function __clone() 2005 { 2006 $key = new RSA(); 2007 $key->loadKey($this); 2008 return $key; 2009 } 2010 2011 /** 2012 * Generates the smallest and largest numbers requiring $bits bits 2013 * 2014 * @access private 2015 * @param int $bits 2016 * @return array 2017 */ 2018 function _generateMinMax($bits) 2019 { 2020 $bytes = $bits >> 3; 2021 $min = str_repeat(chr(0), $bytes); 2022 $max = str_repeat(chr(0xFF), $bytes); 2023 $msb = $bits & 7; 2024 if ($msb) { 2025 $min = chr(1 << ($msb - 1)) . $min; 2026 $max = chr((1 << $msb) - 1) . $max; 2027 } else { 2028 $min[0] = chr(0x80); 2029 } 2030 2031 return array( 2032 'min' => new BigInteger($min, 256), 2033 'max' => new BigInteger($max, 256) 2034 ); 2035 } 2036 2037 /** 2038 * DER-decode the length 2039 * 2040 * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See 2041 * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information. 2042 * 2043 * @access private 2044 * @param string $string 2045 * @return int 2046 */ 2047 function _decodeLength(&$string) 2048 { 2049 $length = ord($this->_string_shift($string)); 2050 if ($length & 0x80) { // definite length, long form 2051 $length&= 0x7F; 2052 $temp = $this->_string_shift($string, $length); 2053 list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)); 2054 } 2055 return $length; 2056 } 2057 2058 /** 2059 * DER-encode the length 2060 * 2061 * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See 2062 * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information. 2063 * 2064 * @access private 2065 * @param int $length 2066 * @return string 2067 */ 2068 function _encodeLength($length) 2069 { 2070 if ($length <= 0x7F) { 2071 return chr($length); 2072 } 2073 2074 $temp = ltrim(pack('N', $length), chr(0)); 2075 return pack('Ca*', 0x80 | strlen($temp), $temp); 2076 } 2077 2078 /** 2079 * String Shift 2080 * 2081 * Inspired by array_shift 2082 * 2083 * @param string $string 2084 * @param int $index 2085 * @return string 2086 * @access private 2087 */ 2088 function _string_shift(&$string, $index = 1) 2089 { 2090 $substr = substr($string, 0, $index); 2091 $string = substr($string, $index); 2092 return $substr; 2093 } 2094 2095 /** 2096 * Determines the private key format 2097 * 2098 * @see self::createKey() 2099 * @access public 2100 * @param int $format 2101 */ 2102 function setPrivateKeyFormat($format) 2103 { 2104 $this->privateKeyFormat = $format; 2105 } 2106 2107 /** 2108 * Determines the public key format 2109 * 2110 * @see self::createKey() 2111 * @access public 2112 * @param int $format 2113 */ 2114 function setPublicKeyFormat($format) 2115 { 2116 $this->publicKeyFormat = $format; 2117 } 2118 2119 /** 2120 * Determines which hashing function should be used 2121 * 2122 * Used with signature production / verification and (if the encryption mode is self::ENCRYPTION_OAEP) encryption and 2123 * decryption. If $hash isn't supported, sha1 is used. 2124 * 2125 * @access public 2126 * @param string $hash 2127 */ 2128 function setHash($hash) 2129 { 2130 // \phpseclib\Crypt\Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example. 2131 switch ($hash) { 2132 case 'md2': 2133 case 'md5': 2134 case 'sha1': 2135 case 'sha256': 2136 case 'sha384': 2137 case 'sha512': 2138 $this->hash = new Hash($hash); 2139 $this->hashName = $hash; 2140 break; 2141 default: 2142 $this->hash = new Hash('sha1'); 2143 $this->hashName = 'sha1'; 2144 } 2145 $this->hLen = $this->hash->getLength(); 2146 } 2147 2148 /** 2149 * Determines which hashing function should be used for the mask generation function 2150 * 2151 * The mask generation function is used by self::ENCRYPTION_OAEP and self::SIGNATURE_PSS and although it's 2152 * best if Hash and MGFHash are set to the same thing this is not a requirement. 2153 * 2154 * @access public 2155 * @param string $hash 2156 */ 2157 function setMGFHash($hash) 2158 { 2159 // \phpseclib\Crypt\Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example. 2160 switch ($hash) { 2161 case 'md2': 2162 case 'md5': 2163 case 'sha1': 2164 case 'sha256': 2165 case 'sha384': 2166 case 'sha512': 2167 $this->mgfHash = new Hash($hash); 2168 break; 2169 default: 2170 $this->mgfHash = new Hash('sha1'); 2171 } 2172 $this->mgfHLen = $this->mgfHash->getLength(); 2173 } 2174 2175 /** 2176 * Determines the salt length 2177 * 2178 * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}: 2179 * 2180 * Typical salt lengths in octets are hLen (the length of the output 2181 * of the hash function Hash) and 0. 2182 * 2183 * @access public 2184 * @param int $format 2185 */ 2186 function setSaltLength($sLen) 2187 { 2188 $this->sLen = $sLen; 2189 } 2190 2191 /** 2192 * Integer-to-Octet-String primitive 2193 * 2194 * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}. 2195 * 2196 * @access private 2197 * @param \phpseclib\Math\BigInteger $x 2198 * @param int $xLen 2199 * @return string 2200 */ 2201 function _i2osp($x, $xLen) 2202 { 2203 $x = $x->toBytes(); 2204 if (strlen($x) > $xLen) { 2205 user_error('Integer too large'); 2206 return false; 2207 } 2208 return str_pad($x, $xLen, chr(0), STR_PAD_LEFT); 2209 } 2210 2211 /** 2212 * Octet-String-to-Integer primitive 2213 * 2214 * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}. 2215 * 2216 * @access private 2217 * @param string $x 2218 * @return \phpseclib\Math\BigInteger 2219 */ 2220 function _os2ip($x) 2221 { 2222 return new BigInteger($x, 256); 2223 } 2224 2225 /** 2226 * Exponentiate with or without Chinese Remainder Theorem 2227 * 2228 * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}. 2229 * 2230 * @access private 2231 * @param \phpseclib\Math\BigInteger $x 2232 * @return \phpseclib\Math\BigInteger 2233 */ 2234 function _exponentiate($x) 2235 { 2236 switch (true) { 2237 case empty($this->primes): 2238 case $this->primes[1]->equals($this->zero): 2239 case empty($this->coefficients): 2240 case $this->coefficients[2]->equals($this->zero): 2241 case empty($this->exponents): 2242 case $this->exponents[1]->equals($this->zero): 2243 return $x->modPow($this->exponent, $this->modulus); 2244 } 2245 2246 $num_primes = count($this->primes); 2247 2248 if (defined('CRYPT_RSA_DISABLE_BLINDING')) { 2249 $m_i = array( 2250 1 => $x->modPow($this->exponents[1], $this->primes[1]), 2251 2 => $x->modPow($this->exponents[2], $this->primes[2]) 2252 ); 2253 $h = $m_i[1]->subtract($m_i[2]); 2254 $h = $h->multiply($this->coefficients[2]); 2255 list(, $h) = $h->divide($this->primes[1]); 2256 $m = $m_i[2]->add($h->multiply($this->primes[2])); 2257 2258 $r = $this->primes[1]; 2259 for ($i = 3; $i <= $num_primes; $i++) { 2260 $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]); 2261 2262 $r = $r->multiply($this->primes[$i - 1]); 2263 2264 $h = $m_i->subtract($m); 2265 $h = $h->multiply($this->coefficients[$i]); 2266 list(, $h) = $h->divide($this->primes[$i]); 2267 2268 $m = $m->add($r->multiply($h)); 2269 } 2270 } else { 2271 $smallest = $this->primes[1]; 2272 for ($i = 2; $i <= $num_primes; $i++) { 2273 if ($smallest->compare($this->primes[$i]) > 0) { 2274 $smallest = $this->primes[$i]; 2275 } 2276 } 2277 2278 $one = new BigInteger(1); 2279 2280 $r = $one->random($one, $smallest->subtract($one)); 2281 2282 $m_i = array( 2283 1 => $this->_blind($x, $r, 1), 2284 2 => $this->_blind($x, $r, 2) 2285 ); 2286 $h = $m_i[1]->subtract($m_i[2]); 2287 $h = $h->multiply($this->coefficients[2]); 2288 list(, $h) = $h->divide($this->primes[1]); 2289 $m = $m_i[2]->add($h->multiply($this->primes[2])); 2290 2291 $r = $this->primes[1]; 2292 for ($i = 3; $i <= $num_primes; $i++) { 2293 $m_i = $this->_blind($x, $r, $i); 2294 2295 $r = $r->multiply($this->primes[$i - 1]); 2296 2297 $h = $m_i->subtract($m); 2298 $h = $h->multiply($this->coefficients[$i]); 2299 list(, $h) = $h->divide($this->primes[$i]); 2300 2301 $m = $m->add($r->multiply($h)); 2302 } 2303 } 2304 2305 return $m; 2306 } 2307 2308 /** 2309 * Performs RSA Blinding 2310 * 2311 * Protects against timing attacks by employing RSA Blinding. 2312 * Returns $x->modPow($this->exponents[$i], $this->primes[$i]) 2313 * 2314 * @access private 2315 * @param \phpseclib\Math\BigInteger $x 2316 * @param \phpseclib\Math\BigInteger $r 2317 * @param int $i 2318 * @return \phpseclib\Math\BigInteger 2319 */ 2320 function _blind($x, $r, $i) 2321 { 2322 $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i])); 2323 $x = $x->modPow($this->exponents[$i], $this->primes[$i]); 2324 2325 $r = $r->modInverse($this->primes[$i]); 2326 $x = $x->multiply($r); 2327 list(, $x) = $x->divide($this->primes[$i]); 2328 2329 return $x; 2330 } 2331 2332 /** 2333 * Performs blinded RSA equality testing 2334 * 2335 * Protects against a particular type of timing attack described. 2336 * 2337 * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)} 2338 * 2339 * Thanks for the heads up singpolyma! 2340 * 2341 * @access private 2342 * @param string $x 2343 * @param string $y 2344 * @return bool 2345 */ 2346 function _equals($x, $y) 2347 { 2348 if (function_exists('hash_equals')) { 2349 return hash_equals($x, $y); 2350 } 2351 2352 if (strlen($x) != strlen($y)) { 2353 return false; 2354 } 2355 2356 $result = "\0"; 2357 $x^= $y; 2358 for ($i = 0; $i < strlen($x); $i++) { 2359 $result|= $x[$i]; 2360 } 2361 2362 return $result === "\0"; 2363 } 2364 2365 /** 2366 * RSAEP 2367 * 2368 * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}. 2369 * 2370 * @access private 2371 * @param \phpseclib\Math\BigInteger $m 2372 * @return \phpseclib\Math\BigInteger 2373 */ 2374 function _rsaep($m) 2375 { 2376 if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) { 2377 user_error('Message representative out of range'); 2378 return false; 2379 } 2380 return $this->_exponentiate($m); 2381 } 2382 2383 /** 2384 * RSADP 2385 * 2386 * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}. 2387 * 2388 * @access private 2389 * @param \phpseclib\Math\BigInteger $c 2390 * @return \phpseclib\Math\BigInteger 2391 */ 2392 function _rsadp($c) 2393 { 2394 if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) { 2395 user_error('Ciphertext representative out of range'); 2396 return false; 2397 } 2398 return $this->_exponentiate($c); 2399 } 2400 2401 /** 2402 * RSASP1 2403 * 2404 * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}. 2405 * 2406 * @access private 2407 * @param \phpseclib\Math\BigInteger $m 2408 * @return \phpseclib\Math\BigInteger 2409 */ 2410 function _rsasp1($m) 2411 { 2412 if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) { 2413 user_error('Message representative out of range'); 2414 return false; 2415 } 2416 return $this->_exponentiate($m); 2417 } 2418 2419 /** 2420 * RSAVP1 2421 * 2422 * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}. 2423 * 2424 * @access private 2425 * @param \phpseclib\Math\BigInteger $s 2426 * @return \phpseclib\Math\BigInteger 2427 */ 2428 function _rsavp1($s) 2429 { 2430 if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) { 2431 user_error('Signature representative out of range'); 2432 return false; 2433 } 2434 return $this->_exponentiate($s); 2435 } 2436 2437 /** 2438 * MGF1 2439 * 2440 * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}. 2441 * 2442 * @access private 2443 * @param string $mgfSeed 2444 * @param int $mgfLen 2445 * @return string 2446 */ 2447 function _mgf1($mgfSeed, $maskLen) 2448 { 2449 // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output. 2450 2451 $t = ''; 2452 $count = ceil($maskLen / $this->mgfHLen); 2453 for ($i = 0; $i < $count; $i++) { 2454 $c = pack('N', $i); 2455 $t.= $this->mgfHash->hash($mgfSeed . $c); 2456 } 2457 2458 return substr($t, 0, $maskLen); 2459 } 2460 2461 /** 2462 * RSAES-OAEP-ENCRYPT 2463 * 2464 * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and 2465 * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}. 2466 * 2467 * @access private 2468 * @param string $m 2469 * @param string $l 2470 * @return string 2471 */ 2472 function _rsaes_oaep_encrypt($m, $l = '') 2473 { 2474 $mLen = strlen($m); 2475 2476 // Length checking 2477 2478 // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error 2479 // be output. 2480 2481 if ($mLen > $this->k - 2 * $this->hLen - 2) { 2482 user_error('Message too long'); 2483 return false; 2484 } 2485 2486 // EME-OAEP encoding 2487 2488 $lHash = $this->hash->hash($l); 2489 $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2); 2490 $db = $lHash . $ps . chr(1) . $m; 2491 $seed = Random::string($this->hLen); 2492 $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1); 2493 $maskedDB = $db ^ $dbMask; 2494 $seedMask = $this->_mgf1($maskedDB, $this->hLen); 2495 $maskedSeed = $seed ^ $seedMask; 2496 $em = chr(0) . $maskedSeed . $maskedDB; 2497 2498 // RSA encryption 2499 2500 $m = $this->_os2ip($em); 2501 $c = $this->_rsaep($m); 2502 $c = $this->_i2osp($c, $this->k); 2503 2504 // Output the ciphertext C 2505 2506 return $c; 2507 } 2508 2509 /** 2510 * RSAES-OAEP-DECRYPT 2511 * 2512 * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error 2513 * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2: 2514 * 2515 * Note. Care must be taken to ensure that an opponent cannot 2516 * distinguish the different error conditions in Step 3.g, whether by 2517 * error message or timing, or, more generally, learn partial 2518 * information about the encoded message EM. Otherwise an opponent may 2519 * be able to obtain useful information about the decryption of the 2520 * ciphertext C, leading to a chosen-ciphertext attack such as the one 2521 * observed by Manger [36]. 2522 * 2523 * As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}: 2524 * 2525 * Both the encryption and the decryption operations of RSAES-OAEP take 2526 * the value of a label L as input. In this version of PKCS #1, L is 2527 * the empty string; other uses of the label are outside the scope of 2528 * this document. 2529 * 2530 * @access private 2531 * @param string $c 2532 * @param string $l 2533 * @return string 2534 */ 2535 function _rsaes_oaep_decrypt($c, $l = '') 2536 { 2537 // Length checking 2538 2539 // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error 2540 // be output. 2541 2542 if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) { 2543 user_error('Decryption error'); 2544 return false; 2545 } 2546 2547 // RSA decryption 2548 2549 $c = $this->_os2ip($c); 2550 $m = $this->_rsadp($c); 2551 if ($m === false) { 2552 user_error('Decryption error'); 2553 return false; 2554 } 2555 $em = $this->_i2osp($m, $this->k); 2556 2557 // EME-OAEP decoding 2558 2559 $lHash = $this->hash->hash($l); 2560 $y = ord($em[0]); 2561 $maskedSeed = substr($em, 1, $this->hLen); 2562 $maskedDB = substr($em, $this->hLen + 1); 2563 $seedMask = $this->_mgf1($maskedDB, $this->hLen); 2564 $seed = $maskedSeed ^ $seedMask; 2565 $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1); 2566 $db = $maskedDB ^ $dbMask; 2567 $lHash2 = substr($db, 0, $this->hLen); 2568 $m = substr($db, $this->hLen); 2569 $hashesMatch = $this->_equals($lHash, $lHash2); 2570 $leadingZeros = 1; 2571 $patternMatch = 0; 2572 $offset = 0; 2573 for ($i = 0; $i < strlen($m); $i++) { 2574 $patternMatch|= $leadingZeros & ($m[$i] === "\1"); 2575 $leadingZeros&= $m[$i] === "\0"; 2576 $offset+= $patternMatch ? 0 : 1; 2577 } 2578 2579 // we do & instead of && to avoid https://en.wikipedia.org/wiki/Short-circuit_evaluation 2580 // to protect against timing attacks 2581 if (!$hashesMatch & !$patternMatch) { 2582 user_error('Decryption error'); 2583 return false; 2584 } 2585 2586 // Output the message M 2587 2588 return substr($m, $offset + 1); 2589 } 2590 2591 /** 2592 * Raw Encryption / Decryption 2593 * 2594 * Doesn't use padding and is not recommended. 2595 * 2596 * @access private 2597 * @param string $m 2598 * @return string 2599 */ 2600 function _raw_encrypt($m) 2601 { 2602 $temp = $this->_os2ip($m); 2603 $temp = $this->_rsaep($temp); 2604 return $this->_i2osp($temp, $this->k); 2605 } 2606 2607 /** 2608 * RSAES-PKCS1-V1_5-ENCRYPT 2609 * 2610 * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}. 2611 * 2612 * @access private 2613 * @param string $m 2614 * @return string 2615 */ 2616 function _rsaes_pkcs1_v1_5_encrypt($m) 2617 { 2618 $mLen = strlen($m); 2619 2620 // Length checking 2621 2622 if ($mLen > $this->k - 11) { 2623 user_error('Message too long'); 2624 return false; 2625 } 2626 2627 // EME-PKCS1-v1_5 encoding 2628 2629 $psLen = $this->k - $mLen - 3; 2630 $ps = ''; 2631 while (strlen($ps) != $psLen) { 2632 $temp = Random::string($psLen - strlen($ps)); 2633 $temp = str_replace("\x00", '', $temp); 2634 $ps.= $temp; 2635 } 2636 $type = 2; 2637 // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done 2638 if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) { 2639 $type = 1; 2640 // "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF" 2641 $ps = str_repeat("\xFF", $psLen); 2642 } 2643 $em = chr(0) . chr($type) . $ps . chr(0) . $m; 2644 2645 // RSA encryption 2646 $m = $this->_os2ip($em); 2647 $c = $this->_rsaep($m); 2648 $c = $this->_i2osp($c, $this->k); 2649 2650 // Output the ciphertext C 2651 2652 return $c; 2653 } 2654 2655 /** 2656 * RSAES-PKCS1-V1_5-DECRYPT 2657 * 2658 * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}. 2659 * 2660 * For compatibility purposes, this function departs slightly from the description given in RFC3447. 2661 * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the 2662 * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the 2663 * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed 2664 * to be 2 regardless of which key is used. For compatibility purposes, we'll just check to make sure the 2665 * second byte is 2 or less. If it is, we'll accept the decrypted string as valid. 2666 * 2667 * As a consequence of this, a private key encrypted ciphertext produced with \phpseclib\Crypt\RSA may not decrypt 2668 * with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but 2669 * not private key encrypted ciphertext's. 2670 * 2671 * @access private 2672 * @param string $c 2673 * @return string 2674 */ 2675 function _rsaes_pkcs1_v1_5_decrypt($c) 2676 { 2677 // Length checking 2678 2679 if (strlen($c) != $this->k) { // or if k < 11 2680 user_error('Decryption error'); 2681 return false; 2682 } 2683 2684 // RSA decryption 2685 2686 $c = $this->_os2ip($c); 2687 $m = $this->_rsadp($c); 2688 2689 if ($m === false) { 2690 user_error('Decryption error'); 2691 return false; 2692 } 2693 $em = $this->_i2osp($m, $this->k); 2694 2695 // EME-PKCS1-v1_5 decoding 2696 2697 if (ord($em[0]) != 0 || ord($em[1]) > 2) { 2698 user_error('Decryption error'); 2699 return false; 2700 } 2701 2702 $ps = substr($em, 2, strpos($em, chr(0), 2) - 2); 2703 $m = substr($em, strlen($ps) + 3); 2704 2705 if (strlen($ps) < 8) { 2706 user_error('Decryption error'); 2707 return false; 2708 } 2709 2710 // Output M 2711 2712 return $m; 2713 } 2714 2715 /** 2716 * EMSA-PSS-ENCODE 2717 * 2718 * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}. 2719 * 2720 * @access private 2721 * @param string $m 2722 * @param int $emBits 2723 */ 2724 function _emsa_pss_encode($m, $emBits) 2725 { 2726 // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error 2727 // be output. 2728 2729 $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8) 2730 $sLen = $this->sLen !== null ? $this->sLen : $this->hLen; 2731 2732 $mHash = $this->hash->hash($m); 2733 if ($emLen < $this->hLen + $sLen + 2) { 2734 user_error('Encoding error'); 2735 return false; 2736 } 2737 2738 $salt = Random::string($sLen); 2739 $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; 2740 $h = $this->hash->hash($m2); 2741 $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2); 2742 $db = $ps . chr(1) . $salt; 2743 $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1); 2744 $maskedDB = $db ^ $dbMask; 2745 $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0]; 2746 $em = $maskedDB . $h . chr(0xBC); 2747 2748 return $em; 2749 } 2750 2751 /** 2752 * EMSA-PSS-VERIFY 2753 * 2754 * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}. 2755 * 2756 * @access private 2757 * @param string $m 2758 * @param string $em 2759 * @param int $emBits 2760 * @return string 2761 */ 2762 function _emsa_pss_verify($m, $em, $emBits) 2763 { 2764 // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error 2765 // be output. 2766 2767 $emLen = ($emBits + 7) >> 3; // ie. ceil($emBits / 8); 2768 $sLen = $this->sLen !== null ? $this->sLen : $this->hLen; 2769 2770 $mHash = $this->hash->hash($m); 2771 if ($emLen < $this->hLen + $sLen + 2) { 2772 return false; 2773 } 2774 2775 if ($em[strlen($em) - 1] != chr(0xBC)) { 2776 return false; 2777 } 2778 2779 $maskedDB = substr($em, 0, -$this->hLen - 1); 2780 $h = substr($em, -$this->hLen - 1, $this->hLen); 2781 $temp = chr(0xFF << ($emBits & 7)); 2782 if ((~$maskedDB[0] & $temp) != $temp) { 2783 return false; 2784 } 2785 $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1); 2786 $db = $maskedDB ^ $dbMask; 2787 $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0]; 2788 $temp = $emLen - $this->hLen - $sLen - 2; 2789 if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) { 2790 return false; 2791 } 2792 $salt = substr($db, $temp + 1); // should be $sLen long 2793 $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; 2794 $h2 = $this->hash->hash($m2); 2795 return $this->_equals($h, $h2); 2796 } 2797 2798 /** 2799 * RSASSA-PSS-SIGN 2800 * 2801 * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}. 2802 * 2803 * @access private 2804 * @param string $m 2805 * @return string 2806 */ 2807 function _rsassa_pss_sign($m) 2808 { 2809 // EMSA-PSS encoding 2810 2811 $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1); 2812 2813 // RSA signature 2814 2815 $m = $this->_os2ip($em); 2816 $s = $this->_rsasp1($m); 2817 $s = $this->_i2osp($s, $this->k); 2818 2819 // Output the signature S 2820 2821 return $s; 2822 } 2823 2824 /** 2825 * RSASSA-PSS-VERIFY 2826 * 2827 * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}. 2828 * 2829 * @access private 2830 * @param string $m 2831 * @param string $s 2832 * @return string 2833 */ 2834 function _rsassa_pss_verify($m, $s) 2835 { 2836 // Length checking 2837 2838 if (strlen($s) != $this->k) { 2839 user_error('Invalid signature'); 2840 return false; 2841 } 2842 2843 // RSA verification 2844 2845 $modBits = strlen($this->modulus->toBits()); 2846 2847 $s2 = $this->_os2ip($s); 2848 $m2 = $this->_rsavp1($s2); 2849 if ($m2 === false) { 2850 user_error('Invalid signature'); 2851 return false; 2852 } 2853 $em = $this->_i2osp($m2, $this->k); 2854 if ($em === false) { 2855 user_error('Invalid signature'); 2856 return false; 2857 } 2858 2859 // EMSA-PSS verification 2860 2861 return $this->_emsa_pss_verify($m, $em, $modBits - 1); 2862 } 2863 2864 /** 2865 * EMSA-PKCS1-V1_5-ENCODE 2866 * 2867 * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}. 2868 * 2869 * @access private 2870 * @param string $m 2871 * @param int $emLen 2872 * @return string 2873 */ 2874 function _emsa_pkcs1_v1_5_encode($m, $emLen) 2875 { 2876 $h = $this->hash->hash($m); 2877 if ($h === false) { 2878 return false; 2879 } 2880 2881 // see http://tools.ietf.org/html/rfc3447#page-43 2882 switch ($this->hashName) { 2883 case 'md2': 2884 $t = pack('H*', '3020300c06082a864886f70d020205000410'); 2885 break; 2886 case 'md5': 2887 $t = pack('H*', '3020300c06082a864886f70d020505000410'); 2888 break; 2889 case 'sha1': 2890 $t = pack('H*', '3021300906052b0e03021a05000414'); 2891 break; 2892 case 'sha256': 2893 $t = pack('H*', '3031300d060960864801650304020105000420'); 2894 break; 2895 case 'sha384': 2896 $t = pack('H*', '3041300d060960864801650304020205000430'); 2897 break; 2898 case 'sha512': 2899 $t = pack('H*', '3051300d060960864801650304020305000440'); 2900 } 2901 $t.= $h; 2902 $tLen = strlen($t); 2903 2904 if ($emLen < $tLen + 11) { 2905 user_error('Intended encoded message length too short'); 2906 return false; 2907 } 2908 2909 $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3); 2910 2911 $em = "\0\1$ps\0$t"; 2912 2913 return $em; 2914 } 2915 2916 /** 2917 * RSASSA-PKCS1-V1_5-SIGN 2918 * 2919 * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}. 2920 * 2921 * @access private 2922 * @param string $m 2923 * @return string 2924 */ 2925 function _rsassa_pkcs1_v1_5_sign($m) 2926 { 2927 // EMSA-PKCS1-v1_5 encoding 2928 2929 $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); 2930 if ($em === false) { 2931 user_error('RSA modulus too short'); 2932 return false; 2933 } 2934 2935 // RSA signature 2936 2937 $m = $this->_os2ip($em); 2938 $s = $this->_rsasp1($m); 2939 $s = $this->_i2osp($s, $this->k); 2940 2941 // Output the signature S 2942 2943 return $s; 2944 } 2945 2946 /** 2947 * RSASSA-PKCS1-V1_5-VERIFY 2948 * 2949 * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}. 2950 * 2951 * @access private 2952 * @param string $m 2953 * @return string 2954 */ 2955 function _rsassa_pkcs1_v1_5_verify($m, $s) 2956 { 2957 // Length checking 2958 2959 if (strlen($s) != $this->k) { 2960 user_error('Invalid signature'); 2961 return false; 2962 } 2963 2964 // RSA verification 2965 2966 $s = $this->_os2ip($s); 2967 $m2 = $this->_rsavp1($s); 2968 if ($m2 === false) { 2969 user_error('Invalid signature'); 2970 return false; 2971 } 2972 $em = $this->_i2osp($m2, $this->k); 2973 if ($em === false) { 2974 user_error('Invalid signature'); 2975 return false; 2976 } 2977 2978 // EMSA-PKCS1-v1_5 encoding 2979 2980 $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); 2981 if ($em2 === false) { 2982 user_error('RSA modulus too short'); 2983 return false; 2984 } 2985 2986 // Compare 2987 return $this->_equals($em, $em2); 2988 } 2989 2990 /** 2991 * Set Encryption Mode 2992 * 2993 * Valid values include self::ENCRYPTION_OAEP and self::ENCRYPTION_PKCS1. 2994 * 2995 * @access public 2996 * @param int $mode 2997 */ 2998 function setEncryptionMode($mode) 2999 { 3000 $this->encryptionMode = $mode; 3001 } 3002 3003 /** 3004 * Set Signature Mode 3005 * 3006 * Valid values include self::SIGNATURE_PSS and self::SIGNATURE_PKCS1 3007 * 3008 * @access public 3009 * @param int $mode 3010 */ 3011 function setSignatureMode($mode) 3012 { 3013 $this->signatureMode = $mode; 3014 } 3015 3016 /** 3017 * Set public key comment. 3018 * 3019 * @access public 3020 * @param string $comment 3021 */ 3022 function setComment($comment) 3023 { 3024 $this->comment = $comment; 3025 } 3026 3027 /** 3028 * Get public key comment. 3029 * 3030 * @access public 3031 * @return string 3032 */ 3033 function getComment() 3034 { 3035 return $this->comment; 3036 } 3037 3038 /** 3039 * Encryption 3040 * 3041 * Both self::ENCRYPTION_OAEP and self::ENCRYPTION_PKCS1 both place limits on how long $plaintext can be. 3042 * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will 3043 * be concatenated together. 3044 * 3045 * @see self::decrypt() 3046 * @access public 3047 * @param string $plaintext 3048 * @return string 3049 */ 3050 function encrypt($plaintext) 3051 { 3052 switch ($this->encryptionMode) { 3053 case self::ENCRYPTION_NONE: 3054 $plaintext = str_split($plaintext, $this->k); 3055 $ciphertext = ''; 3056 foreach ($plaintext as $m) { 3057 $ciphertext.= $this->_raw_encrypt($m); 3058 } 3059 return $ciphertext; 3060 case self::ENCRYPTION_PKCS1: 3061 $length = $this->k - 11; 3062 if ($length <= 0) { 3063 return false; 3064 } 3065 3066 $plaintext = str_split($plaintext, $length); 3067 $ciphertext = ''; 3068 foreach ($plaintext as $m) { 3069 $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m); 3070 } 3071 return $ciphertext; 3072 //case self::ENCRYPTION_OAEP: 3073 default: 3074 $length = $this->k - 2 * $this->hLen - 2; 3075 if ($length <= 0) { 3076 return false; 3077 } 3078 3079 $plaintext = str_split($plaintext, $length); 3080 $ciphertext = ''; 3081 foreach ($plaintext as $m) { 3082 $ciphertext.= $this->_rsaes_oaep_encrypt($m); 3083 } 3084 return $ciphertext; 3085 } 3086 } 3087 3088 /** 3089 * Decryption 3090 * 3091 * @see self::encrypt() 3092 * @access public 3093 * @param string $plaintext 3094 * @return string 3095 */ 3096 function decrypt($ciphertext) 3097 { 3098 if ($this->k <= 0) { 3099 return false; 3100 } 3101 3102 $ciphertext = str_split($ciphertext, $this->k); 3103 $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT); 3104 3105 $plaintext = ''; 3106 3107 switch ($this->encryptionMode) { 3108 case self::ENCRYPTION_NONE: 3109 $decrypt = '_raw_encrypt'; 3110 break; 3111 case self::ENCRYPTION_PKCS1: 3112 $decrypt = '_rsaes_pkcs1_v1_5_decrypt'; 3113 break; 3114 //case self::ENCRYPTION_OAEP: 3115 default: 3116 $decrypt = '_rsaes_oaep_decrypt'; 3117 } 3118 3119 foreach ($ciphertext as $c) { 3120 $temp = $this->$decrypt($c); 3121 if ($temp === false) { 3122 return false; 3123 } 3124 $plaintext.= $temp; 3125 } 3126 3127 return $plaintext; 3128 } 3129 3130 /** 3131 * Create a signature 3132 * 3133 * @see self::verify() 3134 * @access public 3135 * @param string $message 3136 * @return string 3137 */ 3138 function sign($message) 3139 { 3140 if (empty($this->modulus) || empty($this->exponent)) { 3141 return false; 3142 } 3143 3144 switch ($this->signatureMode) { 3145 case self::SIGNATURE_PKCS1: 3146 return $this->_rsassa_pkcs1_v1_5_sign($message); 3147 //case self::SIGNATURE_PSS: 3148 default: 3149 return $this->_rsassa_pss_sign($message); 3150 } 3151 } 3152 3153 /** 3154 * Verifies a signature 3155 * 3156 * @see self::sign() 3157 * @access public 3158 * @param string $message 3159 * @param string $signature 3160 * @return bool 3161 */ 3162 function verify($message, $signature) 3163 { 3164 if (empty($this->modulus) || empty($this->exponent)) { 3165 return false; 3166 } 3167 3168 switch ($this->signatureMode) { 3169 case self::SIGNATURE_PKCS1: 3170 return $this->_rsassa_pkcs1_v1_5_verify($message, $signature); 3171 //case self::SIGNATURE_PSS: 3172 default: 3173 return $this->_rsassa_pss_verify($message, $signature); 3174 } 3175 } 3176 3177 /** 3178 * Extract raw BER from Base64 encoding 3179 * 3180 * @access private 3181 * @param string $str 3182 * @return string 3183 */ 3184 function _extractBER($str) 3185 { 3186 /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them 3187 * above and beyond the ceritificate. 3188 * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line: 3189 * 3190 * Bag Attributes 3191 * localKeyID: 01 00 00 00 3192 * subject=/O=organization/OU=org unit/CN=common name 3193 * issuer=/O=organization/CN=common name 3194 */ 3195 $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1); 3196 // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff 3197 $temp = preg_replace('#-+[^-]+-+#', '', $temp); 3198 // remove new lines 3199 $temp = str_replace(array("\r", "\n", ' '), '', $temp); 3200 $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false; 3201 return $temp != false ? $temp : $str; 3202 } 3203 }
Download modules/phpseclib/Crypt/RSA.class.php
History Sat, 31 Oct 2020 00:43:29 +0100 Jan Dankert New: Support for OpenId Connect; Removed: Support for LDAP.