Failed Conditions
Push — PHPSecLib_Rid ( 1a2f9f...838957 )
by Florent
05:04
created

src/Util/RSA.php (3 issues)

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 = BigInteger::createFromDecimalString('0');
0 ignored issues
show
Documentation Bug introduced by
It seems like \Jose\Util\BigInteger::c...eFromDecimalString('0') of type object<Jose\Util\BigInteger> is incompatible with the declared type array of property $zero.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
433
        $this->one = BigInteger::createFromDecimalString('1');
0 ignored issues
show
Documentation Bug introduced by
It seems like \Jose\Util\BigInteger::c...eFromDecimalString('1') of type object<Jose\Util\BigInteger> is incompatible with the declared type array of property $one.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
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'] = BigInteger::createFromBinaryString($temp);
655
                    $this->_string_shift($key); // skip over self::ASN1_INTEGER
656
                    $length = $this->_decodeLength($key);
657
                    $components[$type == self::PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = BigInteger::createFromBinaryString($this->_string_shift($key, $length));
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'] = BigInteger::createFromBinaryString($this->_string_shift($key, $length));
666
                $this->_string_shift($key);
667
                $length = $this->_decodeLength($key);
668
                $components['publicExponent'] = BigInteger::createFromBinaryString($this->_string_shift($key, $length));
669
                $this->_string_shift($key);
670
                $length = $this->_decodeLength($key);
671
                $components['privateExponent'] = BigInteger::createFromBinaryString($this->_string_shift($key, $length));
672
                $this->_string_shift($key);
673
                $length = $this->_decodeLength($key);
674
                $components['primes'] = [1 => BigInteger::createFromBinaryString($this->_string_shift($key, $length))];
675
                $this->_string_shift($key);
676
                $length = $this->_decodeLength($key);
677
                $components['primes'][] = BigInteger::createFromBinaryString($this->_string_shift($key, $length));
678
                $this->_string_shift($key);
679
                $length = $this->_decodeLength($key);
680
                $components['exponents'] = [1 => BigInteger::createFromBinaryString($this->_string_shift($key, $length))];
681
                $this->_string_shift($key);
682
                $length = $this->_decodeLength($key);
683
                $components['exponents'][] = BigInteger::createFromBinaryString($this->_string_shift($key, $length));
684
                $this->_string_shift($key);
685
                $length = $this->_decodeLength($key);
686
                $components['coefficients'] = [2 => BigInteger::createFromBinaryString($this->_string_shift($key, $length))];
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'][] = BigInteger::createFromBinaryString($this->_string_shift($key, $length));
701
                        $this->_string_shift($key);
702
                        $length = $this->_decodeLength($key);
703
                        $components['exponents'][] = BigInteger::createFromBinaryString($this->_string_shift($key, $length));
704
                        $this->_string_shift($key);
705
                        $length = $this->_decodeLength($key);
706
                        $components['coefficients'][] = BigInteger::createFromBinaryString($this->_string_shift($key, $length));
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 = BigInteger::createFromBinaryString($this->_string_shift($key, $length));
728
                if (strlen($key) <= 4) {
729
                    return false;
730
                }
731
                extract(unpack('Nlength', $this->_string_shift($key, 4)));
732
                $modulus = BigInteger::createFromBinaryString($this->_string_shift($key, $length));
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 = BigInteger::createFromBinaryString($this->_string_shift($key, $length));
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'] = BigInteger::createFromBinaryString($this->_string_shift($public, $length));
785
                extract(unpack('Nlength', $this->_string_shift($public, 4)));
786
                $components['modulus'] = BigInteger::createFromBinaryString($this->_string_shift($public, $length));
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'] = BigInteger::createFromBinaryString($this->_string_shift($private, $length), true);
817
                extract(unpack('Nlength', $this->_string_shift($private, 4)));
818
                if (strlen($private) < $length) {
819
                    return false;
820
                }
821
                $components['primes'] = [1 => BigInteger::createFromBinaryString($this->_string_shift($private, $length), true)];
822
                extract(unpack('Nlength', $this->_string_shift($private, 4)));
823
                if (strlen($private) < $length) {
824
                    return false;
825
                }
826
                $components['primes'][] = BigInteger::createFromBinaryString($this->_string_shift($private, $length), true);
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 => BigInteger::createFromBinaryString($this->_string_shift($private, $length), true)];
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
    private function _stop_element_handler()
887
    {
888
        if (isset($this->current)) {
889
            $this->current = BigInteger::createFromBinaryString(base64_decode($this->current));
890
            unset($this->current);
891
        }
892
    }
893
894
    /**
895
     * Data Handler.
896
     *
897
     * Called by xml_set_character_data_handler()
898
     *
899
     * @param resource $parser
900
     * @param string   $data
901
     */
902
    public function _data_handler($parser, $data)
903
    {
904
        if (!isset($this->current) || is_object($this->current)) {
905
            return;
906
        }
907
        $this->current .= trim($data);
908
    }
909
910
    /**
911
     * Loads a public or private key.
912
     *
913
     * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
914
     *
915
     * @param string $key
916
     * @param int    $type optional
917
     */
918
    public function loadKey($key, $type = false)
