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