[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/vendor/phpseclib/phpseclib/phpseclib/Crypt/ -> RSA.php (source)

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