919
    {
920
        if ($key instanceof self) {
921
            $this->privateKeyFormat = $key->privateKeyFormat;
922
            $this->publicKeyFormat = $key->publicKeyFormat;
923
            $this->k = $key->k;
924
            $this->hLen = $key->hLen;
925
            $this->sLen = $key->sLen;
926
            $this->mgfHLen = $key->mgfHLen;
927
            $this->encryptionMode = $key->encryptionMode;
928
            $this->signatureMode = $key->signatureMode;
929
            $this->password = $key->password;
930
            $this->configFile = $key->configFile;
931
            $this->comment = $key->comment;
932
933
            if (is_object($key->hash)) {
934
                $this->hash = new Hash($key->hash->getHash());
935
            }
936
            if (is_object($key->mgfHash)) {
937
                $this->mgfHash = new Hash($key->mgfHash->getHash());
938
            }
939
940
            if (is_object($key->modulus)) {
941
                $this->modulus = $key->modulus->copy();
942
            }
943
            if (is_object($key->exponent)) {
944
                $this->exponent = $key->exponent->copy();
945
            }
946
            if (is_object($key->publicExponent)) {
947
                $this->publicExponent = $key->publicExponent->copy();
948
            }
949
950
            $this->primes = [];
951
            $this->exponents = [];
952
            $this->coefficients = [];
953
954
            foreach ($this->primes as $prime) {
955
                $this->primes[] = $prime->copy();
956
            }
957
            foreach ($this->exponents as $exponent) {
958
                $this->exponents[] = $exponent->copy();
959
            }
960
            foreach ($this->coefficients as $coefficient) {
961
                $this->coefficients[] = $coefficient->copy();
962
            }
963
964
            return true;
965
        }
966
967
        if ($type === false) {
968
            $types = [
969
                self::PUBLIC_FORMAT_RAW,
970
                self::PRIVATE_FORMAT_PKCS1,
971
                self::PRIVATE_FORMAT_XML,
972
                self::PRIVATE_FORMAT_PUTTY,
973
                self::PUBLIC_FORMAT_OPENSSH,
974
            ];
975
            foreach ($types as $type) {
976
                $components = $this->_parseKey($key, $type);
977
                if ($components !== false) {
978
                    break;
979
                }
980
            }
981
        } else {
982
            $components = $this->_parseKey($key, $type);
983
        }
984
985
        if ($components === false) {
986
            return false;
987
        }
988
989
        if (isset($components['comment']) && $components['comment'] !== false) {
990
            $this->comment = $components['comment'];
991
        }
992
        $this->modulus = $components['modulus'];
993
        $this->k = strlen($this->modulus->toBytes());
994
        $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
995
        if (isset($components['primes'])) {
996
            $this->primes = $components['primes'];
997
            $this->exponents = $components['exponents'];
998
            $this->coefficients = $components['coefficients'];
999
            $this->publicExponent = $components['publicExponent'];
1000
        } else {
1001
            $this->primes = [];
1002
            $this->exponents = [];
1003
            $this->coefficients = [];
1004
            $this->publicExponent = false;
1005
        }
1006
1007
        switch ($type) {
1008
            case self::PUBLIC_FORMAT_OPENSSH:
1009
            case self::PUBLIC_FORMAT_RAW:
1010
                $this->setPublicKey();
1011
                break;
1012
            case self::PRIVATE_FORMAT_PKCS1:
1013
                switch (true) {
1014
                    case strpos($key, '-BEGIN PUBLIC KEY-') !== false:
1015
                    case strpos($key, '-BEGIN RSA PUBLIC KEY-') !== false:
1016
                        $this->setPublicKey();
1017
                }
1018
        }
1019
1020
        return true;
1021
    }
1022
1023
    /**
1024
     * DER-decode the length.
1025
     *
1026
     * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4.  See
1027
     * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
1028
     *
1029
     * @param string $string
1030
     *
1031
     * @return int
1032
     */
1033
    private function _decodeLength(&$string)
1034
    {
1035
        $length = ord($this->_string_shift($string));
1036
        if ($length & 0x80) { // definite length, long form
1037
            $length &= 0x7F;
1038
            $temp = $this->_string_shift($string, $length);
1039
            list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
1040
        }
1041
1042
        return $length;
1043
    }
1044
1045
    /**
1046
     * String Shift.
1047
     *
1048
     * Inspired by array_shift
1049
     *
1050
     * @param string $string
1051
     * @param int    $index
1052
     *
1053
     * @return string
1054
     */
1055
    private function _string_shift(&$string, $index = 1)
1056
    {
1057
        $substr = substr($string, 0, $index);
1058
        $string = substr($string, $index);
1059
1060
        return $substr;
1061
    }
1062
1063
    /**
1064
     * Determines which hashing function should be used.
1065
     *
1066
     * Used with signature production / verification and (if the encryption mode is self::ENCRYPTION_OAEP) encryption and
1067
     * decryption.  If $hash isn't supported, sha1 is used.
1068
     *
1069
     * @param string $hash
1070
     */
1071
    public function setHash($hash)
1072
    {
1073
        switch ($hash) {
1074
            case 'sha1':
1075
                $this->hLen = 20;
1076
                break;
1077
            case 'sha256':
1078
                $this->hLen = 32;
1079
                break;
1080
            case 'sha384':
1081
                $this->hLen = 48;
1082
                break;
1083
            case 'sha512':
1084
                $this->hLen = 64;
1085
                break;
1086
            default:
1087
                throw new \InvalidArgumentException('Unsupported hash algorithm.');
1088
        }
1089
        $this->hash = new Hash($hash);
1090
    }
1091
1092
    /**
1093
     * Determines which hashing function should be used for the mask generation function.
1094
     *
1095
     * The mask generation function is used by self::ENCRYPTION_OAEP and self::SIGNATURE_PSS and although it's
1096
     * best if Hash and MGFHash are set to the same thing this is not a requirement.
1097
     *
1098
     * @param string $hash
1099
     */
