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 52namespace phpseclib\Crypt; 53 54use 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 */ 63class 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 1544 /** 1545 * Returns the key size 1546 * 1547 * More specifically, this returns the size of the modulo in bits. 1548 * 1549 * @access public 1550 * @return int 1551 */ 1552 function getSize() 1553 { 1554 return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits()); 1555 } 1556 1557 /** 1558 * Start Element Handler 1559 * 1560 * Called by xml_set_element_handler() 1561 * 1562 * @access private 1563 * @param resource $parser 1564 * @param string $name 1565 * @param array $attribs 1566 */ 1567 function _start_element_handler($parser, $name, $attribs) 1568 { 1569 //$name = strtoupper($name); 1570 switch ($name) { 1571 case 'MODULUS': 1572 $this->current = &$this->components['modulus']; 1573 break; 1574 case 'EXPONENT': 1575 $this->current = &$this->components['publicExponent']; 1576 break; 1577 case 'P': 1578 $this->current = &$this->components['primes'][1]; 1579 break; 1580 case 'Q': 1581 $this->current = &$this->components['primes'][2]; 1582 break; 1583 case 'DP': 1584 $this->current = &$this->components['exponents'][1]; 1585 break; 1586 case 'DQ': 1587 $this->current = &$this->components['exponents'][2]; 1588 break; 1589 case 'INVERSEQ': 1590 $this->current = &$this->components['coefficients'][2]; 1591 break; 1592 case 'D': 1593 $this->current = &$this->components['privateExponent']; 1594 } 1595 $this->current = ''; 1596 } 1597 1598 /** 1599 * Stop Element Handler 1600 * 1601 * Called by xml_set_element_handler() 1602 * 1603 * @access private 1604 * @param resource $parser 1605 * @param string $name 1606 */ 1607 function _stop_element_handler($parser, $name) 1608 { 1609 if (isset($this->current)) { 1610 $this->current = new BigInteger(base64_decode($this->current), 256); 1611 unset($this->current); 1612 } 1613 } 1614 1615 /** 1616 * Data Handler 1617 * 1618 * Called by xml_set_character_data_handler() 1619 * 1620 * @access private 1621 * @param resource $parser 1622 * @param string $data 1623 */ 1624 function _data_handler($parser, $data) 1625 { 1626 if (!isset($this->current) || is_object($this->current)) { 1627 return; 1628 } 1629 $this->current.= trim($data); 1630 } 1631 1632 /** 1633 * Loads a public or private key 1634 * 1635 * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed) 1636 * 1637 * @access public 1638 * @param string|RSA|array $key 1639 * @param bool|int $type optional 1640 * @return bool 1641 */ 1642 function loadKey($key, $type = false) 1643 { 1644 if ($key instanceof RSA) { 1645 $this->privateKeyFormat = $key->privateKeyFormat; 1646 $this->publicKeyFormat = $key->publicKeyFormat; 1647 $this->k = $key->k; 1648 $this->hLen = $key->hLen; 1649 $this->sLen = $key->sLen; 1650 $this->mgfHLen = $key->mgfHLen; 1651 $this->encryptionMode = $key->encryptionMode; 1652 $this->signatureMode = $key->signatureMode; 1653 $this->password = $key->password; 1654 $this->configFile = $key->configFile; 1655 $this->comment = $key->comment; 1656 1657 if (is_object($key->hash)) { 1658 $this->hash = new Hash($key->hash->getHash()); 1659 } 1660 if (is_object($key->mgfHash)) { 1661 $this->mgfHash = new Hash($key->mgfHash->getHash()); 1662 } 1663 1664 if (is_object($key->modulus)) { 1665 $this->modulus = $key->modulus->copy(); 1666 } 1667 if (is_object($key->exponent)) { 1668 $this->exponent = $key->exponent->copy(); 1669 } 1670 if (is_object($key->publicExponent)) { 1671 $this->publicExponent = $key->publicExponent->copy(); 1672 } 1673 1674 $this->primes = array(); 1675 $this->exponents = array(); 1676 $this->coefficients = array(); 1677 1678 foreach ($this->primes as $prime) { 1679 $this->primes[] = $prime->copy(); 1680 } 1681 foreach ($this->exponents as $exponent) { 1682 $this->exponents[] = $exponent->copy(); 1683 } 1684 foreach ($this->coefficients as $coefficient) { 1685 $this->coefficients[] = $coefficient->copy(); 1686 } 1687 1688 return true; 1689 } 1690 1691 if ($type === false) { 1692 $types = array( 1693 self::PUBLIC_FORMAT_RAW, 1694 self::PRIVATE_FORMAT_PKCS1, 1695 self::PRIVATE_FORMAT_XML, 1696 self::PRIVATE_FORMAT_PUTTY, 1697 self::PUBLIC_FORMAT_OPENSSH, 1698 self::PRIVATE_FORMAT_OPENSSH 1699 ); 1700 foreach ($types as $type) { 1701 $components = $this->_parseKey($key, $type); 1702 if ($components !== false) { 1703 break; 1704 } 1705 } 1706 } else { 1707 $components = $this->_parseKey($key, $type); 1708 } 1709 1710 if ($components === false) { 1711 $this->comment = null; 1712 $this->modulus = null; 1713 $this->k = null; 1714 $this->exponent = null; 1715 $this->primes = null; 1716 $this->exponents = null; 1717 $this->coefficients = null; 1718 $this->publicExponent = null; 1719 1720 return false; 1721 } 1722 1723 if (isset($components['comment']) && $components['comment'] !== false) { 1724 $this->comment = $components['comment']; 1725 } 1726 $this->modulus = $components['modulus']; 1727 $this->k = strlen($this->modulus->toBytes()); 1728 $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent']; 1729 if (isset($components['primes'])) { 1730 $this->primes = $components['primes']; 1731 $this->exponents = $components['exponents']; 1732 $this->coefficients = $components['coefficients']; 1733 $this->publicExponent = $components['publicExponent']; 1734 } else { 1735 $this->primes = array(); 1736 $this->exponents = array(); 1737 $this->coefficients = array(); 1738 $this->publicExponent = false; 1739 } 1740 1741 switch ($type) { 1742 case self::PUBLIC_FORMAT_OPENSSH: 1743 case self::PUBLIC_FORMAT_RAW: 1744 $this->setPublicKey(); 1745 break; 1746 case self::PRIVATE_FORMAT_PKCS1: 1747 switch (true) { 1748 case strpos($key, '-BEGIN PUBLIC KEY-') !== false: 1749 case strpos($key, '-BEGIN RSA PUBLIC KEY-') !== false: 1750 $this->setPublicKey(); 1751 } 1752 } 1753 1754 return true; 1755 } 1756 1757 /** 1758 * Sets the password 1759 * 1760 * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false. 1761 * Or rather, pass in $password such that empty($password) && !is_string($password) is true. 1762 * 1763 * @see self::createKey() 1764 * @see self::loadKey() 1765 * @access public 1766 * @param string $password 1767 */ 1768 function setPassword($password = false) 1769 { 1770 $this->password = $password; 1771 } 1772 1773 /** 1774 * Defines the public key 1775 * 1776 * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when 1777 * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a 1778 * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys 1779 * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public 1780 * exponent this won't work unless you manually add the public exponent. phpseclib tries to guess if the key being used 1781 * is the public key but in the event that it guesses incorrectly you might still want to explicitly set the key as being 1782 * public. 1783 * 1784 * Do note that when a new key is loaded the index will be cleared. 1785 * 1786 * Returns true on success, false on failure 1787 * 1788 * @see self::getPublicKey() 1789 * @access public 1790 * @param string $key optional 1791 * @param int $type optional 1792 * @return bool 1793 */ 1794 function setPublicKey($key = false, $type = false) 1795 { 1796 // if a public key has already been loaded return false 1797 if (!empty($this->publicExponent)) { 1798 return false; 1799 } 1800 1801 if ($key === false && !empty($this->modulus)) { 1802 $this->publicExponent = $this->exponent; 1803 return true; 1804 } 1805 1806 if ($type === false) { 1807 $types = array( 1808 self::PUBLIC_FORMAT_RAW, 1809 self::PUBLIC_FORMAT_PKCS1, 1810 self::PUBLIC_FORMAT_XML, 1811 self::PUBLIC_FORMAT_OPENSSH 1812 ); 1813 foreach ($types as $type) { 1814 $components = $this->_parseKey($key, $type); 1815 if ($components !== false) { 1816 break; 1817 } 1818 } 1819 } else { 1820 $components = $this->_parseKey($key, $type); 1821 } 1822 1823 if ($components === false) { 1824 return false; 1825 } 1826 1827 if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) { 1828 $this->modulus = $components['modulus']; 1829 $this->exponent = $this->publicExponent = $components['publicExponent']; 1830 return true; 1831 } 1832 1833 $this->publicExponent = $components['publicExponent']; 1834 1835 return true; 1836 } 1837 1838 /** 1839 * Defines the private key 1840 * 1841 * If phpseclib guessed a private key was a public key and loaded it as such it might be desirable to force 1842 * phpseclib to treat the key as a private key. This function will do that. 1843 * 1844 * Do note that when a new key is loaded the index will be cleared. 1845 * 1846 * Returns true on success, false on failure 1847 * 1848 * @see self::getPublicKey() 1849 * @access public 1850 * @param string $key optional 1851 * @param int $type optional 1852 * @return bool 1853 */ 1854 function setPrivateKey($key = false, $type = false) 1855 { 1856 if ($key === false && !empty($this->publicExponent)) { 1857 $this->publicExponent = false; 1858 return true; 1859 } 1860 1861 $rsa = new RSA(); 1862 if (!$rsa->loadKey($key, $type)) { 1863 return false; 1864 } 1865 $rsa->publicExponent = false; 1866 1867 // don't overwrite the old key if the new key is invalid 1868 $this->loadKey($rsa); 1869 return true; 1870 } 1871 1872 /** 1873 * Returns the public key 1874 * 1875 * The public key is only returned under two circumstances - if the private key had the public key embedded within it 1876 * or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this 1877 * function won't return it since this library, for the most part, doesn't distinguish between public and private keys. 1878 * 1879 * @see self::getPublicKey() 1880 * @access public 1881 * @param string $key 1882 * @param int $type optional 1883 */ 1884 function getPublicKey($type = self::PUBLIC_FORMAT_PKCS8) 1885 { 1886 if (empty($this->modulus) || empty($this->publicExponent)) { 1887 return false; 1888 } 1889 1890 $oldFormat = $this->publicKeyFormat; 1891 $this->publicKeyFormat = $type; 1892 $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent); 1893 $this->publicKeyFormat = $oldFormat; 1894 return $temp; 1895 } 1896 1897 /** 1898 * Returns the public key's fingerprint 1899 * 1900 * The public key's fingerprint is returned, which is equivalent to running `ssh-keygen -lf rsa.pub`. If there is 1901 * no public key currently loaded, false is returned. 1902 * Example output (md5): "c1:b1:30:29:d7:b8:de:6c:97:77:10:d7:46:41:63:87" (as specified by RFC 4716) 1903 * 1904 * @access public 1905 * @param string $algorithm The hashing algorithm to be used. Valid options are 'md5' and 'sha256'. False is returned 1906 * for invalid values. 1907 * @return mixed 1908 */ 1909 function getPublicKeyFingerprint($algorithm = 'md5') 1910 { 1911 if (empty($this->modulus) || empty($this->publicExponent)) { 1912 return false; 1913 } 1914 1915 $modulus = $this->modulus->toBytes(true); 1916 $publicExponent = $this->publicExponent->toBytes(true); 1917 1918 $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus); 1919 1920 switch ($algorithm) { 1921 case 'sha256': 1922 $hash = new Hash('sha256'); 1923 $base = base64_encode($hash->hash($RSAPublicKey)); 1924 return substr($base, 0, strlen($base) - 1); 1925 case 'md5': 1926 return substr(chunk_split(md5($RSAPublicKey), 2, ':'), 0, -1); 1927 default: 1928 return false; 1929 } 1930 } 1931 1932 /** 1933 * Returns the private key 1934 * 1935 * The private key is only returned if the currently loaded key contains the constituent prime numbers. 1936 * 1937 * @see self::getPublicKey() 1938 * @access public 1939 * @param string $key 1940 * @param int $type optional 1941 * @return mixed 1942 */ 1943 function getPrivateKey($type = self::PUBLIC_FORMAT_PKCS1) 1944 { 1945 if (empty($this->primes)) { 1946 return false; 1947 } 1948 1949 $oldFormat = $this->privateKeyFormat; 1950 $this->privateKeyFormat = $type; 1951 $temp = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients); 1952 $this->privateKeyFormat = $oldFormat; 1953 return $temp; 1954 } 1955 1956 /** 1957 * Returns a minimalistic private key 1958 * 1959 * Returns the private key without the prime number constituants. Structurally identical to a public key that 1960 * hasn't been set as the public key 1961 * 1962 * @see self::getPrivateKey() 1963 * @access private 1964 * @param string $key 1965 * @param int $type optional 1966 */ 1967 function _getPrivatePublicKey($mode = self::PUBLIC_FORMAT_PKCS8) 1968 { 1969 if (empty($this->modulus) || empty($this->exponent)) { 1970 return false; 1971 } 1972 1973 $oldFormat = $this->publicKeyFormat; 1974 $this->publicKeyFormat = $mode; 1975 $temp = $this->_convertPublicKey($this->modulus, $this->exponent); 1976 $this->publicKeyFormat = $oldFormat; 1977 return $temp; 1978 } 1979 1980 /** 1981 * __toString() magic method 1982 * 1983 * @access public 1984 * @return string 1985 */ 1986 function __toString() 1987 { 1988 $key = $this->getPrivateKey($this->privateKeyFormat); 1989 if ($key !== false) { 1990 return $key; 1991 } 1992 $key = $this->_getPrivatePublicKey($this->publicKeyFormat); 1993 return $key !== false ? $key : ''; 1994 } 1995 1996 /** 1997 * __clone() magic method 1998 * 1999 * @access public 2000 * @return Crypt_RSA 2001 */ 2002 function __clone() 2003 { 2004 $key = new RSA(); 2005 $key->loadKey($this); 2006 return $key; 2007 } 2008 2009 /** 2010 * Generates the smallest and largest numbers requiring $bits bits 2011 * 2012 * @access private 2013 * @param int $bits 2014 * @return array 2015 */ 2016 function _generateMinMax($bits) 2017 { 2018 $bytes = $bits >> 3; 2019 $min = str_repeat(chr(0), $bytes); 2020 $max = str_repeat(chr(0xFF), $bytes); 2021 $msb = $bits & 7; 2022 if ($msb) { 2023 $min = chr(1 << ($msb - 1)) . $min; 2024 $max = chr((1 << $msb) - 1) . $max; 2025 } else { 2026 $min[0] = chr(0x80); 2027 } 2028 2029 return array( 2030 'min' => new BigInteger($min, 256), 2031 'max' => new BigInteger($max, 256) 2032 ); 2033 } 2034 2035 /** 2036 * DER-decode the length 2037 * 2038 * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See 2039 * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information. 2040 * 2041 * @access private 2042 * @param string $string 2043 * @return int 2044 */ 2045 function _decodeLength(&$string) 2046 { 2047 $length = ord($this->_string_shift($string)); 2048 if ($length & 0x80) { // definite length, long form 2049 $length&= 0x7F; 2050 $temp = $this->_string_shift($string, $length); 2051 list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)); 2052 } 2053 return $length; 2054 } 2055 2056 /** 2057 * DER-encode the length 2058 * 2059 * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See 2060 * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information. 2061 * 2062 * @access private 2063 * @param int $length 2064 * @return string 2065 */ 2066 function _encodeLength($length) 2067 { 2068 if ($length <= 0x7F) { 2069 return chr($length); 2070 } 2071 2072 $temp = ltrim(pack('N', $length), chr(0)); 2073 return pack('Ca*', 0x80 | strlen($temp), $temp); 2074 } 2075 2076 /** 2077 * String Shift 2078 * 2079 * Inspired by array_shift 2080 * 2081 * @param string $string 2082 * @param int $index 2083 * @return string 2084 * @access private 2085 */ 2086 function _string_shift(&$string, $index = 1) 2087 { 2088 $substr = substr($string, 0, $index); 2089 $string = substr($string, $index); 2090 return $substr; 2091 } 2092 2093 /** 2094 * Determines the private key format 2095 * 2096 * @see self::createKey() 2097 * @access public 2098 * @param int $format 2099 */ 2100 function setPrivateKeyFormat($format) 2101 { 2102 $this->privateKeyFormat = $format; 2103 } 2104 2105 /** 2106 * Determines the public key format 2107 * 2108 * @see self::createKey() 2109 * @access public 2110 * @param int $format 2111 */ 2112 function setPublicKeyFormat($format) 2113 { 2114 $this->publicKeyFormat = $format; 2115 } 2116 2117 /** 2118 * Determines which hashing function should be used 2119 * 2120 * Used with signature production / verification and (if the encryption mode is self::ENCRYPTION_OAEP) encryption and 2121 * decryption. If $hash isn't supported, sha1 is used. 2122 * 2123 * @access public 2124 * @param string $hash 2125 */ 2126 function setHash($hash) 2127 { 2128 // \phpseclib\Crypt\Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example. 2129 switch ($hash) { 2130 case 'md2': 2131 case 'md5': 2132 case 'sha1': 2133 case 'sha256': 2134 case 'sha384': 2135 case 'sha512': 2136 $this->hash = new Hash($hash); 2137 $this->hashName = $hash; 2138 break; 2139 default: 2140 $this->hash = new Hash('sha1'); 2141 $this->hashName = 'sha1'; 2142 } 2143 $this->hLen = $this->hash->getLength(); 2144 } 2145 2146 /** 2147 * Determines which hashing function should be used for the mask generation function 2148 * 2149 * The mask generation function is used by self::ENCRYPTION_OAEP and self::SIGNATURE_PSS and although it's 2150 * best if Hash and MGFHash are set to the same thing this is not a requirement. 2151 * 2152 * @access public 2153 * @param string $hash 2154 */ 2155 function setMGFHash($hash) 2156 { 2157 // \phpseclib\Crypt\Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example. 2158 switch ($hash) { 2159 case 'md2': 2160 case 'md5': 2161 case 'sha1': 2162 case 'sha256': 2163 case 'sha384': 2164 case 'sha512': 2165 $this->mgfHash = new Hash($hash); 2166 break; 2167 default: 2168 $this->mgfHash = new Hash('sha1'); 2169 } 2170 $this->mgfHLen = $this->mgfHash->getLength(); 2171 } 2172 2173 /** 2174 * Determines the salt length 2175 * 2176 * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}: 2177 * 2178 * Typical salt lengths in octets are hLen (the length of the output 2179 * of the hash function Hash) and 0. 2180 * 2181 * @access public 2182 * @param int $format 2183 */ 2184 function setSaltLength($sLen) 2185 { 2186 $this->sLen = $sLen; 2187 } 2188 2189 /** 2190 * Integer-to-Octet-String primitive 2191 * 2192 * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}. 2193 * 2194 * @access private 2195 * @param \phpseclib\Math\BigInteger $x 2196 * @param int $xLen 2197 * @return string 2198 */ 2199 function _i2osp($x, $xLen) 2200 { 2201 $x = $x->toBytes(); 2202 if (strlen($x) > $xLen) { 2203 user_error('Integer too large'); 2204 return false; 2205 } 2206 return str_pad($x, $xLen, chr(0), STR_PAD_LEFT); 2207 } 2208 2209 /** 2210 * Octet-String-to-Integer primitive 2211 * 2212 * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}. 2213 * 2214 * @access private 2215 * @param string $x 2216 * @return \phpseclib\Math\BigInteger 2217 */ 2218 function _os2ip($x) 2219 { 2220 return new BigInteger($x, 256); 2221 } 2222 2223 /** 2224 * Exponentiate with or without Chinese Remainder Theorem 2225 * 2226 * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}. 2227 * 2228 * @access private 2229 * @param \phpseclib\Math\BigInteger $x 2230 * @return \phpseclib\Math\BigInteger 2231 */ 2232 function _exponentiate($x) 2233 { 2234 switch (true) { 2235 case empty($this->primes): 2236 case $this->primes[1]->equals($this->zero): 2237 case empty($this->coefficients): 2238 case $this->coefficients[2]->equals($this->zero): 2239 case empty($this->exponents): 2240 case $this->exponents[1]->equals($this->zero): 2241 return $x->modPow($this->exponent, $this->modulus); 2242 } 2243 2244 $num_primes = count($this->primes); 2245 2246 if (defined('CRYPT_RSA_DISABLE_BLINDING')) { 2247 $m_i = array( 2248 1 => $x->modPow($this->exponents[1], $this->primes[1]), 2249 2 => $x->modPow($this->exponents[2], $this->primes[2]) 2250 ); 2251 $h = $m_i[1]->subtract($m_i[2]); 2252 $h = $h->multiply($this->coefficients[2]); 2253 list(, $h) = $h->divide($this->primes[1]); 2254 $m = $m_i[2]->add($h->multiply($this->primes[2])); 2255 2256 $r = $this->primes[1]; 2257 for ($i = 3; $i <= $num_primes; $i++) { 2258 $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]); 2259 2260 $r = $r->multiply($this->primes[$i - 1]); 2261 2262 $h = $m_i->subtract($m); 2263 $h = $h->multiply($this->coefficients[$i]); 2264 list(, $h) = $h->divide($this->primes[$i]); 2265 2266 $m = $m->add($r->multiply($h)); 2267 } 2268 } else { 2269 $smallest = $this->primes[1]; 2270 for ($i = 2; $i <= $num_primes; $i++) { 2271 if ($smallest->compare($this->primes[$i]) > 0) { 2272 $smallest = $this->primes[$i]; 2273 } 2274 } 2275 2276 $one = new BigInteger(1); 2277 2278 $r = $one->random($one, $smallest->subtract($one)); 2279 2280 $m_i = array( 2281 1 => $this->_blind($x, $r, 1), 2282 2 => $this->_blind($x, $r, 2) 2283 ); 2284 $h = $m_i[1]->subtract($m_i[2]); 2285 $h = $h->multiply($this->coefficients[2]); 2286 list(, $h) = $h->divide($this->primes[1]); 2287 $m = $m_i[2]->add($h->multiply($this->primes[2])); 2288 2289 $r = $this->primes[1]; 2290 for ($i = 3; $i <= $num_primes; $i++) { 2291 $m_i = $this->_blind($x, $r, $i); 2292 2293 $r = $r->multiply($this->primes[$i - 1]); 2294 2295 $h = $m_i->subtract($m); 2296 $h = $h->multiply($this->coefficients[$i]); 2297 list(, $h) = $h->divide($this->primes[$i]); 2298 2299 $m = $m->add($r->multiply($h)); 2300 } 2301 } 2302 2303 return $m; 2304 } 2305 2306 /** 2307 * Performs RSA Blinding 2308 * 2309 * Protects against timing attacks by employing RSA Blinding. 2310 * Returns $x->modPow($this->exponents[$i], $this->primes[$i]) 2311 * 2312 * @access private 2313 * @param \phpseclib\Math\BigInteger $x 2314 * @param \phpseclib\Math\BigInteger $r 2315 * @param int $i 2316 * @return \phpseclib\Math\BigInteger 2317 */ 2318 function _blind($x, $r, $i) 2319 { 2320 $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i])); 2321 $x = $x->modPow($this->exponents[$i], $this->primes[$i]); 2322 2323 $r = $r->modInverse($this->primes[$i]); 2324 $x = $x->multiply($r); 2325 list(, $x) = $x->divide($this->primes[$i]); 2326 2327 return $x; 2328 } 2329 2330 /** 2331 * Performs blinded RSA equality testing 2332 * 2333 * Protects against a particular type of timing attack described. 2334 * 2335 * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)} 2336 * 2337 * Thanks for the heads up singpolyma! 2338 * 2339 * @access private 2340 * @param string $x 2341 * @param string $y 2342 * @return bool 2343 */ 2344 function _equals($x, $y) 2345 { 2346 if (function_exists('hash_equals')) { 2347 return hash_equals($x, $y); 2348 } 2349 2350 if (strlen($x) != strlen($y)) { 2351 return false; 2352 } 2353 2354 $result = "\0"; 2355 $x^= $y; 2356 for ($i = 0; $i < strlen($x); $i++) { 2357 $result|= $x[$i]; 2358 } 2359 2360 return $result === "\0"; 2361 } 2362 2363 /** 2364 * RSAEP 2365 * 2366 * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}. 2367 * 2368 * @access private 2369 * @param \phpseclib\Math\BigInteger $m 2370 * @return \phpseclib\Math\BigInteger 2371 */ 2372 function _rsaep($m) 2373 { 2374 if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) { 2375 user_error('Message representative out of range'); 2376 return false; 2377 } 2378 return $this->_exponentiate($m); 2379 } 2380 2381 /** 2382 * RSADP 2383 * 2384 * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}. 2385 * 2386 * @access private 2387 * @param \phpseclib\Math\BigInteger $c 2388 * @return \phpseclib\Math\BigInteger 2389 */ 2390 function _rsadp($c) 2391 { 2392 if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) { 2393 user_error('Ciphertext representative out of range'); 2394 return false; 2395 } 2396 return $this->_exponentiate($c); 2397 } 2398 2399 /** 2400 * RSASP1 2401 * 2402 * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}. 2403 * 2404 * @access private 2405 * @param \phpseclib\Math\BigInteger $m 2406 * @return \phpseclib\Math\BigInteger 2407 */ 2408 function _rsasp1($m) 2409 { 2410 if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) { 2411 user_error('Message representative out of range'); 2412 return false; 2413 } 2414 return $this->_exponentiate($m); 2415 } 2416 2417 /** 2418 * RSAVP1 2419 * 2420 * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}. 2421 * 2422 * @access private 2423 * @param \phpseclib\Math\BigInteger $s 2424 * @return \phpseclib\Math\BigInteger 2425 */ 2426 function _rsavp1($s) 2427 { 2428 if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) { 2429 user_error('Signature representative out of range'); 2430 return false; 2431 } 2432 return $this->_exponentiate($s); 2433 } 2434 2435 /** 2436 * MGF1 2437 * 2438 * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}. 2439 * 2440 * @access private 2441 * @param string $mgfSeed 2442 * @param int $mgfLen 2443 * @return string 2444 */ 2445 function _mgf1($mgfSeed, $maskLen) 2446 { 2447 // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output. 2448 2449 $t = ''; 2450 $count = ceil($maskLen / $this->mgfHLen); 2451 for ($i = 0; $i < $count; $i++) { 2452 $c = pack('N', $i); 2453 $t.= $this->mgfHash->hash($mgfSeed . $c); 2454 } 2455 2456 return substr($t, 0, $maskLen); 2457 } 2458 2459 /** 2460 * RSAES-OAEP-ENCRYPT 2461 * 2462 * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and 2463 * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}. 2464 * 2465 * @access private 2466 * @param string $m 2467 * @param string $l 2468 * @return string 2469 */ 2470 function _rsaes_oaep_encrypt($m, $l = '') 2471 { 2472 $mLen = strlen($m); 2473 2474 // Length checking 2475 2476 // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error 2477 // be output. 2478 2479 if ($mLen > $this->k - 2 * $this->hLen - 2) { 2480 user_error('Message too long'); 2481 return false; 2482 } 2483 2484 // EME-OAEP encoding 2485 2486 $lHash = $this->hash->hash($l); 2487 $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2); 2488 $db = $lHash . $ps . chr(1) . $m; 2489 $seed = Random::string($this->hLen); 2490 $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1); 2491 $maskedDB = $db ^ $dbMask; 2492 $seedMask = $this->_mgf1($maskedDB, $this->hLen); 2493 $maskedSeed = $seed ^ $seedMask; 2494 $em = chr(0) . $maskedSeed . $maskedDB; 2495 2496 // RSA encryption 2497 2498 $m = $this->_os2ip($em); 2499 $c = $this->_rsaep($m); 2500 $c = $this->_i2osp($c, $this->k); 2501 2502 // Output the ciphertext C 2503 2504 return $c; 2505 } 2506 2507 /** 2508 * RSAES-OAEP-DECRYPT 2509 * 2510 * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error 2511 * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2: 2512 * 2513 * Note. Care must be taken to ensure that an opponent cannot 2514 * distinguish the different error conditions in Step 3.g, whether by 2515 * error message or timing, or, more generally, learn partial 2516 * information about the encoded message EM. Otherwise an opponent may 2517 * be able to obtain useful information about the decryption of the 2518 * ciphertext C, leading to a chosen-ciphertext attack such as the one 2519 * observed by Manger [36]. 2520 * 2521 * As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}: 2522 * 2523 * Both the encryption and the decryption operations of RSAES-OAEP take 2524 * the value of a label L as input. In this version of PKCS #1, L is 2525 * the empty string; other uses of the label are outside the scope of 2526 * this document. 2527 * 2528 * @access private 2529 * @param string $c 2530 * @param string $l 2531 * @return string 2532 */ 2533 function _rsaes_oaep_decrypt($c, $l = '') 2534 { 2535 // Length checking 2536 2537 // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error 2538 // be output. 2539 2540 if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) { 2541 user_error('Decryption error'); 2542 return false; 2543 } 2544 2545 // RSA decryption 2546 2547 $c = $this->_os2ip($c); 2548 $m = $this->_rsadp($c); 2549 if ($m === false) { 2550 user_error('Decryption error'); 2551 return false; 2552 } 2553 $em = $this->_i2osp($m, $this->k); 2554 2555 // EME-OAEP decoding 2556 2557 $lHash = $this->hash->hash($l); 2558 $y = ord($em[0]); 2559 $maskedSeed = substr($em, 1, $this->hLen); 2560 $maskedDB = substr($em, $this->hLen + 1); 2561 $seedMask = $this->_mgf1($maskedDB, $this->hLen); 2562 $seed = $maskedSeed ^ $seedMask; 2563 $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1); 2564 $db = $maskedDB ^ $dbMask; 2565 $lHash2 = substr($db, 0, $this->hLen); 2566 $m = substr($db, $this->hLen); 2567 $hashesMatch = $this->_equals($lHash, $lHash2); 2568 $leadingZeros = 1; 2569 $patternMatch = 0; 2570 $offset = 0; 2571 for ($i = 0; $i < strlen($m); $i++) { 2572 $patternMatch|= $leadingZeros & ($m[$i] === "\1"); 2573 $leadingZeros&= $m[$i] === "\0"; 2574 $offset+= $patternMatch ? 0 : 1; 2575 } 2576 2577 // we do & instead of && to avoid https://en.wikipedia.org/wiki/Short-circuit_evaluation 2578 // to protect against timing attacks 2579 if (!$hashesMatch & !$patternMatch) { 2580 user_error('Decryption error'); 2581 return false; 2582 } 2583 2584 // Output the message M 2585 2586 return substr($m, $offset + 1); 2587 } 2588 2589 /** 2590 * Raw Encryption / Decryption 2591 * 2592 * Doesn't use padding and is not recommended. 2593 * 2594 * @access private 2595 * @param string $m 2596 * @return string 2597 */ 2598 function _raw_encrypt($m) 2599 { 2600 $temp = $this->_os2ip($m); 2601 $temp = $this->_rsaep($temp); 2602 return $this->_i2osp($temp, $this->k); 2603 } 2604 2605 /** 2606 * RSAES-PKCS1-V1_5-ENCRYPT 2607 * 2608 * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}. 2609 * 2610 * @access private 2611 * @param string $m 2612 * @return string 2613 */ 2614 function _rsaes_pkcs1_v1_5_encrypt($m) 2615 { 2616 $mLen = strlen($m); 2617 2618 // Length checking 2619 2620 if ($mLen > $this->k - 11) { 2621 user_error('Message too long'); 2622 return false; 2623 } 2624 2625 // EME-PKCS1-v1_5 encoding 2626 2627 $psLen = $this->k - $mLen - 3; 2628 $ps = ''; 2629 while (strlen($ps) != $psLen) { 2630 $temp = Random::string($psLen - strlen($ps)); 2631 $temp = str_replace("\x00", '', $temp); 2632 $ps.= $temp; 2633 } 2634 $type = 2; 2635 // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done 2636 if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) { 2637 $type = 1; 2638 // "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF" 2639 $ps = str_repeat("\xFF", $psLen); 2640 } 2641 $em = chr(0) . chr($type) . $ps . chr(0) . $m; 2642 2643 // RSA encryption 2644 $m = $this->_os2ip($em); 2645 $c = $this->_rsaep($m); 2646 $c = $this->_i2osp($c, $this->k); 2647 2648 // Output the ciphertext C 2649 2650 return $c; 2651 } 2652 2653 /** 2654 * RSAES-PKCS1-V1_5-DECRYPT 2655 * 2656 * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}. 2657 * 2658 * For compatibility purposes, this function departs slightly from the description given in RFC3447. 2659 * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the 2660 * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the 2661 * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed 2662 * to be 2 regardless of which key is used. For compatibility purposes, we'll just check to make sure the 2663 * second byte is 2 or less. If it is, we'll accept the decrypted string as valid. 2664 * 2665 * As a consequence of this, a private key encrypted ciphertext produced with \phpseclib\Crypt\RSA may not decrypt 2666 * with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but 2667 * not private key encrypted ciphertext's. 2668 * 2669 * @access private 2670 * @param string $c 2671 * @return string 2672 */ 2673 function _rsaes_pkcs1_v1_5_decrypt($c) 2674 { 2675 // Length checking 2676 2677 if (strlen($c) != $this->k) { // or if k < 11 2678 user_error('Decryption error'); 2679 return false; 2680 } 2681 2682 // RSA decryption 2683 2684 $c = $this->_os2ip($c); 2685 $m = $this->_rsadp($c); 2686 2687 if ($m === false) { 2688 user_error('Decryption error'); 2689 return false; 2690 } 2691 $em = $this->_i2osp($m, $this->k); 2692 2693 // EME-PKCS1-v1_5 decoding 2694 2695 if (ord($em[0]) != 0 || ord($em[1]) > 2) { 2696 user_error('Decryption error'); 2697 return false; 2698 } 2699 2700 $ps = substr($em, 2, strpos($em, chr(0), 2) - 2); 2701 $m = substr($em, strlen($ps) + 3); 2702 2703 if (strlen($ps) < 8) { 2704 user_error('Decryption error'); 2705 return false; 2706 } 2707 2708 // Output M 2709 2710 return $m; 2711 } 2712 2713 /** 2714 * EMSA-PSS-ENCODE 2715 * 2716 * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}. 2717 * 2718 * @access private 2719 * @param string $m 2720 * @param int $emBits 2721 */ 2722 function _emsa_pss_encode($m, $emBits) 2723 { 2724 // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error 2725 // be output. 2726 2727 $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8) 2728 $sLen = $this->sLen !== null ? $this->sLen : $this->hLen; 2729 2730 $mHash = $this->hash->hash($m); 2731 if ($emLen < $this->hLen + $sLen + 2) { 2732 user_error('Encoding error'); 2733 return false; 2734 } 2735 2736 $salt = Random::string($sLen); 2737 $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; 2738 $h = $this->hash->hash($m2); 2739 $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2); 2740 $db = $ps . chr(1) . $salt; 2741 $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1); 2742 $maskedDB = $db ^ $dbMask; 2743 $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0]; 2744 $em = $maskedDB . $h . chr(0xBC); 2745 2746 return $em; 2747 } 2748 2749 /** 2750 * EMSA-PSS-VERIFY 2751 * 2752 * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}. 2753 * 2754 * @access private 2755 * @param string $m 2756 * @param string $em 2757 * @param int $emBits 2758 * @return string 2759 */ 2760 function _emsa_pss_verify($m, $em, $emBits) 2761 { 2762 // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error 2763 // be output. 2764 2765 $emLen = ($emBits + 7) >> 3; // ie. ceil($emBits / 8); 2766 $sLen = $this->sLen !== null ? $this->sLen : $this->hLen; 2767 2768 $mHash = $this->hash->hash($m); 2769 if ($emLen < $this->hLen + $sLen + 2) { 2770 return false; 2771 } 2772 2773 if ($em[strlen($em) - 1] != chr(0xBC)) { 2774 return false; 2775 } 2776 2777 $maskedDB = substr($em, 0, -$this->hLen - 1); 2778 $h = substr($em, -$this->hLen - 1, $this->hLen); 2779 $temp = chr(0xFF << ($emBits & 7)); 2780 if ((~$maskedDB[0] & $temp) != $temp) { 2781 return false; 2782 } 2783 $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1); 2784 $db = $maskedDB ^ $dbMask; 2785 $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0]; 2786 $temp = $emLen - $this->hLen - $sLen - 2; 2787 if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) { 2788 return false; 2789 } 2790 $salt = substr($db, $temp + 1); // should be $sLen long 2791 $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; 2792 $h2 = $this->hash->hash($m2); 2793 return $this->_equals($h, $h2); 2794 } 2795 2796 /** 2797 * RSASSA-PSS-SIGN 2798 * 2799 * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}. 2800 * 2801 * @access private 2802 * @param string $m 2803 * @return string 2804 */ 2805 function _rsassa_pss_sign($m) 2806 { 2807 // EMSA-PSS encoding 2808 2809 $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1); 2810 2811 // RSA signature 2812 2813 $m = $this->_os2ip($em); 2814 $s = $this->_rsasp1($m); 2815 $s = $this->_i2osp($s, $this->k); 2816 2817 // Output the signature S 2818 2819 return $s; 2820 } 2821 2822 /** 2823 * RSASSA-PSS-VERIFY 2824 * 2825 * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}. 2826 * 2827 * @access private 2828 * @param string $m 2829 * @param string $s 2830 * @return string 2831 */ 2832 function _rsassa_pss_verify($m, $s) 2833 { 2834 // Length checking 2835 2836 if (strlen($s) != $this->k) { 2837 user_error('Invalid signature'); 2838 return false; 2839 } 2840 2841 // RSA verification 2842 2843 $modBits = strlen($this->modulus->toBits()); 2844 2845 $s2 = $this->_os2ip($s); 2846 $m2 = $this->_rsavp1($s2); 2847 if ($m2 === false) { 2848 user_error('Invalid signature'); 2849 return false; 2850 } 2851 $em = $this->_i2osp($m2, $this->k); 2852 if ($em === false) { 2853 user_error('Invalid signature'); 2854 return false; 2855 } 2856 2857 // EMSA-PSS verification 2858 2859 return $this->_emsa_pss_verify($m, $em, $modBits - 1); 2860 } 2861 2862 /** 2863 * EMSA-PKCS1-V1_5-ENCODE 2864 * 2865 * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}. 2866 * 2867 * @access private 2868 * @param string $m 2869 * @param int $emLen 2870 * @return string 2871 */ 2872 function _emsa_pkcs1_v1_5_encode($m, $emLen) 2873 { 2874 $h = $this->hash->hash($m); 2875 if ($h === false) { 2876 return false; 2877 } 2878 2879 // see http://tools.ietf.org/html/rfc3447#page-43 2880 switch ($this->hashName) { 2881 case 'md2': 2882 $t = pack('H*', '3020300c06082a864886f70d020205000410'); 2883 break; 2884 case 'md5': 2885 $t = pack('H*', '3020300c06082a864886f70d020505000410'); 2886 break; 2887 case 'sha1': 2888 $t = pack('H*', '3021300906052b0e03021a05000414'); 2889 break; 2890 case 'sha256': 2891 $t = pack('H*', '3031300d060960864801650304020105000420'); 2892 break; 2893 case 'sha384': 2894 $t = pack('H*', '3041300d060960864801650304020205000430'); 2895 break; 2896 case 'sha512': 2897 $t = pack('H*', '3051300d060960864801650304020305000440'); 2898 } 2899 $t.= $h; 2900 $tLen = strlen($t); 2901 2902 if ($emLen < $tLen + 11) { 2903 user_error('Intended encoded message length too short'); 2904 return false; 2905 } 2906 2907 $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3); 2908 2909 $em = "\0\1$ps\0$t"; 2910 2911 return $em; 2912 } 2913 2914 /** 2915 * RSASSA-PKCS1-V1_5-SIGN 2916 * 2917 * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}. 2918 * 2919 * @access private 2920 * @param string $m 2921 * @return string 2922 */ 2923 function _rsassa_pkcs1_v1_5_sign($m) 2924 { 2925 // EMSA-PKCS1-v1_5 encoding 2926 2927 $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); 2928 if ($em === false) { 2929 user_error('RSA modulus too short'); 2930 return false; 2931 } 2932 2933 // RSA signature 2934 2935 $m = $this->_os2ip($em); 2936 $s = $this->_rsasp1($m); 2937 $s = $this->_i2osp($s, $this->k); 2938 2939 // Output the signature S 2940 2941 return $s; 2942 } 2943 2944 /** 2945 * RSASSA-PKCS1-V1_5-VERIFY 2946 * 2947 * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}. 2948 * 2949 * @access private 2950 * @param string $m 2951 * @return string 2952 */ 2953 function _rsassa_pkcs1_v1_5_verify($m, $s) 2954 { 2955 // Length checking 2956 2957 if (strlen($s) != $this->k) { 2958 user_error('Invalid signature'); 2959 return false; 2960 } 2961 2962 // RSA verification 2963 2964 $s = $this->_os2ip($s); 2965 $m2 = $this->_rsavp1($s); 2966 if ($m2 === false) { 2967 user_error('Invalid signature'); 2968 return false; 2969 } 2970 $em = $this->_i2osp($m2, $this->k); 2971 if ($em === false) { 2972 user_error('Invalid signature'); 2973 return false; 2974 } 2975 2976 // EMSA-PKCS1-v1_5 encoding 2977 2978 $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); 2979 if ($em2 === false) { 2980 user_error('RSA modulus too short'); 2981 return false; 2982 } 2983 2984 // Compare 2985 return $this->_equals($em, $em2); 2986 } 2987 2988 /** 2989 * Set Encryption Mode 2990 * 2991 * Valid values include self::ENCRYPTION_OAEP and self::ENCRYPTION_PKCS1. 2992 * 2993 * @access public 2994 * @param int $mode 2995 */ 2996 function setEncryptionMode($mode) 2997 { 2998 $this->encryptionMode = $mode; 2999 } 3000 3001 /** 3002 * Set Signature Mode 3003 * 3004 * Valid values include self::SIGNATURE_PSS and self::SIGNATURE_PKCS1 3005 * 3006 * @access public 3007 * @param int $mode 3008 */ 3009 function setSignatureMode($mode) 3010 { 3011 $this->signatureMode = $mode; 3012 } 3013 3014 /** 3015 * Set public key comment. 3016 * 3017 * @access public 3018 * @param string $comment 3019 */ 3020 function setComment($comment) 3021 { 3022 $this->comment = $comment; 3023 } 3024 3025 /** 3026 * Get public key comment. 3027 * 3028 * @access public 3029 * @return string 3030 */ 3031 function getComment() 3032 { 3033 return $this->comment; 3034 } 3035 3036 /** 3037 * Encryption 3038 * 3039 * Both self::ENCRYPTION_OAEP and self::ENCRYPTION_PKCS1 both place limits on how long $plaintext can be. 3040 * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will 3041 * be concatenated together. 3042 * 3043 * @see self::decrypt() 3044 * @access public 3045 * @param string $plaintext 3046 * @return string 3047 */ 3048 function encrypt($plaintext) 3049 { 3050 switch ($this->encryptionMode) { 3051 case self::ENCRYPTION_NONE: 3052 $plaintext = str_split($plaintext, $this->k); 3053 $ciphertext = ''; 3054 foreach ($plaintext as $m) { 3055 $ciphertext.= $this->_raw_encrypt($m); 3056 } 3057 return $ciphertext; 3058 case self::ENCRYPTION_PKCS1: 3059 $length = $this->k - 11; 3060 if ($length <= 0) { 3061 return false; 3062 } 3063 3064 $plaintext = str_split($plaintext, $length); 3065 $ciphertext = ''; 3066 foreach ($plaintext as $m) { 3067 $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m); 3068 } 3069 return $ciphertext; 3070 //case self::ENCRYPTION_OAEP: 3071 default: 3072 $length = $this->k - 2 * $this->hLen - 2; 3073 if ($length <= 0) { 3074 return false; 3075 } 3076 3077 $plaintext = str_split($plaintext, $length); 3078 $ciphertext = ''; 3079 foreach ($plaintext as $m) { 3080 $ciphertext.= $this->_rsaes_oaep_encrypt($m); 3081 } 3082 return $ciphertext; 3083 } 3084 } 3085 3086 /** 3087 * Decryption 3088 * 3089 * @see self::encrypt() 3090 * @access public 3091 * @param string $plaintext 3092 * @return string 3093 */ 3094 function decrypt($ciphertext) 3095 { 3096 if ($this->k <= 0) { 3097 return false; 3098 } 3099 3100 $ciphertext = str_split($ciphertext, $this->k); 3101 $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT); 3102 3103 $plaintext = ''; 3104 3105 switch ($this->encryptionMode) { 3106 case self::ENCRYPTION_NONE: 3107 $decrypt = '_raw_encrypt'; 3108 break; 3109 case self::ENCRYPTION_PKCS1: 3110 $decrypt = '_rsaes_pkcs1_v1_5_decrypt'; 3111 break; 3112 //case self::ENCRYPTION_OAEP: 3113 default: 3114 $decrypt = '_rsaes_oaep_decrypt'; 3115 } 3116 3117 foreach ($ciphertext as $c) { 3118 $temp = $this->$decrypt($c); 3119 if ($temp === false) { 3120 return false; 3121 } 3122 $plaintext.= $temp; 3123 } 3124 3125 return $plaintext; 3126 } 3127 3128 /** 3129 * Create a signature 3130 * 3131 * @see self::verify() 3132 * @access public 3133 * @param string $message 3134 * @return string 3135 */ 3136 function sign($message) 3137 { 3138 if (empty($this->modulus) || empty($this->exponent)) { 3139 return false; 3140 } 3141 3142 switch ($this->signatureMode) { 3143 case self::SIGNATURE_PKCS1: 3144 return $this->_rsassa_pkcs1_v1_5_sign($message); 3145 //case self::SIGNATURE_PSS: 3146 default: 3147 return $this->_rsassa_pss_sign($message); 3148 } 3149 } 3150 3151 /** 3152 * Verifies a signature 3153 * 3154 * @see self::sign() 3155 * @access public 3156 * @param string $message 3157 * @param string $signature 3158 * @return bool 3159 */ 3160 function verify($message, $signature) 3161 { 3162 if (empty($this->modulus) || empty($this->exponent)) { 3163 return false; 3164 } 3165 3166 switch ($this->signatureMode) { 3167 case self::SIGNATURE_PKCS1: 3168 return $this->_rsassa_pkcs1_v1_5_verify($message, $signature); 3169 //case self::SIGNATURE_PSS: 3170 default: 3171 return $this->_rsassa_pss_verify($message, $signature); 3172 } 3173 } 3174 3175 /** 3176 * Extract raw BER from Base64 encoding 3177 * 3178 * @access private 3179 * @param string $str 3180 * @return string 3181 */ 3182 function _extractBER($str) 3183 { 3184 /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them 3185 * above and beyond the ceritificate. 3186 * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line: 3187 * 3188 * Bag Attributes 3189 * localKeyID: 01 00 00 00 3190 * subject=/O=organization/OU=org unit/CN=common name 3191 * issuer=/O=organization/CN=common name 3192 */ 3193 $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1); 3194 // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff 3195 $temp = preg_replace('#-+[^-]+-+#', '', $temp); 3196 // remove new lines 3197 $temp = str_replace(array("\r", "\n", ' '), '', $temp); 3198 $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false; 3199 return $temp != false ? $temp : $str; 3200 } 3201} 3202