Failed Conditions
Push — PHPSecLib_Rid ( 2ba149...2881a4 )
by Florent
05:10
created

src/Util/RSA.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * The MIT License (MIT)
5
 *
6
 * Copyright (c) 2014-2016 Spomky-Labs
7
 *
8
 * This software may be modified and distributed under the terms
9
 * of the MIT license.  See the LICENSE file for details.
10
 */
11
12
namespace Jose\Util;
13
14
/**
15
 * Pure-PHP PKCS#1 compliant implementation of RSA.
16
 *
17
 * @author  Jim Wigginton <[email protected]>
18
 */
19
final class RSA
20
{
21
    /**#@+
22
     * @see self::encrypt()
23
     * @see self::decrypt()
24
     */
25
    /**
26
     * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
27
     * (OAEP) for encryption / decryption.
28
     *
29
     * Uses sha1 by default.
30
     *
31
     * @see self::setHash()
32
     * @see self::setMGFHash()
33
     */
34
    const ENCRYPTION_OAEP = 1;
35
36
    /**
37
     * Use PKCS#1 padding.
38
     *
39
     * Although self::ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
40
     * compatibility with protocols (like SSH-1) written before OAEP's introduction.
41
     */
42
    const ENCRYPTION_PKCS1 = 2;
43
44
    /**#@-*/
45
46
    /**#@+
47
     * @see self::sign()
48
     * @see self::verify()
49
     * @see self::setHash()
50
     */
51
    /**
52
     * Use the Probabilistic Signature Scheme for signing.
53
     *
54
     * Uses sha1 by default.
55
     *
56
     * @see self::setSaltLength()
57
     * @see self::setMGFHash()
58
     */
59
    const SIGNATURE_PSS = 1;
60
    /**
61
     * Use the PKCS#1 scheme by default.
62
     *
63
     * Although self::SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
64
     * compatibility with protocols (like SSH-2) written before PSS's introduction.
65
     */
66
    const SIGNATURE_PKCS1 = 2;
67
    /**#@-*/
68
69
    /**#@+
70
     * @see \phpseclib\Crypt\RSA::createKey()
71
     */
72
    /**
73
     * ASN1 Integer.
74
     */
75
    const ASN1_INTEGER = 2;
76
    /**
77
     * ASN1 Bit String.
78
     */
79
    const ASN1_BITSTRING = 3;
80
    /**
81
     * ASN1 Octet String.
82
     */
83
    const ASN1_OCTETSTRING = 4;
84
    /**
85
     * ASN1 Object Identifier.
86
     */
87
    const ASN1_OBJECT = 6;
88
    /**
89
     * ASN1 Sequence (with the constucted bit set).
90
     */
91
    const ASN1_SEQUENCE = 48;
92
    /**#@-*/
93
94
    /**#@+
95
     * @see \phpseclib\Crypt\RSA::__construct()
96
     */
97
    /**
98
     * To use the pure-PHP implementation.
99
     */
100
    const MODE_INTERNAL = 1;
101
    /**
102
     * To use the OpenSSL library.
103
     *
104
     * (if enabled; otherwise, the internal implementation will be used)
105
     */
106
    const MODE_OPENSSL = 2;
107
    /**#@-*/
108
109
    /**#@+
110
     * @see \phpseclib\Crypt\RSA::createKey()
111
     * @see \phpseclib\Crypt\RSA::setPrivateKeyFormat()
112
     */
113
    /**
114
     * PKCS#1 formatted private key.
115
     *
116
     * Used by OpenSSH
117
     */
118
    const PRIVATE_FORMAT_PKCS1 = 0;
119
    /**
120
     * PuTTY formatted private key.
121
     */
122
    const PRIVATE_FORMAT_PUTTY = 1;
123
    /**
124
     * XML formatted private key.
125
     */
126
    const PRIVATE_FORMAT_XML = 2;
127
    /**
128
     * PKCS#8 formatted private key.
129
     */
130
    const PRIVATE_FORMAT_PKCS8 = 8;
131
    /**#@-*/
132
133
    /**#@+
134
     * @see \phpseclib\Crypt\RSA::createKey()
135
     * @see \phpseclib\Crypt\RSA::setPublicKeyFormat()
136
     */
137
    /**
138
     * Raw public key.
139
     *
140
     * An array containing two \Jose\Util\BigInteger objects.
141
     *
142
     * The exponent can be indexed with any of the following:
143
     *
144
     * 0, e, exponent, publicExponent
145
     *
146
     * The modulus can be indexed with any of the following:
147
     *
148
     * 1, n, modulo, modulus
149
     */
150
    const PUBLIC_FORMAT_RAW = 3;
151
    /**
152
     * PKCS#1 formatted public key (raw).
153
     *
154
     * Used by File/X509.php
155
     *
156
     * Has the following header:
157
     *
158
     * -----BEGIN RSA PUBLIC KEY-----
159
     *
160
     * Analogous to ssh-keygen's pem format (as specified by -m)
161
     */
162
    const PUBLIC_FORMAT_PKCS1 = 4;
163
    const PUBLIC_FORMAT_PKCS1_RAW = 4;
164
    /**
165
     * XML formatted public key.
166
     */
167
    const PUBLIC_FORMAT_XML = 5;
168
    /**
169
     * OpenSSH formatted public key.
170
     *
171
     * Place in $HOME/.ssh/authorized_keys
172
     */
173
    const PUBLIC_FORMAT_OPENSSH = 6;
174
    /**
175
     * PKCS#1 formatted public key (encapsulated).
176
     *
177
     * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
178
     *
179
     * Has the following header:
180
     *
181
     * -----BEGIN PUBLIC KEY-----
182
     *
183
     * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
184
     * is specific to private keys it's basically creating a DER-encoded wrapper
185
     * for keys. This just extends that same concept to public keys (much like ssh-keygen)
186
     */
187
    const PUBLIC_FORMAT_PKCS8 = 7;
188
    /**#@-*/
189
190
    /**
191
     * Precomputed Zero.
192
     *
193
     * @var array
194
     */
195
    private $zero;
196
197
    /**
198
     * Precomputed One.
199
     *
200
     * @var array
201
     */
202
    private $one;
203
204
    /**
205
     * Private Key Format.
206
     *
207
     * @var int
208
     */
209
    private $privateKeyFormat = self::PRIVATE_FORMAT_PKCS1;
210
211
    /**
212
     * Public Key Format.
213
     *
214
     * @var int
215
     */
216
    private $publicKeyFormat = self::PUBLIC_FORMAT_PKCS8;
217
218
    /**
219
     * Modulus (ie. n).
220
     *
221
     * @var \Jose\Util\BigInteger
222
     */
223
    private $modulus;
224
225
    /**
226
     * Modulus length.
227
     *
228
     * @var \Jose\Util\BigInteger
229
     */
230
    private $k;
231
232
    /**
233
     * Exponent (ie. e or d).
234
     *
235
     * @var \Jose\Util\BigInteger
236
     */
237
    private $exponent;
238
239
    /**
240
     * Primes for Chinese Remainder Theorem (ie. p and q).
241
     *
242
     * @var array
243
     */
244
    private $primes;
245
246
    /**
247
     * Exponents for Chinese Remainder Theorem (ie. dP and dQ).
248
     *
249
     * @var array
250
     */
251
    private $exponents;
252
253
    /**
254
     * Coefficients for Chinese Remainder Theorem (ie. qInv).
255
     *
256
     * @var array
257
     */
258
    private $coefficients;
259
260
    /**
261
     * Hash name.
262
     *
263
     * @var string
264
     */
265
    private $hashName;
266
267
    /**
268
     * Hash function.
269
     *
270
     * @var \Jose\Util\Hash
271
     */
272
    private $hash;
273
274
    /**
275
     * Length of hash function output.
276
     *
277
     * @var int
278
     */
279
    private $hLen;
280
281
    /**
282
     * Length of salt.
283
     *
284
     * @var int
285
     */
286
    private $sLen;
287
288
    /**
289
     * Hash function for the Mask Generation Function.
290
     *
291
     * @var \Jose\Util\Hash
292
     */
293
    private $mgfHash;
294
295
    /**
296
     * Length of MGF hash function output.
297
     *
298
     * @var int
299
     */
300
    private $mgfHLen;
301
302
    /**
303
     * Encryption mode.
304
     *
305
     * @var int
306
     */
307
    private $encryptionMode = self::ENCRYPTION_OAEP;
308
309
    /**
310
     * Signature mode.
311
     *
312
     * @var int
313
     */
314
    private $signatureMode = self::SIGNATURE_PSS;
315
316
    /**
317
     * Public Exponent.
318
     *
319
     * @var mixed
320
     */
321
    private $publicExponent = false;
322
323
    /**
324
     * Password.
325
     *
326
     * @var string
327
     */
328
    private $password = false;
329
330
    /**
331
     * Components.
332
     *
333
     * For use with parsing XML formatted keys.  PHP's XML Parser functions use utilized - instead of PHP's DOM functions -
334
     * because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't.
335
     *
336
     * @see self::_start_element_handler()
337
     *
338
     * @var array
339
     */
340
    private $components = [];
341
342
    /**
343
     * Current String.
344
     *
345
     * For use with parsing XML formatted keys.
346
     *
347
     * @see self::_character_handler()
348
     * @see self::_stop_element_handler()
349
     *
350
     * @var mixed
351
     */
352
    private $current;
353
354
    /**
355
     * OpenSSL configuration file name.
356
     *
357
     * Set to null to use system configuration file.
358
     *
359
     * @see self::createKey()
360
     *
361
     * @var mixed
362
     * @Access public
363
     */
364
    private $configFile;
365
366
    /**
367
     * Public key comment field.
368
     *
369
     * @var string
370
     */
371
    private $comment = 'phpseclib-generated-key';
372
373
    /**
374
     * The constructor.
375
     *
376
     * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself.  The reason
377
     * \phpseclib\Crypt\RSA doesn't do it is because OpenSSL doesn't fail gracefully.  openssl_pkey_new(), in particular, requires
378
     * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late.
379
     */
380
    public function __construct()
381
    {
382
        $this->configFile = dirname(__FILE__).'/../openssl.cnf';
383
384
        if (!defined('CRYPT_RSA_MODE')) {
385
            switch (true) {
386
                // Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular,
387
                // Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger
388
                // can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either.
389
                case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'):
390
                    define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
391
                    break;
392
                case extension_loaded('openssl') && file_exists($this->configFile):
393
                    // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
394
                    ob_start();
395
                    @phpinfo();
396
                    $content = ob_get_contents();
397
                    ob_end_clean();
398
399
                    preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
400
401
                    $versions = [];
402
                    if (!empty($matches[1])) {
403
                        for ($i = 0; $i < count($matches[1]); $i++) {
404
                            $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
405
406
                            // Remove letter part in OpenSSL version
407
                            if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
408
                                $versions[$matches[1][$i]] = $fullVersion;
409
                            } else {
410
                                $versions[$matches[1][$i]] = $m[0];
411
                            }
412
                        }
413
                    }
414
415
                    // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
416
                    switch (true) {
417
                        case !isset($versions['Header']):
418
                        case !isset($versions['Library']):
419
                        case $versions['Header'] == $versions['Library']:
420
                            define('CRYPT_RSA_MODE', self::MODE_OPENSSL);
421
                            break;
422
                        default:
423
                            define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
424
                            define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
425
                    }
426
                    break;
427
                default:
428
                    define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
429
            }
430
        }
431
432
        $this->zero = new BigInteger();
433
        $this->one = new BigInteger(1);
434
435
        $this->hash = new Hash('sha1');
436
        $this->hLen = 20;
437
        $this->hashName = 'sha1';
438
        $this->mgfHash = new Hash('sha1');
439
        $this->mgfHLen = 20;
440
    }