1100
    public function setMGFHash($hash)
1101
    {
1102
        switch ($hash) {
1103
            case 'sha1':
1104
                $this->mgfHLen = 20;
1105
                break;
1106
            case 'sha256':
1107
                $this->mgfHash = 32;
1108
                break;
1109
            case 'sha384':
1110
                $this->mgfHash = 48;
1111
                break;
1112
            case 'sha512':
1113
                $this->mgfHash = 64;
1114
                break;
1115
            default:
1116
                throw new \InvalidArgumentException('Unsupported hash algorithm.');
1117
        }
1118
        $this->mgfHash = new Hash($hash);
1119
    }
1120
1121
    /**
1122
     * Determines the salt length.
1123
     *
1124
     * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
1125
     *
1126
     *    Typical salt lengths in octets are hLen (the length of the output
1127
     *    of the hash function Hash) and 0.
1128
     *
1129
     * @param int $format
1130
     */
1131
    public function setSaltLength($sLen)
1132
    {
1133
        $this->sLen = $sLen;
1134
    }
1135
1136
    /**
1137
     * Integer-to-Octet-String primitive.
1138
     *
1139
     * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
1140
     *
1141
     * @param \Jose\Util\BigInteger $x
1142
     * @param int                   $xLen
1143
     *
1144
     * @return string
1145
     */
1146
    private function _i2osp($x, $xLen)
1147
    {
1148
        $x = $x->toBytes();
1149
        if (strlen($x) > $xLen) {
1150
            user_error('Integer too large');
1151
1152
            return false;
1153
        }
1154
1155
        return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
1156
    }
1157
1158
    /**
1159
     * Octet-String-to-Integer primitive.
1160
     *
1161
     * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
1162
     *
1163
     * @param string $x
1164
     *
1165
     * @return \Jose\Util\BigInteger
1166
     */
1167
    private function _os2ip($x)
1168
    {
1169
        return BigInteger::createFromBinaryString($x);
1170
    }
1171
1172
    /**
1173
     * Exponentiate with or without Chinese Remainder Theorem.
1174
     *
1175
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
1176
     *
1177
     * @param \Jose\Util\BigInteger $x
1178
     *
1179
     * @return \Jose\Util\BigInteger
1180
     */
1181
    private function _exponentiate($x)
1182
    {
1183
        if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) {
1184
            return $x->modPow($this->exponent, $this->modulus);
0 ignored issues
show
Bug Compatibility introduced by
The expression $x->modPow($this->exponent, $this->modulus); of type Jose\Util\BigInteger|boolean adds the type boolean to the return on line 1184 which is incompatible with the return type documented by Jose\Util\RSA::_exponentiate of type Jose\Util\BigInteger.
Loading history...
1185
        }
1186
1187
        $num_primes = count($this->primes);
1188
1189
        if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
1190
            $m_i = [
1191
                1 => $x->modPow($this->exponents[1], $this->primes[1]),
1192
                2 => $x->modPow($this->exponents[2], $this->primes[2]),
1193
            ];
1194
            $h = $m_i[1]->subtract($m_i[2]);
1195
            $h = $h->multiply($this->coefficients[2]);
1196
            list(, $h) = $h->divide($this->primes[1]);
1197
            $m = $m_i[2]->add($h->multiply($this->primes[2]));
1198
1199
            $r = $this->primes[1];
1200
            for ($i = 3; $i <= $num_primes; $i++) {
1201
                $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
1202
1203
                $r = $r->multiply($this->primes[$i - 1]);
1204
1205
                $h = $m_i->subtract($m);
1206
                $h = $h->multiply($this->coefficients[$i]);
1207
                list(, $h) = $h->divide($this->primes[$i]);
1208
1209
                $m = $m->add($r->multiply($h));
1210
            }
1211
        } else {
1212
            $smallest = $this->primes[1];
1213
            for ($i = 2; $i <= $num_primes; $i++) {
1214
                if ($smallest->compare($this->primes[$i]) > 0) {
1215
                    $smallest = $this->primes[$i];
1216
                }
1217
            }
1218
1219
            $one = BigInteger::createFromDecimalString('1');
1220
1221
            $r = $one->random($one, $smallest->subtract($one));
1222
1223
            $m_i = [
1224
                1 => $this->_blind($x, $r, 1),
1225
                2 => $this->_blind($x, $r, 2),
1226
            ];
1227
            $h = $m_i[1]->subtract($m_i[2]);
1228
            $h = $h->multiply($this->coefficients[2]);
1229
            list(, $h) = $h->divide($this->primes[1]);
1230
            $m = $m_i[2]->add($h->multiply($this->primes[2]));
1231
1232
            $r = $this->primes[1];
1233
            for ($i = 3; $i <= $num_primes; $i++) {
1234
                $m_i = $this->_blind($x, $r, $i);
1235
1236
                $r = $r->multiply($this->primes[$i - 1]);
1237
1238
                $h = $m_i->subtract($m);
1239
                $h = $h->multiply($this->coefficients[$i]);
1240
                list(, $h) = $h->divide($this->primes[$i]);
1241
1242
                $m = $m->add($r->multiply($h));
1243
            }
1244
        }
1245
1246
        return $m;
1247
    }
1248
1249
    /**
1250
     * Performs RSA Blinding.
1251
     *
1252
     * Protects against timing attacks by employing RSA Blinding.
1253
     * Returns $x->modPow($this->exponents[$i], $this->primes[$i])
1254
     *
1255
     * @param \Jose\Util\BigInteger $x
1256
     * @param \Jose\Util\BigInteger $r
1257
     * @param int                   $i
1258
     *
1259
     * @return \Jose\Util\BigInteger
1260
     */
