Subversion Repositories cheapmusic

Rev

Details | Last modification | View Log | RSS feed

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