441
442
    /**
443
     * Break a public or private key down into its constituant components.
444
     *
445
     * @see self::_convertPublicKey()
446
     * @see self::_convertPrivateKey()
447
     *
448
     * @param string $key
449
     * @param int    $type
450
     *
451
     * @return array
452
     */
453
    private function _parseKey($key, $type)
454
    {
455
        if ($type != self::PUBLIC_FORMAT_RAW && !is_string($key)) {
456
            return false;
457
        }
458
459
        switch ($type) {
460
            case self::PUBLIC_FORMAT_RAW:
461
                if (!is_array($key)) {
462
                    return false;
463
                }
464
                $components = [];
465
                switch (true) {
466
                    case isset($key['e']):
467
                        $components['publicExponent'] = $key['e']->copy();
468
                        break;
469
                    case isset($key['exponent']):
470
                        $components['publicExponent'] = $key['exponent']->copy();
471
                        break;
472
                    case isset($key['publicExponent']):
473
                        $components['publicExponent'] = $key['publicExponent']->copy();
474
                        break;
475
                    case isset($key[0]):
476
                        $components['publicExponent'] = $key[0]->copy();
477
                }
478
                switch (true) {
479
                    case isset($key['n']):
480
                        $components['modulus'] = $key['n']->copy();
481
                        break;
482
                    case isset($key['modulo']):
483
                        $components['modulus'] = $key['modulo']->copy();
484
                        break;
485
                    case isset($key['modulus']):
486
                        $components['modulus'] = $key['modulus']->copy();
487
                        break;
488
                    case isset($key[1]):
489
                        $components['modulus'] = $key[1]->copy();
490
                }
491
492
                return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
493
            case self::PRIVATE_FORMAT_PKCS1:
494
            case self::PRIVATE_FORMAT_PKCS8:
495
            case self::PUBLIC_FORMAT_PKCS1:
496
                /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
497
                   "outside the scope" of PKCS#1.  PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
498
                   protect private keys, however, that's not what OpenSSL* does.  OpenSSL protects private keys by adding
499
                   two new "fields" to the key - DEK-Info and Proc-Type.  These fields are discussed here:
500
501
                   http://tools.ietf.org/html/rfc1421#section-4.6.1.1
502
                   http://tools.ietf.org/html/rfc1421#section-4.6.1.3
503
504
                   DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
505
                   DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
506
                   function.  As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
507
                   own implementation.  ie. the implementation *is* the standard and any bugs that may exist in that
508
                   implementation are part of the standard, as well.
509
510
                   * OpenSSL is the de facto standard.  It's utilized by OpenSSH and other projects */
511
                if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
512
                    $iv = pack('H*', trim($matches[2]));
513
                    $symkey = pack('H*', md5($this->password.substr($iv, 0, 8))); // symkey is short for symmetric key
514
                    $symkey .= pack('H*', md5($symkey.$this->password.substr($iv, 0, 8)));
515
                    // remove the Proc-Type / DEK-Info sections as they're no longer needed
516
                    $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
517
                    $ciphertext = $this->_extractBER($key);
518
                    if ($ciphertext === false) {
519
                        $ciphertext = $key;
520
                    }
521
                    switch ($matches[1]) {
522
                        case 'AES-256-CBC':
523
                            $crypto = new AES();
524
                            break;
525
                        case 'AES-128-CBC':
526
                            $symkey = substr($symkey, 0, 16);
527
                            $crypto = new AES();
528
                            break;
529
                        case 'DES-EDE3-CFB':
530
                            $crypto = new TripleDES(Base::MODE_CFB);
531
                            break;
532
                        case 'DES-EDE3-CBC':
533
                            $symkey = substr($symkey, 0, 24);
534
                            $crypto = new TripleDES();
535
                            break;
536
                        case 'DES-CBC':
537
                            $crypto = new DES();
538
                            break;
539
                        default:
540
                            return false;
541
                    }
542
                    $crypto->setKey($symkey);
543
                    $crypto->setIV($iv);
544
                    $decoded = $crypto->decrypt($ciphertext);
545
                } else {
546
                    $decoded = $this->_extractBER($key);
547
                }
548
549
                if ($decoded !== false) {
550
                    $key = $decoded;
551
                }
552
553
                $components = [];
554
555
                if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
556
                    return false;
557
                }
558
                if ($this->_decodeLength($key) != strlen($key)) {
559
                    return false;
560
                }
561
562
                $tag = ord($this->_string_shift($key));
563
                /* intended for keys for which OpenSSL's asn1parse returns the following:
564
565
                    0:d=0  hl=4 l= 631 cons: SEQUENCE
566
                    4:d=1  hl=2 l=   1 prim:  INTEGER           :00
567
                    7:d=1  hl=2 l=  13 cons:  SEQUENCE
568
                    9:d=2  hl=2 l=   9 prim:   OBJECT            :rsaEncryption
569
                   20:d=2  hl=2 l=   0 prim:   NULL
570
                   22:d=1  hl=4 l= 609 prim:  OCTET STRING
571
572
                   ie. PKCS8 keys*/
573
574
                if ($tag == self::ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
575
                    $this->_string_shift($key, 3);
576
                    $tag = self::ASN1_SEQUENCE;
577
                }