1261
    private function _blind($x, $r, $i)
1262
    {
1263
        $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
1264
        $x = $x->modPow($this->exponents[$i], $this->primes[$i]);
1265
1266
        $r = $r->modInverse($this->primes[$i]);
1267
        $x = $x->multiply($r);
1268
        list(, $x) = $x->divide($this->primes[$i]);
1269
1270
        return $x;
1271
    }
1272
1273
    /**
1274
     * Performs blinded RSA equality testing.
1275
     *
1276
     * Protects against a particular type of timing attack described.
1277
     *
1278
     * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)}
1279
     *
1280
     * Thanks for the heads up singpolyma!
1281
     *
1282
     * @param string $x
1283
     * @param string $y
1284
     *
1285
     * @return bool
1286
     */
1287
    private function _equals($x, $y)
1288
    {
1289
        if (strlen($x) != strlen($y)) {
1290
            return false;
1291
        }
1292
1293
        $result = 0;
1294
        for ($i = 0; $i < strlen($x); $i++) {
1295
            $result |= ord($x[$i]) ^ ord($y[$i]);
1296
        }
1297
1298
        return $result == 0;
1299
    }
1300
1301
    /**
1302
     * RSAEP.
1303
     *
1304
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
1305
     *
1306
     * @param \Jose\Util\BigInteger $m
1307
     *
1308
     * @return \Jose\Util\BigInteger
1309
     */
1310
    private function _rsaep($m)
1311
    {
1312
        if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1313
            user_error('Message representative out of range');
1314
1315
            return false;
1316
        }
1317
1318
        return $this->_exponentiate($m);
1319
    }
1320
1321
    /**
1322
     * RSADP.
1323
     *
1324
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
1325
     *
1326
     * @param \Jose\Util\BigInteger $c
1327
     *
1328
     * @return \Jose\Util\BigInteger
1329
     */
1330
    private function _rsadp($c)
1331
    {
1332
        if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
1333
            user_error('Ciphertext representative out of range');
1334
1335
            return false;
1336
        }
1337
1338
        return $this->_exponentiate($c);
1339
    }
1340
1341
    /**
1342
     * RSASP1.
1343
     *
1344
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
1345
     *
1346
     * @param \Jose\Util\BigInteger $m
1347
     *
1348
     * @return \Jose\Util\BigInteger
1349
     */
1350
    private function _rsasp1($m)
1351
    {
1352
        if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1353
            user_error('Message representative out of range');
1354
1355
            return false;
1356
        }
1357
1358
        return $this->_exponentiate($m);
1359
    }
1360
1361
    /**
1362
     * RSAVP1.
1363
     *
1364
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
1365
     *
1366
     * @param \Jose\Util\BigInteger $s
1367
     *
1368
     * @return \Jose\Util\BigInteger
1369
     */
1370
    private function _rsavp1($s)
1371
    {
1372
        if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
1373
            user_error('Signature representative out of range');
1374
1375
            return false;
1376
        }
1377
1378
        return $this->_exponentiate($s);
1379
    }
1380
1381
    /**
1382
     * MGF1.
1383
     *
1384
     * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
1385
     *
1386
     * @param string $mgfSeed
1387
     * @param int    $mgfLen
1388
     *
1389
     * @return string
1390
     */
1391
    private function _mgf1($mgfSeed, $maskLen)
1392
    {
1393
        // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
1394
1395
        $t = '';
1396
        $count = ceil($maskLen / $this->mgfHLen);
1397
        for ($i = 0; $i < $count; $i++) {
1398
            $c = pack('N', $i);
1399
            $t .= $this->mgfHash->hash($mgfSeed.$c);
1400
        }
1401
1402
        return substr($t, 0, $maskLen);
1403
    }
1404
1405
    /**
1406
     * RSAES-OAEP-ENCRYPT.
1407
     *
1408
     * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and
1409
     * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}.
1410
     *
1411
     * @param string $m
1412
     * @param string $l
1413
     *
1414
     * @return string
1415
     */
1416
    private function _rsaes_oaep_encrypt($m, $l = '')
1417
    {
1418
        $mLen = strlen($m);
1419
1420
        // Length checking
1421
1422
        // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
1423
        // be output.
1424
1425
        if ($mLen > $this->k - 2 * $this->hLen - 2) {
1426
            user_error('Message too long');
1427
1428
            return false;
1429
        }
1430
1431
        // EME-OAEP encoding
1432
1433
        $lHash = $this->hash->hash($l);
1434
        $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
1435
        $db = $lHash.$ps.chr(1).$m;
1436
        $seed = random_bytes($this->hLen);
1437
        $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
1438
        $maskedDB = $db ^ $dbMask;
1439
        $seedMask = $this->_mgf1($maskedDB, $this->hLen);
1440
        $maskedSeed = $seed ^ $seedMask;
1441
        $em = chr(0).$maskedSeed.$maskedDB;
1442
1443
        // RSA encryption
1444
1445
        $m = $this->_os2ip($em);
1446
        $c = $this->_rsaep($m);
1447
        $c = $this->_i2osp($c, $this->k);
1448
1449
        // Output the ciphertext C
1450
1451
        return $c;
1452
    }
