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