578
579
                if ($tag == self::ASN1_SEQUENCE) {
580
                    $temp = $this->_string_shift($key, $this->_decodeLength($key));
581
                    if (ord($this->_string_shift($temp)) != self::ASN1_OBJECT) {
582
                        return false;
583
                    }
584
                    $length = $this->_decodeLength($temp);
585
                    switch ($this->_string_shift($temp, $length)) {
586
                        case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption
587
                            break;
588
                        case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC
589
                            /*
590
                               PBEParameter ::= SEQUENCE {
591
                                   salt OCTET STRING (SIZE(8)),
592
                                   iterationCount INTEGER }
593
                            */
594
                            if (ord($this->_string_shift($temp)) != self::ASN1_SEQUENCE) {
595
                                return false;
596
                            }
597
                            if ($this->_decodeLength($temp) != strlen($temp)) {
598
                                return false;
599
                            }
600
                            $this->_string_shift($temp); // assume it's an octet string
601
                            $salt = $this->_string_shift($temp, $this->_decodeLength($temp));
602
                            if (ord($this->_string_shift($temp)) != self::ASN1_INTEGER) {
603
                                return false;
604
                            }
605
                            $this->_decodeLength($temp);
606
                            list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
607
                            $this->_string_shift($key); // assume it's an octet string
608
                            $length = $this->_decodeLength($key);
609
                            if (strlen($key) != $length) {
610
                                return false;
611
                            }
612
613
                            $crypto = new DES();
614
                            $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
615
                            $key = $crypto->decrypt($key);
616
                            if ($key === false) {
617
                                return false;
618
                            }
619
620
                            return $this->_parseKey($key, self::PRIVATE_FORMAT_PKCS1);
621
                        default:
622
                            return false;
623
                    }
624
                    /* intended for keys for which OpenSSL's asn1parse returns the following:
625
626
                        0:d=0  hl=4 l= 290 cons: SEQUENCE
627
                        4:d=1  hl=2 l=  13 cons:  SEQUENCE
628
                        6:d=2  hl=2 l=   9 prim:   OBJECT            :rsaEncryption
629
                       17:d=2  hl=2 l=   0 prim:   NULL
630
                       19:d=1  hl=4 l= 271 prim:  BIT STRING */
631
                    $tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
632
                    $this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
633
                    // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
634
                    //  unused bits in the final subsequent octet. The number shall be in the range zero to seven."
635
                    //  -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
636
                    if ($tag == self::ASN1_BITSTRING) {
637
                        $this->_string_shift($key);
638
                    }
639
                    if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
640
                        return false;
641
                    }
642
                    if ($this->_decodeLength($key) != strlen($key)) {
643
                        return false;
644
                    }
645
                    $tag = ord($this->_string_shift($key));
646
                }
647
                if ($tag != self::ASN1_INTEGER) {
648
                    return false;
649
                }
650
651
                $length = $this->_decodeLength($key);
652
                $temp = $this->_string_shift($key, $length);
653
                if (strlen($temp) != 1 || ord($temp) > 2) {
654
                    $components['modulus'] = new BigInteger($temp, 256);
655
                    $this->_string_shift($key); // skip over self::ASN1_INTEGER
656
                    $length = $this->_decodeLength($key);
657
                    $components[$type == self::PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new BigInteger($this->_string_shift($key, $length), 256);
658
659
                    return $components;
660
                }
661
                if (ord($this->_string_shift($key)) != self::ASN1_INTEGER) {
662
                    return false;
663
                }
664
                $length = $this->_decodeLength($key);
665
                $components['modulus'] = new BigInteger($this->_string_shift($key, $length), 256);
666
                $this->_string_shift($key);
667
                $length = $this->_decodeLength($key);
668
                $components['publicExponent'] = new BigInteger($this->_string_shift($key, $length), 256);
669
                $this->_string_shift($key);
670
                $length = $this->_decodeLength($key);
671
                $components['privateExponent'] = new BigInteger($this->_string_shift($key, $length), 256);
672
                $this->_string_shift($key);
673
                $length = $this->_decodeLength($key);
674
                $components['primes'] = [1 => new BigInteger($this->_string_shift($key, $length), 256)];
675
                $this->_string_shift($key);
676
                $length = $this->_decodeLength($key);
677
                $components['primes'][] = new BigInteger($this->_string_shift($key, $length), 256);
678
                $this->_string_shift($key);
679
                $length = $this->_decodeLength($key);
680
                $components['exponents'] = [1 => new BigInteger($this->_string_shift($key, $length), 256)];
681
                $this->_string_shift($key);
682
                $length = $this->_decodeLength($key);
683
                $components['exponents'][] = new BigInteger($this->_string_shift($key, $length), 256);
684
                $this->_string_shift($key);
685
                $length = $this->_decodeLength($key);
686
                $components['coefficients'] = [2 => new BigInteger($this->_string_shift($key, $length), 256)];
687
688
                if (!empty($key)) {
689
                    if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
690
                        return false;
691
                    }
692
                    $this->_decodeLength($key);
693
                    while (!empty($key)) {
694
                        if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
695
                            return false;
696
                        }
697
                        $this->_decodeLength($key);
698
                        $key = substr($key, 1);
699
                        $length = $this->_decodeLength($key);
700
                        $components['primes'][] = new BigInteger($this->_string_shift($key, $length), 256);
701
                        $this->_string_shift($key);
702
                        $length = $this->_decodeLength($key);
703
                        $components['exponents'][] = new BigInteger($this->_string_shift($key, $length), 256);
704
                        $this->_string_shift($key);
705
                        $length = $this->_decodeLength($key);
706
                        $components['coefficients'][] = new BigInteger($this->_string_shift($key, $length), 256);
707
                    }
708
                }
709
710
                return $components;
711
            case self::PUBLIC_FORMAT_OPENSSH:
712
                $parts = explode(' ', $key, 3);
713
714
                $key = isset($parts[1]) ? base64_decode($parts[1]) : false;
715
                if ($key === false) {
716
                    return false;
717
                }
718
719
                $comment = isset($parts[2]) ? $parts[2] : false;
720
721
                $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
722
723
                if (strlen($key) <= 4) {
724
                    return false;
725
                }
726
                extract(unpack('Nlength', $this->_string_shift($key, 4)));
727
                $publicExponent = new BigInteger($this->_string_shift($key, $length), -256);
728
                if (strlen($key) <= 4) {
729
                    return false;
730
                }
731
                extract(unpack('Nlength', $this->_string_shift($key, 4)));
732
                $modulus = new BigInteger($this->_string_shift($key, $length), -256);
733
734
                if ($cleanup && strlen($key)) {
735
                    if (strlen($key) <= 4) {
736
                        return false;
737
                    }
738
                    extract(unpack('Nlength', $this->_string_shift($key, 4)));
739
                    $realModulus = new BigInteger($this->_string_shift($key, $length), -256);
740
741
                    return strlen($key) ? false : [
742
                        'modulus'        => $realModulus,
743
                        'publicExponent' => $modulus,
744
                        'comment'        => $comment,
745
                    ];
746
                } else {
747
                    return strlen($key) ? false : [
748
                        'modulus'        => $modulus,
749
                        'publicExponent' => $publicExponent,
750
                        'comment'        => $comment,
751
                    ];
752
                }
753
            // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
754
            // http://en.wikipedia.org/wiki/XML_Signature
755
            case self::PRIVATE_FORMAT_XML:
756
            case self::PUBLIC_FORMAT_XML:
757
                $this->components = [];
758
759
                $xml = xml_parser_create('UTF-8');
760
                xml_set_object($xml, $this);
761
                xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
762
                xml_set_character_data_handler($xml, '_data_handler');
763
                // add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
764
                if (!xml_parse($xml, '<xml>'.$key.'</xml>')) {
765
                    return false;
766
                }
767
768
                return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
769
            // from PuTTY's SSHPUBK.C
770
            case self::PRIVATE_FORMAT_PUTTY:
771
                $components = [];
772
                $key = preg_split('#\r\n|\r|\n#', $key);
773
                $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
774
                if ($type != 'ssh-rsa') {
775
                    return false;
776
                }
777
                $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
778
                $comment = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
779
780
                $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
781
                $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
782
                $public = substr($public, 11);
783
                extract(unpack('Nlength', $this->_string_shift($public, 4)));
784
                $components['publicExponent'] = new BigInteger($this->_string_shift($public, $length), -256);
785
                extract(unpack('Nlength', $this->_string_shift($public, 4)));
786
                $components['modulus'] = new BigInteger($this->_string_shift($public, $length), -256);
787
788
                $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
789
                $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