1453
1454
    /**
1455
     * RSAES-OAEP-DECRYPT.
1456
     *
1457
     * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}.  The fact that the error
1458
     * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
1459
     *
1460
     *    Note.  Care must be taken to ensure that an opponent cannot
1461
     *    distinguish the different error conditions in Step 3.g, whether by
1462
     *    error message or timing, or, more generally, learn partial
1463
     *    information about the encoded message EM.  Otherwise an opponent may
1464
     *    be able to obtain useful information about the decryption of the
1465
     *    ciphertext C, leading to a chosen-ciphertext attack such as the one
1466
     *    observed by Manger [36].
1467
     *
1468
     * As for $l...  to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
1469
     *
1470
     *    Both the encryption and the decryption operations of RSAES-OAEP take
1471
     *    the value of a label L as input.  In this version of PKCS #1, L is
1472
     *    the empty string; other uses of the label are outside the scope of
1473
     *    this document.
1474
     *
1475
     * @param string $c
1476
     * @param string $l
1477
     *
1478
     * @return string
1479
     */
1480
    private function _rsaes_oaep_decrypt($c, $l = '')
1481
    {
1482
        // Length checking
1483
1484
        // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
1485
        // be output.
1486
1487
        if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
1488
            user_error('Decryption error');
1489
1490
            return false;
1491
        }
1492
1493
        // RSA decryption
1494
1495
        $c = $this->_os2ip($c);
1496
        $m = $this->_rsadp($c);
1497
        if ($m === false) {
1498
            user_error('Decryption error');
1499
1500
            return false;
1501
        }
1502
        $em = $this->_i2osp($m, $this->k);
1503
1504
        // EME-OAEP decoding
1505
1506
        $lHash = $this->hash->hash($l);
1507
        $y = ord($em[0]);
1508
        $maskedSeed = substr($em, 1, $this->hLen);
1509
        $maskedDB = substr($em, $this->hLen + 1);
1510
        $seedMask = $this->_mgf1($maskedDB, $this->hLen);
1511
        $seed = $maskedSeed ^ $seedMask;
1512
        $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
1513
        $db = $maskedDB ^ $dbMask;
1514
        $lHash2 = substr($db, 0, $this->hLen);
1515
        $m = substr($db, $this->hLen);
1516
        if ($lHash != $lHash2) {
1517
            user_error('Decryption error');
1518
1519
            return false;
1520
        }
1521
        $m = ltrim($m, chr(0));
1522
        if (ord($m[0]) != 1) {
1523
            user_error('Decryption error');
1524
1525
            return false;
1526
        }
1527
1528
        // Output the message M
1529
1530
        return substr($m, 1);
1531
    }
1532
1533
    /**
1534
     * RSAES-PKCS1-V1_5-ENCRYPT.
1535
     *
1536
     * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
1537
     *
1538
     * @param string $m
1539
     *
1540
     * @return string
1541
     */
1542
    private function _rsaes_pkcs1_v1_5_encrypt($m)
1543
    {
1544
        $mLen = strlen($m);
1545
1546
        // Length checking
1547
1548
        if ($mLen > $this->k - 11) {
1549
            user_error('Message too long');
1550
1551
            return false;
1552
        }
1553
1554
        // EME-PKCS1-v1_5 encoding
1555
1556
        $psLen = $this->k - $mLen - 3;
1557
        $ps = '';
1558
        while (strlen($ps) != $psLen) {
1559
            $temp = random_bytes($psLen - strlen($ps));
1560
            $temp = str_replace("\x00", '', $temp);
1561
            $ps .= $temp;
1562
        }
1563
        $type = 2;
1564
        // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done
1565
        if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) {
1566
            $type = 1;
1567
            // "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF"
1568
            $ps = str_repeat("\xFF", $psLen);
1569
        }
1570
        $em = chr(0).chr($type).$ps.chr(0).$m;
1571
1572
        // RSA encryption
1573
        $m = $this->_os2ip($em);
1574
        $c = $this->_rsaep($m);
1575
        $c = $this->_i2osp($c, $this->k);
1576
1577
        // Output the ciphertext C
1578
1579
        return $c;
1580
    }
1581
1582
    /**
1583
     * RSAES-PKCS1-V1_5-DECRYPT.
1584
     *
1585
     * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
1586
     *
1587
     * For compatibility purposes, this function departs slightly from the description given in RFC3447.
1588
     * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
1589
     * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
1590
     * public key should have the second byte set to 2.  In RFC3447 (PKCS#1 v2.1), the second byte is supposed
1591
     * to be 2 regardless of which key is used.  For compatibility purposes, we'll just check to make sure the
1592
     * second byte is 2 or less.  If it is, we'll accept the decrypted string as valid.
1593
     *
1594
     * As a consequence of this, a private key encrypted ciphertext produced with \phpseclib\Crypt\RSA may not decrypt
1595
     * with a strictly PKCS#1 v1.5 compliant RSA implementation.  Public key encrypted ciphertext's should but
1596
     * not private key encrypted ciphertext's.
1597
     *
1598
     * @param string $c
1599
     *
1600
     * @return string
1601
     */
1602
    private function _rsaes_pkcs1_v1_5_decrypt($c)
1603
    {
1604
        // Length checking
1605
1606
        if (strlen($c) != $this->k) { // or if k < 11
1607
            user_error('Decryption error');
1608
1609
            return false;
1610
        }
1611
1612
        // RSA decryption
1613
1614
        $c = $this->_os2ip($c);
1615
        $m = $this->_rsadp($c);
1616
1617
        if ($m === false) {
1618
            user_error('Decryption error');
1619
1620
            return false;
1621
        }
1622
        $em = $this->_i2osp($m, $this->k);
1623
1624
        // EME-PKCS1-v1_5 decoding
1625
1626
        if (ord($em[0]) != 0 || ord($em[1]) > 2) {
1627
            user_error('Decryption error');
1628
1629
            return false;
1630
        }
1631
1632
        $ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
1633
        $m = substr($em, strlen($ps) + 3);
1634
1635
        if (strlen($ps) < 8) {
1636
            user_error('Decryption error');
1637
1638
            return false;
1639
        }
1640
1641
        // Output M
1642
1643
        return $m;
1644
    }
