xref: /dokuwiki/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php (revision 7a48b45e8159fda5cdf0bf07c87cff9744ba1a9c)
1<?php
2
3/**
4 * Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA.
5 *
6 * PHP version 5
7 *
8 * Here's an example of how to encrypt and decrypt text with this library:
9 * <code>
10 * <?php
11 * include 'vendor/autoload.php';
12 *
13 * $private = Crypt\RSA::createKey();
14 * $public = $private->getPublicKey();
15 *
16 * $plaintext = 'terrafrost';
17 *
18 * $ciphertext = $public->encrypt($plaintext);
19 *
20 * echo $private->decrypt($ciphertext);
21 * ?>
22 * </code>
23 *
24 * Here's an example of how to create signatures and verify signatures with this library:
25 * <code>
26 * <?php
27 * include 'vendor/autoload.php';
28 *
29 * $private = Crypt\RSA::createKey();
30 * $public = $private->getPublicKey();
31 *
32 * $plaintext = 'terrafrost';
33 *
34 * $signature = $private->sign($plaintext);
35 *
36 * echo $public->verify($plaintext, $signature) ? 'verified' : 'unverified';
37 * ?>
38 * </code>
39 *
40 * One thing to consider when using this: so phpseclib uses PSS mode by default.
41 * Technically, id-RSASSA-PSS has a different key format than rsaEncryption. So
42 * should phpseclib save to the id-RSASSA-PSS format by default or the
43 * rsaEncryption format? For stand-alone keys I figure rsaEncryption is better
44 * because SSH doesn't use PSS and idk how many SSH servers would be able to
45 * decode an id-RSASSA-PSS key. For X.509 certificates the id-RSASSA-PSS
46 * format is used by default (unless you change it up to use PKCS1 instead)
47 *
48 * @author    Jim Wigginton <terrafrost@php.net>
49 * @copyright 2009 Jim Wigginton
50 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
51 * @link      http://phpseclib.sourceforge.net
52 */
53
54namespace phpseclib3\Crypt;
55
56use phpseclib3\Crypt\Common\AsymmetricKey;
57use phpseclib3\Crypt\RSA\Formats\Keys\PSS;
58use phpseclib3\Crypt\RSA\PrivateKey;
59use phpseclib3\Crypt\RSA\PublicKey;
60use phpseclib3\Exception\BadConfigurationException;
61use phpseclib3\Exception\InconsistentSetupException;
62use phpseclib3\Exception\UnsupportedAlgorithmException;
63use phpseclib3\Math\BigInteger;
64
65/**
66 * Pure-PHP PKCS#1 compliant implementation of RSA.
67 *
68 * @author  Jim Wigginton <terrafrost@php.net>
69 */
70abstract class RSA extends AsymmetricKey
71{
72    /**
73     * Algorithm Name
74     *
75     * @var string
76     */
77    const ALGORITHM = 'RSA';
78
79    /**
80     * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
81     * (OAEP) for encryption / decryption.
82     *
83     * Uses sha256 by default
84     *
85     * @see self::setHash()
86     * @see self::setMGFHash()
87     * @see self::encrypt()
88     * @see self::decrypt()
89     */
90    const ENCRYPTION_OAEP = 1;
91
92    /**
93     * Use PKCS#1 padding.
94     *
95     * Although self::PADDING_OAEP / self::PADDING_PSS  offers more security, including PKCS#1 padding is necessary for purposes of backwards
96     * compatibility with protocols (like SSH-1) written before OAEP's introduction.
97     *
98     * @see self::encrypt()
99     * @see self::decrypt()
100     */
101    const ENCRYPTION_PKCS1 = 2;
102
103    /**
104     * Do not use any padding
105     *
106     * Although this method is not recommended it can none-the-less sometimes be useful if you're trying to decrypt some legacy
107     * stuff, if you're trying to diagnose why an encrypted message isn't decrypting, etc.
108     *
109     * @see self::encrypt()
110     * @see self::decrypt()
111     */
112    const ENCRYPTION_NONE = 4;
113
114    /**
115     * Use the Probabilistic Signature Scheme for signing
116     *
117     * Uses sha256 and 0 as the salt length
118     *
119     * @see self::setSaltLength()
120     * @see self::setMGFHash()
121     * @see self::setHash()
122     * @see self::sign()
123     * @see self::verify()
124     * @see self::setHash()
125     */
126    const SIGNATURE_PSS = 16;
127
128    /**
129     * Use a relaxed version of PKCS#1 padding for signature verification
130     *
131     * @see self::sign()
132     * @see self::verify()
133     * @see self::setHash()
134     */
135    const SIGNATURE_RELAXED_PKCS1 = 32;
136
137    /**
138     * Use PKCS#1 padding for signature verification
139     *
140     * @see self::sign()
141     * @see self::verify()
142     * @see self::setHash()
143     */
144    const SIGNATURE_PKCS1 = 64;
145
146    /**
147     * Encryption padding mode
148     *
149     * @var int
150     */
151    protected $encryptionPadding = self::ENCRYPTION_OAEP;
152
153    /**
154     * Signature padding mode
155     *
156     * @var int
157     */
158    protected $signaturePadding = self::SIGNATURE_PSS;
159
160    /**
161     * Length of hash function output
162     *
163     * @var int
164     */
165    protected $hLen;
166
167    /**
168     * Length of salt
169     *
170     * @var int
171     */
172    protected $sLen;
173
174    /**
175     * Label
176     *
177     * @var string
178     */
179    protected $label = '';
180
181    /**
182     * Hash function for the Mask Generation Function
183     *
184     * @var Hash
185     */
186    protected $mgfHash;
187
188    /**
189     * Length of MGF hash function output
190     *
191     * @var int
192     */
193    protected $mgfHLen;
194
195    /**
196     * Modulus (ie. n)
197     *
198     * @var Math\BigInteger
199     */
200    protected $modulus;
201
202    /**
203     * Modulus length
204     *
205     * @var Math\BigInteger
206     */
207    protected $k;
208
209    /**
210     * Exponent (ie. e or d)
211     *
212     * @var Math\BigInteger
213     */
214    protected $exponent;
215
216    /**
217     * Default public exponent
218     *
219     * @var int
220     * @link http://en.wikipedia.org/wiki/65537_%28number%29
221     */
222    private static $defaultExponent = 65537;
223
224    /**
225     * Enable Blinding?
226     *
227     * @var bool
228     */
229    protected static $enableBlinding = true;
230
231    /**
232     * Smallest Prime
233     *
234     * Per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
235     * than 256 bits. As a consequence if the key you're trying to create is 1024 bits and you've set smallestPrime
236     * to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). At least if
237     * engine is set to self::ENGINE_INTERNAL. If Engine is set to self::ENGINE_OPENSSL then smallest Prime is
238     * ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key generation when there's
239     * a chance neither gmp nor OpenSSL are installed)
240     *
241     * @var int
242     */
243    private static $smallestPrime = 4096;
244
245    /**
246     * Public Exponent
247     *
248     * @var Math\BigInteger
249     */
250    protected $publicExponent;
251
252    /**
253     * Forced Engine
254     *
255     * @var ?string
256     * @see parent::forceEngine()
257     */
258    protected static $forcedEngine = null;
259
260    /**
261     * Sets the public exponent for key generation
262     *
263     * This will be 65537 unless changed.
264     *
265     * @param int $val
266     */
267    public static function setExponent($val)
268    {
269        self::$defaultExponent = $val;
270    }
271
272    /**
273     * Sets the smallest prime number in bits. Used for key generation
274     *
275     * This will be 4096 unless changed.
276     *
277     * @param int $val
278     */
279    public static function setSmallestPrime($val)
280    {
281        self::$smallestPrime = $val;
282    }
283
284    /**
285     * Create a private key
286     *
287     * The public key can be extracted from the private key
288     *
289     * @return PrivateKey
290     * @param int $bits
291     */
292    public static function createKey($bits = 2048)
293    {
294        self::initialize_static_variables();
295
296        $class = new \ReflectionClass(static::class);
297        if ($class->isFinal()) {
298            throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')');
299        }
300
301        if (self::$forcedEngine == 'libsodium' || (self::$forcedEngine == 'OpenSSL' && !function_exists('openssl_pkey_new'))) {
302            throw new BadConfigurationException('Engine ' . self::$forcedEngine . ' is forced but unsupported for RSA');
303        }
304
305        $regSize = $bits >> 1; // divide by two to see how many bits P and Q would be
306        if ($regSize > self::$smallestPrime) {
307            $num_primes = floor($bits / self::$smallestPrime);
308            $regSize = self::$smallestPrime;
309        } else {
310            $num_primes = 2;
311        }
312
313        if ($num_primes == 2 && $bits >= 384 && self::$defaultExponent == 65537) {
314            // at this point the only two supported values for self::$forcedEngine are OpenSSL, PHP and null
315            // if it's either OpenSSL or null we'll use OpenSSL (if it's available)
316            if (self::$forcedEngine !== 'PHP' && function_exists('openssl_pkey_new')) {
317                $config = [];
318                if (self::$configFile) {
319                    $config['config'] = self::$configFile;
320                }
321                // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
322                $rsa = openssl_pkey_new(['private_key_bits' => $bits] + $config);
323                if (!$rsa || !openssl_pkey_export($rsa, $privatekeystr, null, $config)) {
324                    if (isset(self::$forcedEngine)) {
325                        throw new BadConfigurationException('Engine OpenSSL is forced but produced an error - ' . openssl_error_string());
326                    }
327                } else {
328                    // clear the buffer of error strings stemming from a minimalistic openssl.cnf
329                    // https://github.com/php/php-src/issues/11054 talks about other errors this'll pick up
330                    while (openssl_error_string() !== false) {
331                    }
332
333                    return RSA::load($privatekeystr);
334                }
335            }
336        }
337
338        static $e;
339        if (!isset($e)) {
340            $e = new BigInteger(self::$defaultExponent);
341        }
342
343        $n = clone self::$one;
344        $exponents = $coefficients = $primes = [];
345        $lcm = [
346            'top' => clone self::$one,
347            'bottom' => false
348        ];
349
350        do {
351            for ($i = 1; $i <= $num_primes; $i++) {
352                if ($i != $num_primes) {
353                    $primes[$i] = BigInteger::randomPrime($regSize);
354                } else {
355                    $minMax = BigInteger::minMaxBits($bits);
356                    $min = $minMax['min'];
357                    $max = $minMax['max'];
358                    list($min) = $min->divide($n);
359                    $min = $min->add(self::$one);
360                    list($max) = $max->divide($n);
361                    $primes[$i] = BigInteger::randomRangePrime($min, $max);
362                }
363
364                // the first coefficient is calculated differently from the rest
365                // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
366                if ($i > 2) {
367                    $coefficients[$i] = $n->modInverse($primes[$i]);
368                }
369
370                $n = $n->multiply($primes[$i]);
371
372                $temp = $primes[$i]->subtract(self::$one);
373
374                // textbook RSA implementations use Euler's totient function instead of the least common multiple.
375                // see http://en.wikipedia.org/wiki/Euler%27s_totient_function
376                $lcm['top'] = $lcm['top']->multiply($temp);
377                $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
378            }
379
380            list($temp) = $lcm['top']->divide($lcm['bottom']);
381            $gcd = $temp->gcd($e);
382            $i0 = 1;
383        } while (!$gcd->equals(self::$one));
384
385        $coefficients[2] = $primes[2]->modInverse($primes[1]);
386
387        $d = $e->modInverse($temp);
388
389        foreach ($primes as $i => $prime) {
390            $temp = $prime->subtract(self::$one);
391            $exponents[$i] = $e->modInverse($temp);
392        }
393
394        // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
395        // RSAPrivateKey ::= SEQUENCE {
396        //     version           Version,
397        //     modulus           INTEGER,  -- n
398        //     publicExponent    INTEGER,  -- e
399        //     privateExponent   INTEGER,  -- d
400        //     prime1            INTEGER,  -- p
401        //     prime2            INTEGER,  -- q
402        //     exponent1         INTEGER,  -- d mod (p-1)
403        //     exponent2         INTEGER,  -- d mod (q-1)
404        //     coefficient       INTEGER,  -- (inverse of q) mod p
405        //     otherPrimeInfos   OtherPrimeInfos OPTIONAL
406        // }
407        $privatekey = new PrivateKey();
408        $privatekey->modulus = $n;
409        $privatekey->k = $bits >> 3;
410        $privatekey->publicExponent = $e;
411        $privatekey->exponent = $d;
412        $privatekey->primes = $primes;
413        $privatekey->exponents = $exponents;
414        $privatekey->coefficients = $coefficients;
415
416        /*
417        $publickey = new PublicKey;
418        $publickey->modulus = $n;
419        $publickey->k = $bits >> 3;
420        $publickey->exponent = $e;
421        $publickey->publicExponent = $e;
422        $publickey->isPublic = true;
423        */
424
425        return $privatekey;
426    }
427
428    /**
429     * OnLoad Handler
430     *
431     * @return bool
432     */
433    protected static function onLoad(array $components)
434    {
435        $key = $components['isPublicKey'] ?
436            new PublicKey() :
437            new PrivateKey();
438
439        $key->modulus = $components['modulus'];
440        $key->publicExponent = $components['publicExponent'];
441        $key->k = $key->modulus->getLengthInBytes();
442
443        if ($components['isPublicKey'] || !isset($components['privateExponent'])) {
444            $key->exponent = $key->publicExponent;
445        } else {
446            $key->privateExponent = $components['privateExponent'];
447            $key->exponent = $key->privateExponent;
448            $key->primes = $components['primes'];
449            $key->exponents = $components['exponents'];
450            $key->coefficients = $components['coefficients'];
451        }
452
453        if ($components['format'] == PSS::class) {
454            // in the X509 world RSA keys are assumed to use PKCS1 padding by default. only if the key is
455            // explicitly a PSS key is the use of PSS assumed. phpseclib does not work like this. phpseclib
456            // uses PSS padding by default. it assumes the more secure method by default and altho it provides
457            // for the less secure PKCS1 method you have to go out of your way to use it. this is consistent
458            // with the latest trends in crypto. libsodium (NaCl) is actually a little more extreme in that
459            // not only does it defaults to the most secure methods - it doesn't even let you choose less
460            // secure methods
461            //$key = $key->withPadding(self::SIGNATURE_PSS);
462            if (isset($components['hash'])) {
463                $key = $key->withHash($components['hash']);
464            }
465            if (isset($components['MGFHash'])) {
466                $key = $key->withMGFHash($components['MGFHash']);
467            }
468            if (isset($components['saltLength'])) {
469                $key = $key->withSaltLength($components['saltLength']);
470            }
471        }
472
473        return $key;
474    }
475
476    /**
477     * Constructor
478     *
479     * PublicKey and PrivateKey objects can only be created from abstract RSA class
480     */
481    protected function __construct()
482    {
483        parent::__construct();
484
485        $this->hLen = $this->hash->getLengthInBytes();
486        $this->mgfHash = new Hash('sha256');
487        $this->mgfHLen = $this->mgfHash->getLengthInBytes();
488    }
489
490    /**
491     * Integer-to-Octet-String primitive
492     *
493     * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
494     *
495     * @param bool|Math\BigInteger $x
496     * @param int $xLen
497     * @return bool|string
498     */
499    protected function i2osp($x, $xLen)
500    {
501        if ($x === false) {
502            return false;
503        }
504        $x = $x->toBytes();
505        if (strlen($x) > $xLen) {
506            throw new \OutOfRangeException('Resultant string length out of range');
507        }
508        return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
509    }
510
511    /**
512     * Octet-String-to-Integer primitive
513     *
514     * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
515     *
516     * @param string $x
517     * @return Math\BigInteger
518     */
519    protected function os2ip($x)
520    {
521        return new BigInteger($x, 256);
522    }
523
524    /**
525     * EMSA-PKCS1-V1_5-ENCODE
526     *
527     * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
528     *
529     * @param string $m
530     * @param int $emLen
531     * @throws \LengthException if the intended encoded message length is too short
532     * @return string
533     */
534    protected function emsa_pkcs1_v1_5_encode($m, $emLen)
535    {
536        $h = $this->hash->hash($m);
537
538        // see http://tools.ietf.org/html/rfc3447#page-43
539        switch ($this->hash->getHash()) {
540            case 'md2':
541                $t = "\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x02\x05\x00\x04\x10";
542                break;
543            case 'md5':
544                $t = "\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10";
545                break;
546            case 'sha1':
547                $t = "\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14";
548                break;
549            case 'sha256':
550                $t = "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20";
551                break;
552            case 'sha384':
553                $t = "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30";
554                break;
555            case 'sha512':
556                $t = "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40";
557                break;
558            // from https://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptography-standard-wp.pdf#page=40
559            case 'sha224':
560                $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04\x05\x00\x04\x1c";
561                break;
562            case 'sha512/224':
563                $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x05\x05\x00\x04\x1c";
564                break;
565            case 'sha512/256':
566                $t = "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x06\x05\x00\x04\x20";
567                break;
568            // the following 3x algorithms are not specified in PKCS1 v2.2, however, some standards none-the-less do use them:
569            // https://sk-eid.github.io/smart-id-documentation/rp-api/changes.html#_security_enhancements
570            // the OIDs are from this URL:
571            // https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration#Hash
572            case 'sha3/224':
573                $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x07\x05\x00\x04\x1c";
574                break;
575            case 'sha3/256':
576                $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x08\x05\x00\x04\x20";
577                break;
578            case 'sha3/384':
579                $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x09\x05\x00\x04\x30";
580                break;
581            case 'sha3/512':
582                $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0A\x05\x00\x04\x40";
583        }
584        $t .= $h;
585        $tLen = strlen($t);
586
587        if ($emLen < $tLen + 11) {
588            throw new \LengthException('Intended encoded message length too short');
589        }
590
591        $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
592
593        $em = "\0\1$ps\0$t";
594
595        return $em;
596    }
597
598    /**
599     * EMSA-PKCS1-V1_5-ENCODE (without NULL)
600     *
601     * Quoting https://tools.ietf.org/html/rfc8017#page-65,
602     *
603     * "The parameters field associated with id-sha1, id-sha224, id-sha256,
604     *  id-sha384, id-sha512, id-sha512/224, and id-sha512/256 should
605     *  generally be omitted, but if present, it shall have a value of type
606     *  NULL"
607     *
608     * @param string $m
609     * @param int $emLen
610     * @return string
611     */
612    protected function emsa_pkcs1_v1_5_encode_without_null($m, $emLen)
613    {
614        $h = $this->hash->hash($m);
615
616        // see http://tools.ietf.org/html/rfc3447#page-43
617        switch ($this->hash->getHash()) {
618            case 'sha1':
619                $t = "\x30\x1f\x30\x07\x06\x05\x2b\x0e\x03\x02\x1a\x04\x14";
620                break;
621            case 'sha256':
622                $t = "\x30\x2f\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x04\x20";
623                break;
624            case 'sha384':
625                $t = "\x30\x3f\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x04\x30";
626                break;
627            case 'sha512':
628                $t = "\x30\x4f\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x04\x40";
629                break;
630            // from https://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptography-standard-wp.pdf#page=40
631            case 'sha224':
632                $t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04\x04\x1c";
633                break;
634            case 'sha512/224':
635                $t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x05\x04\x1c";
636                break;
637            case 'sha512/256':
638                $t = "\x30\x2f\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x06\x04\x20";
639                break;
640            // the following 3x algorithms are not specified in PKCS1 v2.2, however, some standards none-the-less do use them:
641            // https://sk-eid.github.io/smart-id-documentation/rp-api/changes.html#_security_enhancements
642            // the OIDs are from this URL:
643            // https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration#Hash
644            case 'sha3/224':
645                $t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x07\x04\x1c";
646                break;
647            case 'sha3/256':
648                $t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x08\x04\x20";
649                break;
650            case 'sha3/384':
651                $t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x09\x04\x30";
652                break;
653            case 'sha3/512':
654                $t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0A\x04\x40";
655                break;
656            default:
657                throw new UnsupportedAlgorithmException('md2 and md5 require NULLs');
658        }
659        $t .= $h;
660        $tLen = strlen($t);
661
662        if ($emLen < $tLen + 11) {
663            throw new \LengthException('Intended encoded message length too short');
664        }
665
666        $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
667
668        $em = "\0\1$ps\0$t";
669
670        return $em;
671    }
672
673    /**
674     * MGF1
675     *
676     * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
677     *
678     * @param string $mgfSeed
679     * @param int $maskLen
680     * @return string
681     */
682    protected function mgf1($mgfSeed, $maskLen)
683    {
684        // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
685
686        $t = '';
687        $count = ceil($maskLen / $this->mgfHLen);
688        for ($i = 0; $i < $count; $i++) {
689            $c = pack('N', $i);
690            $t .= $this->mgfHash->hash($mgfSeed . $c);
691        }
692
693        return substr($t, 0, $maskLen);
694    }
695
696    /**
697     * Returns the key size
698     *
699     * More specifically, this returns the size of the modulo in bits.
700     *
701     * @return int
702     */
703    public function getLength()
704    {
705        return !isset($this->modulus) ? 0 : $this->modulus->getLength();
706    }
707
708    /**
709     * Determines which hashing function should be used
710     *
711     * Used with signature production / verification and (if the encryption mode is self::PADDING_OAEP) encryption and
712     * decryption.
713     *
714     * @param string $hash
715     */
716    public function withHash($hash)
717    {
718        $new = clone $this;
719
720        // Crypt\Hash supports algorithms that PKCS#1 doesn't support.  md5-96 and sha1-96, for example.
721        switch (strtolower($hash)) {
722            case 'md2':
723            case 'md5':
724            case 'sha1':
725            case 'sha256':
726            case 'sha384':
727            case 'sha512':
728            case 'sha224':
729            case 'sha512/224':
730            case 'sha512/256':
731            case 'sha3/224':
732            case 'sha3/256':
733            case 'sha3/384':
734            case 'sha3/512':
735                $new->hash = new Hash($hash);
736                break;
737            default:
738                throw new UnsupportedAlgorithmException(
739                    "The only supported hash algorithms are: md2, md5, sha1, sha256, sha384, sha512, sha224, sha512/224, sha512/256 - $hash provided"
740                );
741        }
742        $new->hLen = $new->hash->getLengthInBytes();
743
744        return $new;
745    }
746
747    /**
748     * Determines which hashing function should be used for the mask generation function
749     *
750     * The mask generation function is used by self::PADDING_OAEP and self::PADDING_PSS and although it's
751     * best if Hash and MGFHash are set to the same thing this is not a requirement.
752     *
753     * @param string $hash
754     */
755    public function withMGFHash($hash)
756    {
757        $new = clone $this;
758
759        // Crypt\Hash supports algorithms that PKCS#1 doesn't support.  md5-96 and sha1-96, for example.
760        switch (strtolower($hash)) {
761            case 'md2':
762            case 'md5':
763            case 'sha1':
764            case 'sha256':
765            case 'sha384':
766            case 'sha512':
767            case 'sha224':
768            case 'sha512/224':
769            case 'sha512/256':
770            case 'sha3/224':
771            case 'sha3/256':
772            case 'sha3/384':
773            case 'sha3/512':
774                $new->mgfHash = new Hash($hash);
775                break;
776            default:
777                throw new UnsupportedAlgorithmException(
778                    "The only supported hash algorithms are: md2, md5, sha1, sha256, sha384, sha512, sha224, sha512/224, sha512/256 - $hash provided"
779                );
780        }
781        $new->mgfHLen = $new->mgfHash->getLengthInBytes();
782
783        return $new;
784    }
785
786    /**
787     * Returns the MGF hash algorithm currently being used
788     *
789     */
790    public function getMGFHash()
791    {
792        return clone $this->mgfHash;
793    }
794
795    /**
796     * Determines the salt length
797     *
798     * Used by RSA::PADDING_PSS
799     *
800     * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
801     *
802     *    Typical salt lengths in octets are hLen (the length of the output
803     *    of the hash function Hash) and 0.
804     *
805     * @param int $sLen
806     */
807    public function withSaltLength($sLen)
808    {
809        $new = clone $this;
810        $new->sLen = $sLen;
811        return $new;
812    }
813
814    /**
815     * Returns the salt length currently being used
816     *
817     */
818    public function getSaltLength()
819    {
820        return $this->sLen !== null ? $this->sLen : $this->hLen;
821    }
822
823    /**
824     * Determines the label
825     *
826     * Used by RSA::PADDING_OAEP
827     *
828     * To quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
829     *
830     *    Both the encryption and the decryption operations of RSAES-OAEP take
831     *    the value of a label L as input.  In this version of PKCS #1, L is
832     *    the empty string; other uses of the label are outside the scope of
833     *    this document.
834     *
835     * @param string $label
836     */
837    public function withLabel($label)
838    {
839        $new = clone $this;
840        $new->label = $label;
841        return $new;
842    }
843
844    /**
845     * Returns the label currently being used
846     *
847     */
848    public function getLabel()
849    {
850        return $this->label;
851    }
852
853    /**
854     * Determines the padding modes
855     *
856     * Example: $key->withPadding(RSA::ENCRYPTION_PKCS1 | RSA::SIGNATURE_PKCS1);
857     *
858     * @param int $padding
859     */
860    public function withPadding($padding)
861    {
862        $masks = [
863            self::ENCRYPTION_OAEP,
864            self::ENCRYPTION_PKCS1,
865            self::ENCRYPTION_NONE
866        ];
867        $encryptedCount = 0;
868        $selected = 0;
869        foreach ($masks as $mask) {
870            if ($padding & $mask) {
871                $selected = $mask;
872                $encryptedCount++;
873            }
874        }
875        if ($encryptedCount > 1) {
876            throw new InconsistentSetupException('Multiple encryption padding modes have been selected; at most only one should be selected');
877        }
878        $encryptionPadding = $selected;
879
880        $masks = [
881            self::SIGNATURE_PSS,
882            self::SIGNATURE_RELAXED_PKCS1,
883            self::SIGNATURE_PKCS1
884        ];
885        $signatureCount = 0;
886        $selected = 0;
887        foreach ($masks as $mask) {
888            if ($padding & $mask) {
889                $selected = $mask;
890                $signatureCount++;
891            }
892        }
893        if ($signatureCount > 1) {
894            throw new InconsistentSetupException('Multiple signature padding modes have been selected; at most only one should be selected');
895        }
896        $signaturePadding = $selected;
897
898        $new = clone $this;
899        if ($encryptedCount) {
900            $new->encryptionPadding = $encryptionPadding;
901        }
902        if ($signatureCount) {
903            $new->signaturePadding = $signaturePadding;
904        }
905        return $new;
906    }
907
908    /**
909     * Returns the padding currently being used
910     *
911     */
912    public function getPadding()
913    {
914        return $this->signaturePadding | $this->encryptionPadding;
915    }
916
917    /**
918     * Enable RSA Blinding
919     *
920     */
921    public static function enableBlinding()
922    {
923        static::$enableBlinding = true;
924    }
925
926    /**
927     * Disable RSA Blinding
928     *
929     */
930    public static function disableBlinding()
931    {
932        static::$enableBlinding = false;
933    }
934
935    /**
936     * Handles OpenSSL encryption / decryption / signature creation / verification
937     *
938     * @param string $func
939     * @param string $message
940     * @param ?string $signature
941     * @return bool|string|null
942     */
943    protected function handleOpenSSL($func, $message, $signature = null)
944    {
945        switch ($func) {
946            case 'openssl_verify':
947            case 'openssl_sign':
948                $paddingType = 'signaturePadding';
949                break;
950            case 'openssl_public_encrypt':
951            case 'openssl_private_decrypt':
952                $paddingType = 'encryptionPadding';
953        }
954
955        if (self::$forcedEngine === 'libsodium') {
956            throw new BadConfigurationException('Engine libsodium is not supported for RSA');
957        }
958
959        if ((isset(self::$forcedEngine) && self::$forcedEngine !== 'PHP') && $this->$paddingType === self::SIGNATURE_RELAXED_PKCS1) {
960            throw new BadConfigurationException('Only the PHP engine can be used with relaxed PKCS1 padding');
961        }
962
963        if (self::$forcedEngine !== 'PHP') {
964            if (self::$forcedEngine === 'OpenSSL' && !function_exists($func)) {
965                throw new BadConfigurationException('Engine OpenSSL is forced but unavailable for RSA');
966            }
967            if ($this->$paddingType === self::SIGNATURE_PSS) {
968                switch (true) {
969                    case !defined('OPENSSL_PKCS1_PSS_PADDING'):
970                        $error = 'Engine OpenSSL is forced but PSS encryption requires PHP >= 8.5.0';
971                        break;
972                    case $this->hash->getHash() !== $this->mgfHash->getHash():
973                        $error = 'Engine OpenSSL is forced but can\'t be used because the Hash and MGF Hash do not match';
974                        break;
975                    case $this->getSaltLength() !== $this->hLen:
976                        $error = 'Engine OpenSSL is forced but can\'t be used because the salt length doesn\'t match the hash length';
977                }
978            }
979            /*
980            https://datatracker.ietf.org/doc/html/rfc4055#page-6 says the following:
981
982               There are two possible encodings for the AlgorithmIdentifier
983               parameters field associated with these object identifiers.  The two
984               alternatives arise from the loss of the OPTIONAL associated with the
985               algorithm identifier parameters when the 1988 syntax for
986               AlgorithmIdentifier was translated into the 1997 syntax.  Later the
987               OPTIONAL was recovered via a defect report, but by then many people
988               thought that algorithm parameters were mandatory.  Because of this
989               history some implementations encode parameters as a NULL element
990               while others omit them entirely.  The correct encoding is to omit the
991               parameters field; however, when RSASSA-PSS and RSAES-OAEP were
992               defined, it was done using the NULL parameters rather than absent
993               parameters.
994
995               All implementations MUST accept both NULL and absent parameters as
996               legal and equivalent encodings.
997
998            OpenSSL does NOT accept both - it REQUIRES NULL be present. phpseclib, however,
999            DOES accept both. at first, it didn't. at first, not knowing why some small number
1000            of PKCS1 signatures omitted NULL, i added the SIGNATURE_RELAXED_PKCS1 mode on
1001            2015-08-26. https://phpseclib.com/docs/rsa#rsasignature_relaxed_pkcs1 talks more
1002            about that mode. later, on 2021-04-05, there was CVE-2021-30130. consequently,
1003            the SIGNATURE_PKCS1 mode was updated to accept either NULL or non-NULL.
1004
1005            because phpseclib accepts PKCS1 signatures that OpenSSL doesn't, OpenSSL isn't
1006            used for PKCS1. if the OpenSSL extension is installed then it'll be used to perform
1007            unpadded RSA (ie. modular exponentiation), however, the actual PKCS1 construction
1008            takes place in PHP code vs OpenSSL.
1009
1010            see https://security.stackexchange.com/questions/110330/encoding-of-optional-null-in-der
1011            for an additional reference
1012            */
1013            if ($this->$paddingType === self::SIGNATURE_PKCS1 && $func === 'openssl_verify') {
1014                $error = 'Engine OpenSSL is forced but can\'t be used with PKCS1 signature verification because OpenSSL requires NULL be present whereas phpseclib doesn\'t';
1015            }
1016            if ($this->$paddingType === self::ENCRYPTION_OAEP) {
1017                switch (true) {
1018                    case $this->hash->getHash() !== $this->mgfHash->getHash():
1019                        $error = 'Engine OpenSSL is forced but can\'t be used because the Hash and MGF Hash do not match';
1020                        break;
1021                    case $this->hash->getHash() !== 'sha1' && PHP_VERSION_ID < 80500:
1022                        $error = 'Engine OpenSSL is forced but non-sha1 hashes are only supported on PHP 8.5.0+';
1023                        break;
1024                    case strlen($this->label):
1025                        $error = 'Engine OpenSSL is forced but can\'t be used because the label is not the empty string';
1026                }
1027            }
1028            if (isset($error)) {
1029                if (self::$forcedEngine === 'OpenSSL') {
1030                    throw new BadConfigurationException($error);
1031                }
1032            } elseif ($paddingType === 'signaturePadding') {
1033                switch (true) {
1034                    case $this->signaturePadding === self::SIGNATURE_PSS && defined('OPENSSL_PKCS1_PSS_PADDING'):
1035                    case $this->signaturePadding !== self::SIGNATURE_PSS && function_exists($func):
1036                        $key = $this instanceof PrivateKey ?
1037                            $this->withPassword()->toString('PKCS8') :
1038                            $this->toString('PKCS8');
1039                        if ($func === 'openssl_sign' && strpos($key, 'PUBLIC') !== false) {
1040                            if (self::$forcedEngine === 'OpenSSL') {
1041                                throw new BadConfigurationException('Engine OpenSSL is forced but cannot be used because the private key does not have the prime components within it');
1042                            }
1043                            break;
1044                        }
1045                        $hash = $this->hash->getHash();
1046
1047                        // on github actions, php 7.0 and 7.1 on windows emit the following warning:
1048                        // openssl_sign(): supplied key param cannot be coerced into a private key
1049                        set_error_handler(function ($errno, $errstr) {
1050                            throw new BadConfigurationException("Engine OpenSSL is forced but got error: $errstr");
1051                        });
1052                        try {
1053                            $result = $this->signaturePadding === self::SIGNATURE_PSS ?
1054                                $func($message, $signature, $key, $hash, OPENSSL_PKCS1_PSS_PADDING) :
1055                                $func($message, $signature, $key, $hash);
1056                        } catch (BadConfigurationException $e) {
1057                            if (self::$forcedEngine === 'OpenSSL') {
1058                                throw $e;
1059                            }
1060                            $result = false;
1061                        } finally {
1062                            restore_error_handler();
1063                        }
1064
1065                        if ($func === 'openssl_verify' && $result !== -1 && $result !== false) {
1066                            return (bool) $result;
1067                        }
1068                        if ($result) {
1069                            return $signature;
1070                        }
1071                        if (self::$forcedEngine === 'OpenSSL') {
1072                            throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string());
1073                        }
1074                }
1075            } else {
1076                if ($this->encryptionPadding !== self::ENCRYPTION_OAEP || PHP_VERSION_ID >= 80500) {
1077                    $key = $this instanceof PrivateKey ?
1078                        $this->withPassword()->toString('PKCS8') :
1079                        $this->toString('PKCS8');
1080                    if ($func === 'openssl_private_decrypt' && strpos($key, 'PUBLIC') !== false) {
1081                        if ($this->encryptionPadding === self::ENCRYPTION_OAEP) {
1082                            if (self::$forcedEngine === 'OpenSSL') {
1083                                throw new BadConfigurationException('Engine OpenSSL is forced but cannot be used because openssl_public_decrypt() doesn\'t have a hash parameter like openssl_private_decrypt() does');
1084                            }
1085                            return null;
1086                        }
1087                        $func = 'openssl_public_decrypt';
1088                    }
1089                    if ($this->encryptionPadding === self::ENCRYPTION_PKCS1 && OPENSSL_VERSION_NUMBER >= 0x30200000) {
1090                        // quoting https://docs.openssl.org/3.4/man3/RSA_public_encrypt/#return-values :
1091                        //
1092                        // "Since version 3.2.0, the default provider in OpenSSL does not return an error when padding checks fail.
1093                        //  Instead it generates a random message"
1094                        //
1095                        // the idea is that even a perfect implementation of PKCS1 padding can be used to conduct a Bleichenbacher
1096                        // padding oracle attack.
1097                        //
1098                        // so like if $rsa->decrypt() doesn't throw an exception it's liable to run additional code that'll take
1099                        // longer to run than it'd take if an exception would be thrown and in theory, with PKCS1, in particular,
1100                        // you can use that fact to guess at successive bits of the private key until you've figured it out. it's
1101                        // why you should use OAEP padding vs PKCS1 padding BUT if you need PKCS1 padding for interoperability then
1102                        // you're stuck with it.
1103                        //
1104                        // with the OpenSSL 3.2.0+ behavior they're making it harder to do the attack by making it harder to use PKCS1
1105                        // in the real world. this isn't a design philosophy i agree with. like phpseclib lets you DES encryption. you
1106                        // shouldn't use DES encryption but if you need to you need to and phpseclib isn't here to judge. that's a big
1107                        // difference between phpseclib and stuff like libsodium.
1108                        if (self::$forcedEngine === 'OpenSSL') {
1109                            throw new BadConfigurationException('Engine OpenSSL is forced but cannot be used to decrypt PKCS1 encrypted strings with OpenSSL 3.2.0+');
1110                        }
1111                        return null;
1112                    }
1113                    $hash = $this->hash->getHash();
1114                    $output = '';
1115                    switch ($this->encryptionPadding) {
1116                        case self::ENCRYPTION_NONE:
1117                        case self::ENCRYPTION_PKCS1:
1118                            $padding = $this->encryptionPadding === self::ENCRYPTION_NONE ? OPENSSL_NO_PADDING : OPENSSL_PKCS1_PADDING;
1119                            // on github actions, php 7.0 and 7.1 on windows emit the following warning:
1120                            // openssl_private_decrypt(): key parameter is not a valid private key
1121                            set_error_handler(function ($errno, $errstr) {
1122                                throw new BadConfigurationException("Engine OpenSSL is forced but got error: $errstr");
1123                            });
1124                            try {
1125                                $result = $func($message, $output, $key, $padding);
1126                            } catch (BadConfigurationException $e) {
1127                                if (self::$forcedEngine === 'OpenSSL') {
1128                                    throw $e;
1129                                }
1130                                $result = false;
1131                            } finally {
1132                                restore_error_handler();
1133                            }
1134                            break;
1135                        //case self::ENCRYPTION_OAEP:
1136                        default:
1137                            $result = $func($message, $output, $key, OPENSSL_PKCS1_OAEP_PADDING, $hash);
1138                    }
1139                    if ($result) {
1140                        return $output;
1141                    }
1142                }
1143            }
1144            return null;
1145        }
1146    }
1147}
1148