790
791
                switch ($encryption) {
792
                    case 'aes256-cbc':
793
                        $symkey = '';
794
                        $sequence = 0;
795
                        while (strlen($symkey) < 32) {
796
                            $temp = pack('Na*', $sequence++, $this->password);
797
                            $symkey .= pack('H*', sha1($temp));
798
                        }
799
                        $symkey = substr($symkey, 0, 32);
800
                        $crypto = new AES();
801
                }
802
803
                if ($encryption != 'none') {
804
                    $crypto->setKey($symkey);
805
                    $crypto->disablePadding();
806
                    $private = $crypto->decrypt($private);
807
                    if ($private === false) {
808
                        return false;
809
                    }
810
                }
811
812
                extract(unpack('Nlength', $this->_string_shift($private, 4)));
813
                if (strlen($private) < $length) {
814
                    return false;
815
                }
816
                $components['privateExponent'] = new BigInteger($this->_string_shift($private, $length), -256);
817
                extract(unpack('Nlength', $this->_string_shift($private, 4)));
818
                if (strlen($private) < $length) {
819
                    return false;
820
                }
821
                $components['primes'] = [1 => new BigInteger($this->_string_shift($private, $length), -256)];
822
                extract(unpack('Nlength', $this->_string_shift($private, 4)));
823
                if (strlen($private) < $length) {
824
                    return false;
825
                }
826
                $components['primes'][] = new BigInteger($this->_string_shift($private, $length), -256);
827
828
                $temp = $components['primes'][1]->subtract($this->one);
829
                $components['exponents'] = [1 => $components['publicExponent']->modInverse($temp)];
830
                $temp = $components['primes'][2]->subtract($this->one);
831
                $components['exponents'][] = $components['publicExponent']->modInverse($temp);
832
833
                extract(unpack('Nlength', $this->_string_shift($private, 4)));
834
                if (strlen($private) < $length) {
835
                    return false;
836
                }
837
                $components['coefficients'] = [2 => new BigInteger($this->_string_shift($private, $length), -256)];
838
839
                return $components;
840
        }
841
    }
842
843
    /**
844
     * Start Element Handler.
845
     *
846
     * Called by xml_set_element_handler()
847
     *
848
     * @param resource $parser
849
     * @param string   $name
850
     * @param array    $attribs
851
     */
852
    private function _start_element_handler($parser, $name, $attribs)
853
    {
854
        //$name = strtoupper($name);
855
        switch ($name) {
856
            case 'MODULUS':
857
                $this->current = &$this->components['modulus'];
858
                break;
859
            case 'EXPONENT':
860
                $this->current = &$this->components['publicExponent'];
861
                break;
862
            case 'P':
863
                $this->current = &$this->components['primes'][1];
864
                break;
865
            case 'Q':
866
                $this->current = &$this->components['primes'][2];
867
                break;
868
            case 'DP':
869
                $this->current = &$this->components['exponents'][1];
870
                break;
871
            case 'DQ':
872
                $this->current = &$this->components['exponents'][2];
873
                break;
874
            case 'INVERSEQ':
875
                $this->current = &$this->components['coefficients'][2];
876
                break;
877
            case 'D':
878
                $this->current = &$this->components['privateExponent'];
879
        }
880
        $this->current = '';
881
    }
882
883
    /**
884
     * Stop Element Handler.
885
     *
886
     * Called by xml_set_element_handler()
887
     *
888
     * @param resource $parser
889
     * @param string   $name
890
     */
891
    private function _stop_element_handler($parser, $name)
892
    {
893
        if (isset($this->current)) {
894
            $this->current = new BigInteger(base64_decode($this->current), 256);
895
            unset($this->current);
896
        }
897
    }
898
899
    /**
900
     * Data Handler.
901
     *
902
     * Called by xml_set_character_data_handler()
903
     *
904
     * @param resource $parser
905
     * @param string   $data
906
     */
907
    public function _data_handler($parser, $data)
908
    {
909
        if (!isset($this->current) || is_object($this->current)) {
910
            return;
911
        }
912
        $this->current .= trim($data);
913
    }
914
915
    /**
916
     * Loads a public or private key.
917
     *
918
     * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
919
     *
920
     * @param string $key
921
     * @param int    $type optional
922
     */
923
    public function loadKey($key, $type = false)
924
    {
925
        if ($key instanceof self) {
926
            $this->privateKeyFormat = $key->privateKeyFormat;
927
            $this->publicKeyFormat = $key->publicKeyFormat;
928
            $this->k = $key->k;
929
            $this->hLen = $key->hLen;
930
            $this->sLen = $key->sLen;
931
            $this->mgfHLen = $key->mgfHLen;
932
            $this->encryptionMode = $key->encryptionMode;
933
            $this->signatureMode = $key->signatureMode;
934
            $this->password = $key->password;
935
            $this->configFile = $key->configFile;
936
            $this->comment = $key->comment;
937
938
            if (is_object($key->hash)) {
939
                $this->hash = new Hash($key->hash->getHash());
940
            }
941
            if (is_object($key->mgfHash)) {
942
                $this->mgfHash = new Hash($key->mgfHash->getHash());
943
            }
944
945
            if (is_object($key->modulus)) {
946
                $this->modulus = $key->modulus->copy();
947
            }
948
            if (is_object($key->exponent)) {
949
                $this->exponent = $key->exponent->copy();
950
            }
951
            if (is_object($key->publicExponent)) {
952
                $this->publicExponent = $key->publicExponent->copy();
953
            }
954
955
            $this->primes = [];
956
            $this->exponents = [];
957
            $this->coefficients = [];
958
959
            foreach ($this->primes as $prime) {
960
                $this->primes[] = $prime->copy();
961
            }
962
            foreach ($this->exponents as $exponent) {
963
                $this->exponents[] = $exponent->copy();
964
            }
965
            foreach ($this->coefficients as $coefficient) {
966
                $this->coefficients[] = $coefficient->copy();
967
            }
968
969
            return true;
970
        }
971
972
        if ($type === false) {
973
            $types = [
974
                self::PUBLIC_FORMAT_RAW,
975
                self::PRIVATE_FORMAT_PKCS1,
976
                self::PRIVATE_FORMAT_XML,
977
                self::PRIVATE_FORMAT_PUTTY,
978
                self::PUBLIC_FORMAT_OPENSSH,
979
            ];
980
            foreach ($types as $type) {
981
                $components = $this->_parseKey($key, $type);
982
                if ($components !== false) {
983
                    break;
984
                }
985
            }
986
        } else {
987
            $components = $this->_parseKey($key, $type);
988
        }
989
990
        if ($components === false) {
991
            return false;
992
        }
993
994
        if (isset($components['comment']) && $components['comment'] !== false) {
995
            $this->comment = $components['comment'];
996
        }
997
        $this->modulus = $components['modulus'];
998
        $this->k = strlen($this->modulus->toBytes());
999
        $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
1000
        if (isset($components['primes'])) {
1001
            $this->primes = $components['primes'];
1002
            $this->exponents = $components['exponents'];
1003
            $this->coefficients = $components['coefficients'];
1004
            $this->publicExponent = $components['publicExponent'];
1005
        } else {
1006
            $this->primes = [];
1007
            $this->exponents = [];
1008
            $this->coefficients = [];
1009
            $this->publicExponent = false;
1010
        }
1011
1012
        switch ($type) {
1013
            case self::PUBLIC_FORMAT_OPENSSH:
1014
            case self::PUBLIC_FORMAT_RAW:
1015
                $this->setPublicKey();
1016
                break;
1017
            case self::PRIVATE_FORMAT_PKCS1:
1018
                switch (true) {
1019
                    case strpos($key, '-BEGIN PUBLIC KEY-') !== false:
1020
                    case strpos($key, '-BEGIN RSA PUBLIC KEY-') !== false:
1021
                        $this->setPublicKey();
1022
                }
1023
        }
1024
1025
        return true;
1026
    }
1027
1028
    /**
1029
     * DER-decode the length.
1030
     *
1031
     * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4.  See
1032
     * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
1033
     *
1034
     * @param string $string
1035
     *
1036
     * @return int
1037
     */
1038
    private function _decodeLength(&$string)
1039
    {
1040
        $length = ord($this->_string_shift($string));
1041
        if ($length & 0x80) { // definite length, long form
1042
            $length &= 0x7F;
1043
            $temp = $this->_string_shift($string, $length);
1044
            list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
1045
        }
1046
1047
        return $length;
1048
    }
1049
1050
    /**
1051
     * String Shift.
1052
     *
1053
     * Inspired by array_shift
1054
     *
1055
     * @param string $string
1056
     * @param int    $index
1057
     *
1058
     * @return string
1059
     */