1645
1646
    /**
1647
     * EMSA-PSS-ENCODE.
1648
     *
1649
     * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
1650
     *
1651
     * @param string $m
1652
     * @param int    $emBits
1653
     */
1654
    private function _emsa_pss_encode($m, $emBits)
1655
    {
1656
        // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
1657
        // be output.
1658
1659
        $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
1660
        $sLen = $this->sLen ? $this->sLen : $this->hLen;
1661
1662
        $mHash = $this->hash->hash($m);
1663
        if ($emLen < $this->hLen + $sLen + 2) {
1664
            user_error('Encoding error');
1665
1666
            return false;
1667
        }
1668
1669
        $salt = random_bytes($sLen);
1670
        $m2 = "\0\0\0\0\0\0\0\0".$mHash.$salt;
1671
        $h = $this->hash->hash($m2);
1672
        $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
1673
        $db = $ps.chr(1).$salt;
1674
        $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
1675
        $maskedDB = $db ^ $dbMask;
1676
        $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
1677
        $em = $maskedDB.$h.chr(0xBC);
1678
1679
        return $em;
1680
    }
1681
1682
    /**
1683
     * EMSA-PSS-VERIFY.
1684
     *
1685
     * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
1686
     *
1687
     * @param string $m
1688
     * @param string $em
1689
     * @param int    $emBits
1690
     *
1691
     * @return string
1692
     */
1693
    private function _emsa_pss_verify($m, $em, $emBits)
1694
    {
1695
        // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
1696
        // be output.
1697
1698
        $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
1699
        $sLen = $this->sLen ? $this->sLen : $this->hLen;
1700
1701
        $mHash = $this->hash->hash($m);
1702
        if ($emLen < $this->hLen + $sLen + 2) {
1703
            return false;
1704
        }
1705
1706
        if ($em[strlen($em) - 1] != chr(0xBC)) {
1707
            return false;
1708
        }
1709
1710
        $maskedDB = substr($em, 0, -$this->hLen - 1);
1711
        $h = substr($em, -$this->hLen - 1, $this->hLen);
1712
        $temp = chr(0xFF << ($emBits & 7));
1713
        if ((~$maskedDB[0] & $temp) != $temp) {
1714
            return false;
1715
        }
1716
        $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
1717
        $db = $maskedDB ^ $dbMask;
1718
        $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
1719
        $temp = $emLen - $this->hLen - $sLen - 2;
1720
        if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
1721
            return false;
1722
        }
1723
        $salt = substr($db, $temp + 1); // should be $sLen long
1724
        $m2 = "\0\0\0\0\0\0\0\0".$mHash.$salt;
1725
        $h2 = $this->hash->hash($m2);
1726
1727
        return $this->_equals($h, $h2);
1728
    }
1729
1730
    /**
1731
     * RSASSA-PSS-SIGN.
1732
     *
1733
     * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
1734
     *
1735
     * @param string $m
1736
     *
1737
     * @return string
1738
     */
1739
    private function _rsassa_pss_sign($m)
1740
    {
1741
        // EMSA-PSS encoding
1742
1743
        $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);
1744
1745
        // RSA signature
1746
1747
        $m = $this->_os2ip($em);
1748
        $s = $this->_rsasp1($m);
1749
        $s = $this->_i2osp($s, $this->k);
1750
1751
        // Output the signature S
1752
1753
        return $s;
1754
    }
1755
1756
    /**
1757
     * RSASSA-PSS-VERIFY.
1758
     *
1759
     * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
1760
     *
1761
     * @param string $m
1762
     * @param string $s
1763
     *
1764
     * @return string
1765
     */
1766
    private function _rsassa_pss_verify($m, $s)
1767
    {
1768
        // Length checking
1769
1770
        if (strlen($s) != $this->k) {
1771
            user_error('Invalid signature');
1772
1773
            return false;
1774
        }
1775
1776
        // RSA verification
1777
1778
        $modBits = 8 * $this->k;
1779
1780
        $s2 = $this->_os2ip($s);
1781
        $m2 = $this->_rsavp1($s2);
1782
        if ($m2 === false) {
1783
            user_error('Invalid signature');
1784
1785
            return false;
1786
        }
1787
        $em = $this->_i2osp($m2, $modBits >> 3);
1788
        if ($em === false) {
1789
            user_error('Invalid signature');
1790
1791
            return false;
1792
        }
1793
1794
        // EMSA-PSS verification
1795
1796
        return $this->_emsa_pss_verify($m, $em, $modBits - 1);
1797
    }
1798
1799
    /**
1800
     * EMSA-PKCS1-V1_5-ENCODE.
1801
     *
1802
     * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
1803
     *
1804
     * @param string $m
1805
     * @param int    $emLen
1806
     *
1807
     * @return string
1808
     */
1809
    private function _emsa_pkcs1_v1_5_encode($m, $emLen)
