xref: /dokuwiki/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php (revision a896ec97b4d9a77a7ab6956f96aaa0e7987f57d1)
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            if ($this->$paddingType === self::ENCRYPTION_OAEP) {
980                switch (true) {
981                    case $this->hash->getHash() !== $this->mgfHash->getHash():
982                        $error = 'Engine OpenSSL is forced but can\'t be used because the Hash and MGF Hash do not match';
983                        break;
984                    case $this->hash->getHash() !== 'sha1' && PHP_VERSION_ID < 80500:
985                        $error = 'Engine OpenSSL is forced but non-sha1 hashes are only supported on PHP 8.5.0+';
986                        break;
987                    case strlen($this->label):
988                        $error = 'Engine OpenSSL is forced but can\'t be used because the label is not the empty string';
989                }
990            }
991            if (isset($error)) {
992                if (self::$forcedEngine === 'OpenSSL') {
993                    throw new BadConfigurationException($error);
994                }
995            } elseif ($paddingType === 'signaturePadding') {
996                switch (true) {
997                    case $this->signaturePadding === self::SIGNATURE_PSS && defined('OPENSSL_PKCS1_PSS_PADDING'):
998                    case $this->signaturePadding !== self::SIGNATURE_PSS && function_exists($func):
999                        $key = $this instanceof PrivateKey ?
1000                            $this->withPassword()->toString('PKCS8') :
1001                            $this->toString('PKCS8');
1002                        if ($func === 'openssl_sign' && strpos($key, 'PUBLIC') !== false) {
1003                            if (self::$forcedEngine === 'OpenSSL') {
1004                                throw new BadConfigurationException('Engine OpenSSL is forced but cannot be used because the private key does not have the prime components within it');
1005                            }
1006                            break;
1007                        }
1008                        $hash = $this->hash->getHash();
1009
1010                        // on github actions, php 7.0 and 7.1 on windows emit the following warning:
1011                        // openssl_sign(): supplied key param cannot be coerced into a private key
1012                        set_error_handler(function ($errno, $errstr) {
1013                            throw new BadConfigurationException("Engine OpenSSL is forced but got error: $errstr");
1014                        });
1015                        try {
1016                            $result = $this->signaturePadding === self::SIGNATURE_PSS ?
1017                                $func($message, $signature, $key, $hash, OPENSSL_PKCS1_PSS_PADDING) :
1018                                $func($message, $signature, $key, $hash);
1019                        } catch (BadConfigurationException $e) {
1020                            if (self::$forcedEngine === 'OpenSSL') {
1021                                throw $e;
1022                            }
1023                            $result = false;
1024                        } finally {
1025                            restore_error_handler();
1026                        }
1027
1028                        if ($func === 'openssl_verify' && $result !== -1 && $result !== false) {
1029                            return (bool) $result;
1030                        }
1031                        if ($result) {
1032                            return $signature;
1033                        }
1034                        if (self::$forcedEngine === 'OpenSSL') {
1035                            throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string());
1036                        }
1037                }
1038            } else {
1039                if ($this->encryptionPadding !== self::ENCRYPTION_OAEP || PHP_VERSION_ID >= 80500) {
1040                    $key = $this->toString('PKCS8');
1041                    if ($func === 'openssl_private_decrypt' && strpos($key, 'PUBLIC') !== false) {
1042                        if ($this->encryptionPadding === self::ENCRYPTION_OAEP) {
1043                            if (self::$forcedEngine === 'OpenSSL') {
1044                                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');
1045                            }
1046                            return null;
1047                        }
1048                        $func = 'openssl_public_decrypt';
1049                    }
1050                    $hash = $this->hash->getHash();
1051                    $output = '';
1052                    switch ($this->encryptionPadding) {
1053                        case self::ENCRYPTION_NONE:
1054                        case self::ENCRYPTION_PKCS1:
1055                            $padding = $this->encryptionPadding === self::ENCRYPTION_NONE ? OPENSSL_NO_PADDING : OPENSSL_PKCS1_PADDING;
1056                            $result = $func($message, $output, $key, $padding);
1057                            break;
1058                        //case self::ENCRYPTION_OAEP:
1059                        default:
1060                            $result = $func($message, $output, $key, OPENSSL_PKCS1_OAEP_PADDING, $hash);
1061                    }
1062                    if ($result) {
1063                        return $output;
1064                    }
1065                }
1066            }
1067            return null;
1068        }
1069    }
1070}
1071