1060
    private function _string_shift(&$string, $index = 1)
1061
    {
1062
        $substr = substr($string, 0, $index);
1063
        $string = substr($string, $index);
1064
1065
        return $substr;
1066
    }
1067
1068
    /**
1069
     * Determines which hashing function should be used.
1070
     *
1071
     * Used with signature production / verification and (if the encryption mode is self::ENCRYPTION_OAEP) encryption and
1072
     * decryption.  If $hash isn't supported, sha1 is used.
1073
     *
1074
     * @param string $hash
1075
     */
1076
    public function setHash($hash)
1077
    {
1078
        switch ($hash) {
1079
            case 'sha1':
1080
                $this->hLen = 20;
1081
                break;
1082
            case 'sha256':
1083
                $this->hLen = 32;
1084
                break;
1085
            case 'sha384':
1086
                $this->hLen = 48;
1087
                break;
1088
            case 'sha512':
1089
                $this->hLen = 64;
1090
                break;
1091
            default:
1092
                throw new \InvalidArgumentException('Unsupported hash algorithm.');
1093
        }
1094
        $this->hash = new Hash($hash);
1095
    }
1096
1097
    /**
1098
     * Determines which hashing function should be used for the mask generation function.
1099
     *
1100
     * The mask generation function is used by self::ENCRYPTION_OAEP and self::SIGNATURE_PSS and although it's
1101
     * best if Hash and MGFHash are set to the same thing this is not a requirement.
1102
     *
1103
     * @param string $hash
1104
     */
1105
    public function setMGFHash($hash)
1106
    {
1107
        switch ($hash) {
1108
            case 'sha1':
1109
                $this->mgfHLen = 20;
1110
                break;
1111
            case 'sha256':
1112
                $this->mgfHash = 32;
1113
                break;
1114
            case 'sha384':
1115
                $this->mgfHash = 48;
1116
                break;
1117
            case 'sha512':
1118
                $this->mgfHash = 64;
1119
                break;
1120
            default:
1121
                throw new \InvalidArgumentException('Unsupported hash algorithm.');
1122
        }
1123
        $this->mgfHash = new Hash($hash);
1124
    }
1125
1126
    /**
1127
     * Determines the salt length.
1128
     *
1129
     * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
1130
     *
1131
     *    Typical salt lengths in octets are hLen (the length of the output
1132
     *    of the hash function Hash) and 0.
1133
     *
1134
     * @param int $format
1135
     */
1136
    public function setSaltLength($sLen)
1137
    {
1138
        $this->sLen = $sLen;
1139
    }
1140
1141
    /**
1142
     * Integer-to-Octet-String primitive.
1143
     *
1144
     * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
1145
     *
1146
     * @param \Jose\Util\BigInteger $x
1147
     * @param int                   $xLen
1148
     *
1149
     * @return string
1150
     */
1151
    private function _i2osp($x, $xLen)
1152
    {
1153
        $x = $x->toBytes();
1154
        if (strlen($x) > $xLen) {
1155
            user_error('Integer too large');
1156
1157
            return false;
1158
        }
1159
1160
        return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
1161
    }
1162
1163
    /**
1164
     * Octet-String-to-Integer primitive.
1165
     *
1166
     * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
1167
     *
1168
     * @param string $x
1169
     *
1170
     * @return \Jose\Util\BigInteger
1171
     */
1172
    private function _os2ip($x)
1173
    {
1174
        return new BigInteger($x, 256);
1175
    }
1176
1177
    /**
1178
     * Exponentiate with or without Chinese Remainder Theorem.
1179
     *
1180
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
1181
     *
1182
     * @param \Jose\Util\BigInteger $x
1183
     *
1184
     * @return \Jose\Util\BigInteger
1185
     */
1186
    private function _exponentiate($x)
1187
    {
1188
        if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) {
1189
            return $x->modPow($this->exponent, $this->modulus);
1190
        }
1191
1192
        $num_primes = count($this->primes);
1193
1194
        if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
1195
            $m_i = [
1196
                1 => $x->modPow($this->exponents[1], $this->primes[1]),
1197
                2 => $x->modPow($this->exponents[2], $this->primes[2]),
1198
            ];
1199
            $h = $m_i[1]->subtract($m_i[2]);
1200
            $h = $h->multiply($this->coefficients[2]);
1201
            list(, $h) = $h->divide($this->primes[1]);
1202
            $m = $m_i[2]->add($h->multiply($this->primes[2]));
1203
1204
            $r = $this->primes[1];
1205
            for ($i = 3; $i <= $num_primes; $i++) {
1206
                $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
1207
1208
                $r = $r->multiply($this->primes[$i - 1]);
1209
1210
                $h = $m_i->subtract($m);
1211
                $h = $h->multiply($this->coefficients[$i]);
1212
                list(, $h) = $h->divide($this->primes[$i]);
1213
1214
                $m = $m->add($r->multiply($h));
1215
            }
1216
        } else {
1217
            $smallest = $this->primes[1];
1218
            for ($i = 2; $i <= $num_primes; $i++) {
1219
                if ($smallest->compare($this->primes[$i]) > 0) {
1220
                    $smallest = $this->primes[$i];
1221
                }
1222
            }
1223
1224
            $one = new BigInteger(1);
1225
1226
            $r = $one->random($one, $smallest->subtract($one));
1227
1228
            $m_i = [
1229
                1 => $this->_blind($x, $r, 1),
1230
                2 => $this->_blind($x, $r, 2),
1231
            ];
1232
            $h = $m_i[1]->subtract($m_i[2]);
1233
            $h = $h->multiply($this->coefficients[2]);
1234
            list(, $h) = $h->divide($this->primes[1]);
1235
            $m = $m_i[2]->add($h->multiply($this->primes[2]));
1236
1237
            $r = $this->primes[1];
1238
            for ($i = 3; $i <= $num_primes; $i++) {
1239
                $m_i = $this->_blind($x, $r, $i);
1240
1241
                $r = $r->multiply($this->primes[$i - 1]);
1242
1243
                $h = $m_i->subtract($m);
1244
                $h = $h->multiply($this->coefficients[$i]);
1245
                list(, $h) = $h->divide($this->primes[$i]);
1246
1247
                $m = $m->add($r->multiply($h));
1248
            }
1249
        }
1250
1251
        return $m;
1252
    }
1253
1254
    /**
1255
     * Performs RSA Blinding.
1256
     *
1257
     * Protects against timing attacks by employing RSA Blinding.
1258
     * Returns $x->modPow($this->exponents[$i], $this->primes[$i])
1259
     *
1260
     * @param \Jose\Util\BigInteger $x
1261
     * @param \Jose\Util\BigInteger $r
1262
     * @param int                   $i
1263
     *
1264
     * @return \Jose\Util\BigInteger
1265
     */
1266
    private function _blind($x, $r, $i)
1267
    {
1268
        $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
1269
        $x = $x->modPow($this->exponents[$i], $this->primes[$i]);
1270
1271
        $r = $r->modInverse($this->primes[$i]);
1272
        $x = $x->multiply($r);
1273
        list(, $x) = $x->divide($this->primes[$i]);
1274
1275
        return $x;
1276
    }
1277
1278
    /**
1279
     * Performs blinded RSA equality testing.
1280
     *
1281
     * Protects against a particular type of timing attack described.
1282
     *
1283
     * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)}
1284
     *
1285
     * Thanks for the heads up singpolyma!
1286
     *
1287
     * @param string $x
1288
     * @param string $y
1289
     *
1290
     * @return bool
1291
     */
1292
    private function _equals($x, $y)
1293
    {
1294
        if (strlen($x) != strlen($y)) {
1295
            return false;
1296
        }
1297
1298
        $result = 0;
1299
        for ($i = 0; $i < strlen($x); $i++) {
1300
            $result |= ord($x[$i]) ^ ord($y[$i]);
1301
        }
1302
1303
        return $result == 0;
1304
    }
1305
1306
    /**
1307
     * RSAEP.
1308
     *
1309
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
1310
     *
1311
     * @param \Jose\Util\BigInteger $m
1312
     *
1313
     * @return \Jose\Util\BigInteger
1314
     */
1315
    private function _rsaep($m)
1316
    {
1317
        if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1318
            user_error('Message representative out of range');
1319
1320
            return false;
1321
        }
1322
1323
        return $this->_exponentiate($m);
1324
    }
1325
1326
    /**
1327
     * RSADP.
1328
     *
1329
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
1330
     *
1331
     * @param \Jose\Util\BigInteger $c
1332
     *
1333
     * @return \Jose\Util\BigInteger
1334
     */