1810
    {
1811
        $h = $this->hash->hash($m);
1812
        if ($h === false) {
1813
            return false;
1814
        }
1815
1816
        // see http://tools.ietf.org/html/rfc3447#page-43
1817
        switch ($this->hashName) {
1818
            case 'md2':
1819
                $t = pack('H*', '3020300c06082a864886f70d020205000410');
1820
                break;
1821
            case 'md5':
1822
                $t = pack('H*', '3020300c06082a864886f70d020505000410');
1823
                break;
1824
            case 'sha1':
1825
                $t = pack('H*', '3021300906052b0e03021a05000414');
1826
                break;
1827
            case 'sha256':
1828
                $t = pack('H*', '3031300d060960864801650304020105000420');
1829
                break;
1830
            case 'sha384':
1831
                $t = pack('H*', '3041300d060960864801650304020205000430');
1832
                break;
1833
            case 'sha512':
1834
                $t = pack('H*', '3051300d060960864801650304020305000440');
1835
        }
1836
        $t .= $h;
1837
        $tLen = strlen($t);
1838
1839
        if ($emLen < $tLen + 11) {
1840
            user_error('Intended encoded message length too short');
1841
1842
            return false;
1843
        }
1844
1845
        $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
1846
1847
        $em = "\0\1$ps\0$t";
1848
1849
        return $em;
1850
    }
1851
1852
    /**
1853
     * RSASSA-PKCS1-V1_5-SIGN.
1854
     *
1855
     * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
1856
     *
1857
     * @param string $m
1858
     *
1859
     * @return string
1860
     */
1861
    private function _rsassa_pkcs1_v1_5_sign($m)
1862
    {
1863
        // EMSA-PKCS1-v1_5 encoding
1864
1865
        $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
1866
        if ($em === false) {
1867
            user_error('RSA modulus too short');
1868
1869
            return false;
1870
        }
1871
1872
        // RSA signature
1873
1874
        $m = $this->_os2ip($em);
1875
        $s = $this->_rsasp1($m);
1876
        $s = $this->_i2osp($s, $this->k);
1877
1878
        // Output the signature S
1879
1880
        return $s;
1881
    }
1882
1883
    /**
1884
     * RSASSA-PKCS1-V1_5-VERIFY.
1885
     *
1886
     * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}.
1887
     *
1888
     * @param string $m
1889
     *
1890
     * @return string
1891
     */
1892
    private function _rsassa_pkcs1_v1_5_verify($m, $s)
1893
    {
1894
        // Length checking
1895
1896
        if (strlen($s) != $this->k) {
1897
            user_error('Invalid signature');
1898
1899
            return false;
1900
        }
1901
1902
        // RSA verification
1903
1904
        $s = $this->_os2ip($s);
1905
        $m2 = $this->_rsavp1($s);
1906
        if ($m2 === false) {
1907
            user_error('Invalid signature');
1908
1909
            return false;
1910
        }
1911
        $em = $this->_i2osp($m2, $this->k);
1912
        if ($em === false) {
1913
            user_error('Invalid signature');
1914
1915
            return false;
1916
        }
1917
1918
        // EMSA-PKCS1-v1_5 encoding
1919
1920
        $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
1921
        if ($em2 === false) {
1922
            user_error('RSA modulus too short');
1923
1924
            return false;
1925
        }
1926
1927
        // Compare
1928
        return $this->_equals($em, $em2);
1929
    }
1930
1931
    /**
1932
     * Set Encryption Mode.
1933
     *
1934
     * Valid values include self::ENCRYPTION_OAEP and self::ENCRYPTION_PKCS1.
1935
     *
1936
     * @param int $mode
1937
     */
1938
    public function setEncryptionMode($mode)
1939
    {
1940
        $this->encryptionMode = $mode;
1941
    }
1942
1943
    /**
1944
     * Set Signature Mode.
1945
     *
1946
     * Valid values include self::SIGNATURE_PSS and self::SIGNATURE_PKCS1
1947
     *
1948
     * @param int $mode
1949
     */
1950
    public function setSignatureMode($mode)
1951
    {
1952
        $this->signatureMode = $mode;
1953
    }
1954
1955
    /**
1956
     * Encryption.
1957
     *
1958
     * Both self::ENCRYPTION_OAEP and self::ENCRYPTION_PKCS1 both place limits on how long $plaintext can be.
1959
     * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
1960
     * be concatenated together.
1961
     *
1962
     * @see self::decrypt()
1963
     *
1964
     * @param string $plaintext
1965
     *
1966
     * @return string
1967
     */
1968
    public function encrypt($plaintext)
1969
    {
1970
        switch ($this->encryptionMode) {
1971
            case self::ENCRYPTION_PKCS1:
1972
                $length = $this->k - 11;
1973
                if ($length <= 0) {
1974
                    return false;
1975
                }
1976
1977
                $plaintext = str_split($plaintext, $length);
1978
                $ciphertext = '';
1979
                foreach ($plaintext as $m) {
1980
                    $ciphertext .= $this->_rsaes_pkcs1_v1_5_encrypt($m);
1981
                }
1982
1983
                return $ciphertext;
1984
            case self::ENCRYPTION_OAEP:
1985
            default:
1986
                $length = $this->k - 2 * $this->hLen - 2;
1987
                if ($length <= 0) {
1988
                    return false;
1989
                }
1990
1991
                $plaintext = str_split($plaintext, $length);
1992
                $ciphertext = '';
1993
                foreach ($plaintext as $m) {
1994
                    $ciphertext .= $this->_rsaes_oaep_encrypt($m);
1995
                }
1996
1997
                return $ciphertext;
1998
        }
1999
    }
2000
2001
    /**
2002
     * Decryption.
2003
     *
2004
     * @see self::encrypt()
2005
     *
2006
     * @param string $plaintext
2007
     *
2008
     * @return string
2009
     */
