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