1335
    private function _rsadp($c)
1336
    {
1337
        if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
1338
            user_error('Ciphertext representative out of range');
1339
1340
            return false;
1341
        }
1342
1343
        return $this->_exponentiate($c);
1344
    }
1345
1346
    /**
1347
     * RSASP1.
1348
     *
1349
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
1350
     *
1351
     * @param \Jose\Util\BigInteger $m
1352
     *
1353
     * @return \Jose\Util\BigInteger
1354
     */
1355
    private function _rsasp1($m)
1356
    {
1357
        if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1358
            user_error('Message representative out of range');
1359
1360
            return false;
1361
        }
1362
1363
        return $this->_exponentiate($m);
1364
    }
1365
1366
    /**
1367
     * RSAVP1.
1368
     *
1369
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
1370
     *
1371
     * @param \Jose\Util\BigInteger $s
1372
     *
1373
     * @return \Jose\Util\BigInteger
1374
     */
1375
    private function _rsavp1($s)
1376
    {
1377
        if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
1378
            user_error('Signature representative out of range');
1379
1380
            return false;
1381
        }
1382
1383
        return $this->_exponentiate($s);
1384
    }
1385
1386
    /**
1387
     * MGF1.
1388
     *
1389
     * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
1390
     *
1391
     * @param string $mgfSeed
1392
     * @param int    $mgfLen
1393
     *
1394
     * @return string
1395
     */
1396
    private function _mgf1($mgfSeed, $maskLen)
1397
    {
1398
        // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
1399
1400
        $t = '';
1401
        $count = ceil($maskLen / $this->mgfHLen);
1402
        for ($i = 0; $i < $count; $i++) {
1403
            $c = pack('N', $i);
1404
            $t .= $this->mgfHash->hash($mgfSeed.$c);
1405
        }
1406
1407
        return substr($t, 0, $maskLen);
1408
    }
1409
1410
    /**
1411
     * RSAES-OAEP-ENCRYPT.
1412
     *
1413
     * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and
1414
     * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}.
1415
     *
1416
     * @param string $m
1417
     * @param string $l
1418
     *
1419
     * @return string
1420
     */
1421
    private function _rsaes_oaep_encrypt($m, $l = '')
1422
    {
1423
        $mLen = strlen($m);
1424
1425
        // Length checking
1426
1427
        // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
1428
        // be output.
1429
1430
        if ($mLen > $this->k - 2 * $this->hLen - 2) {
1431
            user_error('Message too long');
1432
1433
            return false;
1434
        }
1435
1436
        // EME-OAEP encoding
1437
1438
        $lHash = $this->hash->hash($l);
1439
        $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
1440
        $db = $lHash.$ps.chr(1).$m;
1441
        $seed = random_bytes($this->hLen);
1442
        $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
1443
        $maskedDB = $db ^ $dbMask;
1444
        $seedMask = $this->_mgf1($maskedDB, $this->hLen);
1445
        $maskedSeed = $seed ^ $seedMask;
1446
        $em = chr(0).$maskedSeed.$maskedDB;
1447
1448
        // RSA encryption
1449
1450
        $m = $this->_os2ip($em);
1451
        $c = $this->_rsaep($m);
1452
        $c = $this->_i2osp($c, $this->k);
1453
1454
        // Output the ciphertext C
1455
1456
        return $c;
1457
    }
1458
1459
    /**
1460
     * RSAES-OAEP-DECRYPT.
1461
     *
1462
     * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}.  The fact that the error
1463
     * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
1464
     *
1465
     *    Note.  Care must be taken to ensure that an opponent cannot
1466
     *    distinguish the different error conditions in Step 3.g, whether by
1467
     *    error message or timing, or, more generally, learn partial
1468
     *    information about the encoded message EM.  Otherwise an opponent may
1469
     *    be able to obtain useful information about the decryption of the
1470
     *    ciphertext C, leading to a chosen-ciphertext attack such as the one
1471
     *    observed by Manger [36].
1472
     *
1473
     * As for $l...  to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
1474
     *
1475
     *    Both the encryption and the decryption operations of RSAES-OAEP take
1476
     *    the value of a label L as input.  In this version of PKCS #1, L is
1477
     *    the empty string; other uses of the label are outside the scope of
1478
     *    this document.
1479
     *
1480
     * @param string $c
1481
     * @param string $l
1482
     *
1483
     * @return string
1484
     */
1485
    private function _rsaes_oaep_decrypt($c, $l = '')
1486
    {
1487
        // Length checking
1488
1489
        // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
1490
        // be output.
1491
1492
        if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
1493
            user_error('Decryption error');
1494
1495
            return false;
1496
        }
1497
1498
        // RSA decryption
1499
1500
        $c = $this->_os2ip($c);
1501
        $m = $this->_rsadp($c);
1502
        if ($m === false) {
1503
            user_error('Decryption error');
1504
1505
            return false;
1506
        }
1507
        $em = $this->_i2osp($m, $this->k);
1508
1509
        // EME-OAEP decoding
1510
1511
        $lHash = $this->hash->hash($l);
1512
        $y = ord($em[0]);
1513
        $maskedSeed = substr($em, 1, $this->hLen);
1514
        $maskedDB = substr($em, $this->hLen + 1);
1515
        $seedMask = $this->_mgf1($maskedDB, $this->hLen);
1516
        $seed = $maskedSeed ^ $seedMask;
1517
        $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
1518
        $db = $maskedDB ^ $dbMask;
1519
        $lHash2 = substr($db, 0, $this->hLen);
1520
        $m = substr($db, $this->hLen);
1521
        if ($lHash != $lHash2) {
1522
            user_error('Decryption error');
1523
1524
            return false;
1525
        }
1526
        $m = ltrim($m, chr(0));
1527
        if (ord($m[0]) != 1) {
1528
            user_error('Decryption error');
1529
1530
            return false;
1531
        }
1532
1533
        // Output the message M
1534
1535
        return substr($m, 1);
1536
    }
1537
1538
    /**
1539
     * RSAES-PKCS1-V1_5-ENCRYPT.
1540
     *
1541
     * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
1542
     *
1543
     * @param string $m
1544
     *
1545
     * @return string
1546
     */
1547
    private function _rsaes_pkcs1_v1_5_encrypt($m)
1548
    {
1549
        $mLen = strlen($m);
1550
1551
        // Length checking
1552
1553
        if ($mLen > $this->k - 11) {
1554
            user_error('Message too long');
1555
1556
            return false;
1557
        }
1558
1559
        // EME-PKCS1-v1_5 encoding
1560
1561
        $psLen = $this->k - $mLen - 3;
1562
        $ps = '';
1563
        while (strlen($ps) != $psLen) {
1564
            $temp = random_bytes($psLen - strlen($ps));
1565
            $temp = str_replace("\x00", '', $temp);
1566
            $ps .= $temp;
1567
        }
1568
        $type = 2;
1569
        // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done
1570
        if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) {
1571
            $type = 1;
1572
            // "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF"
1573
            $ps = str_repeat("\xFF", $psLen);
1574
        }
1575
        $em = chr(0).chr($type).$ps.chr(0).$m;
1576
1577
        // RSA encryption
1578
        $m = $this->_os2ip($em);
1579
        $c = $this->_rsaep($m);
1580
        $c = $this->_i2osp($c, $this->k);
1581
1582
        // Output the ciphertext C
1583
1584
        return $c;
1585
    }
1586
1587
    /**
1588
     * RSAES-PKCS1-V1_5-DECRYPT.
1589
     *
1590
     * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
1591
     *
1592
     * For compatibility purposes, this function departs slightly from the description given in RFC3447.
1593
     * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
1594
     * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
1595
     * public key should have the second byte set to 2.  In RFC3447 (PKCS#1 v2.1), the second byte is supposed
1596
     * to be 2 regardless of which key is used.  For compatibility purposes, we'll just check to make sure the
1597
     * second byte is 2 or less.  If it is, we'll accept the decrypted string as valid.
1598
     *
1599
     * As a consequence of this, a private key encrypted ciphertext produced with \phpseclib\Crypt\RSA may not decrypt
1600
     * with a strictly PKCS#1 v1.5 compliant RSA implementation.  Public key encrypted ciphertext's should but
1601
     * not private key encrypted ciphertext's.
1602
     *
1603
     * @param string $c
1604
     *
1605
     * @return string
1606
     */
1607
    private function _rsaes_pkcs1_v1_5_decrypt($c)