2010
    public function decrypt($ciphertext)
2011
    {
2012
        if ($this->k <= 0) {
2013
            return false;
2014
        }
2015
2016
        $ciphertext = str_split($ciphertext, $this->k);
2017
        $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);
2018
2019
        $plaintext = '';
2020
2021
        switch ($this->encryptionMode) {
2022
            case self::ENCRYPTION_PKCS1:
2023
                $decrypt = '_rsaes_pkcs1_v1_5_decrypt';
2024
                break;
2025
            case self::ENCRYPTION_OAEP:
2026
            default:
2027
                $decrypt = '_rsaes_oaep_decrypt';
2028
        }
2029
2030
        foreach ($ciphertext as $c) {
2031
            $temp = $this->$decrypt($c);
2032
            if ($temp === false) {
2033
                return false;
2034
            }
2035
            $plaintext .= $temp;
2036
        }
2037
2038
        return $plaintext;
2039
    }
2040
2041
    /**
2042
     * Create a signature.
2043
     *
2044
     * @see self::verify()
2045
     *
2046
     * @param string $message
2047
     *
2048
     * @return string
2049
     */
2050
    public function sign($message)
2051
    {
2052
        if (empty($this->modulus) || empty($this->exponent)) {
2053
            return false;
2054
        }
2055
2056
        switch ($this->signatureMode) {
2057
            case self::SIGNATURE_PKCS1:
2058
                return $this->_rsassa_pkcs1_v1_5_sign($message);
2059
            case self::SIGNATURE_PSS:
2060
            default:
2061
                return $this->_rsassa_pss_sign($message);
2062
        }
2063
    }
2064
2065
    /**
2066
     * Verifies a signature.
2067
     *
2068
     * @see self::sign()
2069
     *
2070
     * @param string $message
2071
     * @param string $signature
2072
     *
2073
     * @return bool
2074
     */
2075
    public function verify($message, $signature)
2076
    {
2077
        if (empty($this->modulus) || empty($this->exponent)) {
2078
            return false;
2079
        }
2080
2081
        switch ($this->signatureMode) {
2082
            case self::SIGNATURE_PKCS1:
2083
                return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
2084
            case self::SIGNATURE_PSS:
2085
            default:
2086
                return $this->_rsassa_pss_verify($message, $signature);
2087
        }
2088
    }
2089
2090
    /**
2091
     * Extract raw BER from Base64 encoding.
2092
     *
2093
     * @param string $str
2094
     *
2095
     * @return string
2096
     */
2097
    private function _extractBER($str)
2098
    {
2099
        /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
2100
         * above and beyond the ceritificate.
2101
         * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
2102
         *
2103
         * Bag Attributes
2104
         *     localKeyID: 01 00 00 00
2105
         * subject=/O=organization/OU=org unit/CN=common name
2106
         * issuer=/O=organization/CN=common name
2107
         */
2108
        $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
2109
        // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
2110
        $temp = preg_replace('#-+[^-]+-+#', '', $temp);
2111
        // remove new lines
2112
        $temp = str_replace(["\r", "\n", ' '], '', $temp);
2113
        $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
2114
2115
        return $temp != false ? $temp : $str;
2116
    }
2117
2118
    /**
2119
     * Defines the public key.
2120
     *
2121
     * Some private key formats define the public exponent and some don't.  Those that don't define it are problematic when
2122
     * used in certain contexts.  For example, in SSH-2, RSA authentication works by sending the public key along with a
2123
     * message signed by the private key to the server.  The SSH-2 server looks the public key up in an index of public keys
2124
     * and if it's present then proceeds to verify the signature.  Problem is, if your private key doesn't include the public
2125
     * exponent this won't work unless you manually add the public exponent. phpseclib tries to guess if the key being used
2126
     * is the public key but in the event that it guesses incorrectly you might still want to explicitly set the key as being
2127
     * public.
2128
     *
2129
     * Do note that when a new key is loaded the index will be cleared.
2130
     *
2131
     * Returns true on success, false on failure
2132
     *
2133
     * @see self::getPublicKey()
2134
     *
2135
     * @param string $key  optional
2136
     * @param int    $type optional
2137
     *
2138
     * @return bool
2139
     */
2140
    private function setPublicKey($key = false, $type = false)
2141
    {
2142
        // if a public key has already been loaded return false
2143
        if (!empty($this->publicExponent)) {
2144
            return false;
2145
        }
2146
2147
        if ($key === false && !empty($this->modulus)) {
2148
            $this->publicExponent = $this->exponent;
2149
2150
            return true;
2151
        }
2152
2153
        if ($type === false) {
2154
            $types = [
2155
                self::PUBLIC_FORMAT_RAW,
2156
                self::PUBLIC_FORMAT_PKCS1,
2157
                self::PUBLIC_FORMAT_XML,
2158
                self::PUBLIC_FORMAT_OPENSSH,
2159
            ];
2160
            foreach ($types as $type) {
2161
                $components = $this->_parseKey($key, $type);
2162
                if ($components !== false) {
2163
                    break;
2164
                }
2165
            }
2166
        } else {
2167
            $components = $this->_parseKey($key, $type);
2168
        }
2169
2170
        if ($components === false) {
2171
            return false;
2172
        }
2173
2174
        if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
2175
            $this->modulus = $components['modulus'];
2176
            $this->exponent = $this->publicExponent = $components['publicExponent'];
2177
2178
            return true;
2179
        }
2180
2181
        $this->publicExponent = $components['publicExponent'];
2182
2183
        return true;
2184
    }
2185
}
2186