1608
    {
1609
        // Length checking
1610
1611
        if (strlen($c) != $this->k) { // or if k < 11
1612
            user_error('Decryption error');
1613
1614
            return false;
1615
        }
1616
1617
        // RSA decryption
1618
1619
        $c = $this->_os2ip($c);
1620
        $m = $this->_rsadp($c);
1621
1622
        if ($m === false) {
1623
            user_error('Decryption error');
1624
1625
            return false;
1626
        }
1627
        $em = $this->_i2osp($m, $this->k);
1628
1629
        // EME-PKCS1-v1_5 decoding
1630
1631
        if (ord($em[0]) != 0 || ord($em[1]) > 2) {
1632
            user_error('Decryption error');
1633
1634
            return false;
1635
        }
1636
1637
        $ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
1638
        $m = substr($em, strlen($ps) + 3);
1639
1640
        if (strlen($ps) < 8) {
1641
            user_error('Decryption error');
1642
1643
            return false;
1644
        }
1645
1646
        // Output M
1647
1648
        return $m;
1649
    }
1650
1651
    /**
1652
     * EMSA-PSS-ENCODE.
1653
     *
1654
     * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
1655
     *
1656
     * @param string $m
1657
     * @param int    $emBits
1658
     */
1659
    private function _emsa_pss_encode($m, $emBits)
1660
    {
1661
        // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
1662
        // be output.
1663
1664
        $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
1665
        $sLen = $this->sLen ? $this->sLen : $this->hLen;
1666
1667
        $mHash = $this->hash->hash($m);
1668
        if ($emLen < $this->hLen + $sLen + 2) {
1669
            user_error('Encoding error');
1670
1671
            return false;
1672
        }
1673
1674
        $salt = random_bytes($sLen);
1675
        $m2 = "\0\0\0\0\0\0\0\0".$mHash.$salt;
1676
        $h = $this->hash->hash($m2);
1677
        $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
1678
        $db = $ps.chr(1).$salt;
1679
        $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
1680
        $maskedDB = $db ^ $dbMask;
1681
        $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
1682
        $em = $maskedDB.$h.chr(0xBC);
1683
1684
        return $em;
1685
    }
1686
1687
    /**
1688
     * EMSA-PSS-VERIFY.
1689
     *
1690
     * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
1691
     *
1692
     * @param string $m
1693
     * @param string $em
1694
     * @param int    $emBits
1695
     *
1696
     * @return string
1697
     */
1698
    private function _emsa_pss_verify($m, $em, $emBits)
1699
    {
1700
        // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
1701
        // be output.
1702
1703
        $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
1704
        $sLen = $this->sLen ? $this->sLen : $this->hLen;
1705
1706
        $mHash = $this->hash->hash($m);
1707
        if ($emLen < $this->hLen + $sLen + 2) {
1708
            return false;
1709
        }
1710
1711
        if ($em[strlen($em) - 1] != chr(0xBC)) {
1712
            return false;
1713
        }
1714
1715
        $maskedDB = substr($em, 0, -$this->hLen - 1);
1716
        $h = substr($em, -$this->hLen - 1, $this->hLen);
1717
        $temp = chr(0xFF << ($emBits & 7));
1718
        if ((~$maskedDB[0] & $temp) != $temp) {
1719
            return false;
1720
        }
1721
        $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
1722
        $db = $maskedDB ^ $dbMask;
1723
        $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
1724
        $temp = $emLen - $this->hLen - $sLen - 2;
1725
        if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
1726
            return false;
1727
        }
1728
        $salt = substr($db, $temp + 1); // should be $sLen long
1729
        $m2 = "\0\0\0\0\0\0\0\0".$mHash.$salt;
1730
        $h2 = $this->hash->hash($m2);
1731
1732
        return $this->_equals($h, $h2);
1733
    }
1734
1735
    /**
1736
     * RSASSA-PSS-SIGN.
1737
     *
1738
     * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
1739
     *
1740
     * @param string $m
1741
     *
1742
     * @return string
1743
     */
1744
    private function _rsassa_pss_sign($m)
1745
    {
1746
        // EMSA-PSS encoding
1747
1748
        $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);
1749
1750
        // RSA signature
1751
1752
        $m = $this->_os2ip($em);
1753
        $s = $this->_rsasp1($m);
1754
        $s = $this->_i2osp($s, $this->k);
1755
1756
        // Output the signature S
1757
1758
        return $s;
1759
    }
1760
1761
    /**
1762
     * RSASSA-PSS-VERIFY.
1763
     *
1764
     * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
1765
     *
1766
     * @param string $m
1767
     * @param string $s
1768
     *
1769
     * @return string
1770
     */
1771
    private function _rsassa_pss_verify($m, $s)
1772
    {
1773
        // Length checking
1774
1775
        if (strlen($s) != $this->k) {
1776
            user_error('Invalid signature');
1777
1778
            return false;
1779
        }
1780
1781
        // RSA verification
1782
1783
        $modBits = 8 * $this->k;
1784
1785
        $s2 = $this->_os2ip($s);
1786
        $m2 = $this->_rsavp1($s2);
1787
        if ($m2 === false) {
1788
            user_error('Invalid signature');
1789
1790
            return false;
1791
        }
1792
        $em = $this->_i2osp($m2, $modBits >> 3);
1793
        if ($em === false) {
1794
            user_error('Invalid signature');
1795
1796
            return false;
1797
        }
1798
1799
        // EMSA-PSS verification
1800
1801
        return $this->_emsa_pss_verify($m, $em, $modBits - 1);
1802
    }
1803
1804
    /**
1805
     * EMSA-PKCS1-V1_5-ENCODE.
1806
     *
1807
     * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
1808
     *
1809
     * @param string $m
1810
     * @param int    $emLen
1811
     *
1812
     * @return string
1813
     */
1814
    private function _emsa_pkcs1_v1_5_encode($m, $emLen)
1815
    {
1816
        $h = $this->hash->hash($m);
1817
        if ($h === false) {
1818
            return false;
1819
        }
1820
1821
        // see http://tools.ietf.org/html/rfc3447#page-43
1822
        switch ($this->hashName) {
1823
            case 'md2':
1824
                $t = pack('H*', '3020300c06082a864886f70d020205000410');
1825
                break;
1826
            case 'md5':
1827
                $t = pack('H*', '3020300c06082a864886f70d020505000410');
1828
                break;
1829
            case 'sha1':
1830
                $t = pack('H*', '3021300906052b0e03021a05000414');
1831
                break;
1832
            case 'sha256':
1833
                $t = pack('H*', '3031300d060960864801650304020105000420');
1834
                break;
1835
            case 'sha384':
1836
                $t = pack('H*', '3041300d060960864801650304020205000430');
1837
                break;
1838
            case 'sha512':
1839
                $t = pack('H*', '3051300d060960864801650304020305000440');
1840
        }
1841
        $t .= $h;
1842
        $tLen = strlen($t);
1843
1844
        if ($emLen < $tLen + 11) {
1845
            user_error('Intended encoded message length too short');
1846
1847
            return false;
1848
        }
1849
1850
        $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
1851
1852
        $em = "\0\1$ps\0$t";
1853
1854
        return $em;
1855
    }
1856
1857
    /**
1858
     * RSASSA-PKCS1-V1_5-SIGN.
1859
     *
1860
     * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
1861
     *
1862
     * @param string $m
1863
     *
1864
     * @return string
1865
     */
1866
    private function _rsassa_pkcs1_v1_5_sign($m)
1867
    {
1868
        // EMSA-PKCS1-v1_5 encoding
1869
1870
        $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
1871
        if ($em === false) {
1872
            user_error('RSA modulus too short');
1873
1874
            return false;
1875
        }
1876
1877
        // RSA signature
1878
1879
        $m = $this->_os2ip($em);
1880
        $s = $this->_rsasp1($m);
1881
        $s = $this->_i2osp($s, $this->k);
1882
1883
        // Output the signature S
1884
1885
        return $s;
1886
    }
1887
1888
    /**
1889
     * RSASSA-PKCS1-V1_5-VERIFY.
1890
     *
1891
     * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}.
1892
     *
1893
     * @param string $m
1894
     *
1895
     * @return string
1896
     */
1897
    private function _rsassa_pkcs1_v1_5_verify($m, $s)
1898
    {
1899
        // Length checking
1900
1901
        if (strlen($s) != $this->k) {
1902
            user_error('Invalid signature');
1903
1904
            return false;
1905
        }
1906
1907
        // RSA verification
1908
1909
        $s = $this->_os2ip($s);
1910
        $m2 = $this->_rsavp1($s);
1911
        if ($m2 === false) {
1912
            user_error('Invalid signature');
1913
1914
            return false;
1915
        }
1916
        $em = $this->_i2osp($m2, $this->k);
1917
        if ($em === false) {
1918
            user_error('Invalid signature');
1919
1920
            return false;
1921
        }
1922
1923
        // EMSA-PKCS1-v1_5 encoding
1924
1925
        $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
1926
        if ($em2 === false) {
1927
            user_error('RSA modulus too short');
1928
1929
            return false;
1930
        }
1931
1932
        // Compare
1933
        return $this->_equals($em, $em2);
1934
    }
1935
1936
    /**
1937
     * Set Encryption Mode.
1938
     *
1939
     * Valid values include self::ENCRYPTION_OAEP and self::ENCRYPTION_PKCS1.
1940
     *
1941
     * @param int $mode
1942
     */
1943
    public function setEncryptionMode($mode)
1944
    {
1945
        $this->encryptionMode = $mode;
1946
    }
1947
1948
    /**
1949
     * Set Signature Mode.
1950
     *
1951
     * Valid values include self::SIGNATURE_PSS and self::SIGNATURE_PKCS1
1952
     *
1953
     * @param int $mode
1954
     */
1955
    public function setSignatureMode($mode)
1956
    {
1957
        $this->signatureMode = $mode;
1958
    }
1959
1960
    /**
1961
     * Encryption.
1962
     *
1963
     * Both self::ENCRYPTION_OAEP and self::ENCRYPTION_PKCS1 both place limits on how long $plaintext can be.
1964
     * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
1965
     * be concatenated together.
1966
     *
1967
     * @see self::decrypt()
1968
     *
1969
     * @param string $plaintext
1970
     *
1971
     * @return string
1972
     */
1973
    public function encrypt($plaintext)
1974
    {
1975
        switch ($this->encryptionMode) {
1976
            case self::ENCRYPTION_PKCS1:
1977
                $length = $this->k - 11;
1978
                if ($length <= 0) {
1979
                    return false;
1980
                }
1981
1982
                $plaintext = str_split($plaintext, $length);
1983
                $ciphertext = '';
1984
                foreach ($plaintext as $m) {
1985
                    $ciphertext .= $this->_rsaes_pkcs1_v1_5_encrypt($m);
1986
                }
1987
1988
                return $ciphertext;
1989
            case self::ENCRYPTION_OAEP:
1990
            default:
1991
                $length = $this->k - 2 * $this->hLen - 2;
1992
                if ($length <= 0) {
1993
                    return false;
1994
                }
1995
1996
                $plaintext = str_split($plaintext, $length);
1997
                $ciphertext = '';
1998
                foreach ($plaintext as $m) {
1999
                    $ciphertext .= $this->_rsaes_oaep_encrypt($m);
2000
                }
2001
2002
                return $ciphertext;
2003
        }
2004
    }
2005
2006
    /**
2007
     * Decryption.
2008
     *
2009
     * @see self::encrypt()
2010
     *
2011
     * @param string $plaintext
2012
     *
2013
     * @return string
2014
     */
2015
    public function decrypt($ciphertext)
2016
    {
2017
        if ($this->k <= 0) {
2018
            return false;
2019
        }
2020
2021
        $ciphertext = str_split($ciphertext, $this->k);
2022
        $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);
2023
2024
        $plaintext = '';
2025
2026
        switch ($this->encryptionMode) {
2027
            case self::ENCRYPTION_PKCS1:
2028
                $decrypt = '_rsaes_pkcs1_v1_5_decrypt';
2029
                break;
2030
            case self::ENCRYPTION_OAEP:
2031
            default:
2032
                $decrypt = '_rsaes_oaep_decrypt';
2033
        }
2034
2035
        foreach ($ciphertext as $c) {
2036
            $temp = $this->$decrypt($c);
2037
            if ($temp === false) {
2038
                return false;
2039
            }
2040
            $plaintext .= $temp;
2041
        }
2042
2043
        return $plaintext;
2044
    }
2045
2046
    /**
2047
     * Create a signature.
2048
     *
2049
     * @see self::verify()
2050
     *
2051
     * @param string $message
2052
     *
2053
     * @return string
2054
     */
2055
    public function sign($message)
2056
    {
2057
        if (empty($this->modulus) || empty($this->exponent)) {
2058
            return false;
2059
        }
2060
2061
        switch ($this->signatureMode) {
2062
            case self::SIGNATURE_PKCS1:
2063
                return $this->_rsassa_pkcs1_v1_5_sign($message);
2064
            case self::SIGNATURE_PSS:
2065
            default:
2066
                return $this->_rsassa_pss_sign($message);
2067
        }
2068
    }
2069
2070
    /**
2071
     * Verifies a signature.
2072
     *
2073
     * @see self::sign()
2074
     *
2075
     * @param string $message
2076
     * @param string $signature
2077
     *
2078
     * @return bool
2079
     */
2080
    public function verify($message, $signature)
2081
    {
2082
        if (empty($this->modulus) || empty($this->exponent)) {
2083
            return false;
2084
        }
2085
2086
        switch ($this->signatureMode) {
2087
            case self::SIGNATURE_PKCS1:
2088
                return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
2089
            case self::SIGNATURE_PSS:
2090
            default:
2091
                return $this->_rsassa_pss_verify($message, $signature);
2092
        }
2093
    }
2094
2095
    /**
2096
     * Extract raw BER from Base64 encoding.
2097
     *
2098
     * @param string $str
2099
     *
2100
     * @return string
2101
     */
2102
    private function _extractBER($str)
2103
    {
2104
        /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
2105
         * above and beyond the ceritificate.
2106
         * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
2107
         *
2108
         * Bag Attributes
2109
         *     localKeyID: 01 00 00 00
2110
         * subject=/O=organization/OU=org unit/CN=common name
2111
         * issuer=/O=organization/CN=common name
2112
         */
2113
        $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
2114
        // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
2115
        $temp = preg_replace('#-+[^-]+-+#', '', $temp);
2116
        // remove new lines
2117
        $temp = str_replace(["\r", "\n", ' '], '', $temp);
2118
        $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
2119
2120
        return $temp != false ? $temp : $str;
2121
    }
2122
2123
    /**
2124
     * Defines the public key.
2125
     *
2126
     * Some private key formats define the public exponent and some don't.  Those that don't define it are problematic when
2127
     * used in certain contexts.  For example, in SSH-2, RSA authentication works by sending the public key along with a
2128
     * message signed by the private key to the server.  The SSH-2 server looks the public key up in an index of public keys
2129
     * and if it's present then proceeds to verify the signature.  Problem is, if your private key doesn't include the public
2130
     * exponent this won't work unless you manually add the public exponent. phpseclib tries to guess if the key being used
2131
     * is the public key but in the event that it guesses incorrectly you might still want to explicitly set the key as being
2132
     * public.
2133
     *
2134
     * Do note that when a new key is loaded the index will be cleared.
2135
     *
2136
     * Returns true on success, false on failure
2137
     *
2138
     * @see self::getPublicKey()
2139
     *
2140
     * @param string $key  optional
2141
     * @param int    $type optional
2142
     *
2143
     * @return bool
2144
     */
2145
    private function setPublicKey($key = false, $type = false)
2146
    {
2147
        // if a public key has already been loaded return false
2148
        if (!empty($this->publicExponent)) {
2149
            return false;
2150
        }
2151
2152
        if ($key === false && !empty($this->modulus)) {
2153
            $this->publicExponent = $this->exponent;
2154
2155
            return true;
2156
        }
2157
2158
        if ($type === false) {
2159
            $types = [
2160
                self::PUBLIC_FORMAT_RAW,
2161
                self::PUBLIC_FORMAT_PKCS1,
2162
                self::PUBLIC_FORMAT_XML,
2163
                self::PUBLIC_FORMAT_OPENSSH,
2164
            ];
2165
            foreach ($types as $type) {
2166
                $components = $this->_parseKey($key, $type);
2167
                if ($components !== false) {
2168
                    break;
2169
                }
2170
            }
2171
        } else {
2172
            $components = $this->_parseKey($key, $type);
2173
        }
2174
2175
        if ($components === false) {
2176
            return false;
2177
        }
2178
2179
        if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
0 ignored issues
show
The method equals() does not seem to exist on object<Jose\Util\BigInteger>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2180
            $this->modulus = $components['modulus'];
2181
            $this->exponent = $this->publicExponent = $components['publicExponent'];
2182
2183
            return true;
2184
        }
2185
2186
        $this->publicExponent = $components['publicExponent'];
2187
2188
        return true;
2189
    }
2190
}
2191