[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/ -> PrivateKey.php (source)

   1  <?php
   2  
   3  /**
   4   * RSA Private Key
   5   *
   6   * @category  Crypt
   7   * @package   RSA
   8   * @author    Jim Wigginton <[email protected]>
   9   * @copyright 2015 Jim Wigginton
  10   * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
  11   * @link      http://phpseclib.sourceforge.net
  12   */
  13  
  14  namespace phpseclib3\Crypt\RSA;
  15  
  16  use phpseclib3\Crypt\Common;
  17  use phpseclib3\Crypt\Random;
  18  use phpseclib3\Crypt\RSA;
  19  use phpseclib3\Crypt\RSA\Formats\Keys\PSS;
  20  use phpseclib3\Exception\UnsupportedFormatException;
  21  use phpseclib3\Math\BigInteger;
  22  
  23  /**
  24   * Raw RSA Key Handler
  25   *
  26   * @package RSA
  27   * @author  Jim Wigginton <[email protected]>
  28   * @access  public
  29   */
  30  class PrivateKey extends RSA implements Common\PrivateKey
  31  {
  32      use Common\Traits\PasswordProtected;
  33  
  34      /**
  35       * Primes for Chinese Remainder Theorem (ie. p and q)
  36       *
  37       * @var array
  38       * @access private
  39       */
  40      protected $primes;
  41  
  42      /**
  43       * Exponents for Chinese Remainder Theorem (ie. dP and dQ)
  44       *
  45       * @var array
  46       * @access private
  47       */
  48      protected $exponents;
  49  
  50      /**
  51       * Coefficients for Chinese Remainder Theorem (ie. qInv)
  52       *
  53       * @var array
  54       * @access private
  55       */
  56      protected $coefficients;
  57  
  58      /**
  59       * Public Exponent
  60       *
  61       * @var mixed
  62       * @access private
  63       */
  64      protected $publicExponent = false;
  65  
  66      /**
  67       * RSADP
  68       *
  69       * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
  70       *
  71       * @access private
  72       * @param \phpseclib3\Math\BigInteger $c
  73       * @return bool|\phpseclib3\Math\BigInteger
  74       */
  75      private function rsadp($c)
  76      {
  77          if ($c->compare(self::$zero) < 0 || $c->compare($this->modulus) > 0) {
  78              throw new \OutOfRangeException('Ciphertext representative out of range');
  79          }
  80          return $this->exponentiate($c);
  81      }
  82  
  83      /**
  84       * RSASP1
  85       *
  86       * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
  87       *
  88       * @access private
  89       * @param \phpseclib3\Math\BigInteger $m
  90       * @return bool|\phpseclib3\Math\BigInteger
  91       */
  92      private function rsasp1($m)
  93      {
  94          if ($m->compare(self::$zero) < 0 || $m->compare($this->modulus) > 0) {
  95              throw new \OutOfRangeException('Signature representative out of range');
  96          }
  97          return $this->exponentiate($m);
  98      }
  99  
 100      /**
 101       * Exponentiate
 102       *
 103       * @param \phpseclib3\Math\BigInteger $x
 104       * @return \phpseclib3\Math\BigInteger
 105       */
 106      protected function exponentiate(BigInteger $x)
 107      {
 108          switch (true) {
 109              case empty($this->primes):
 110              case $this->primes[1]->equals(self::$zero):
 111              case empty($this->coefficients):
 112              case $this->coefficients[2]->equals(self::$zero):
 113              case empty($this->exponents):
 114              case $this->exponents[1]->equals(self::$zero):
 115                  return $x->modPow($this->exponent, $this->modulus);
 116          }
 117  
 118          $num_primes = count($this->primes);
 119  
 120          if (!static::$enableBlinding) {
 121              $m_i = [
 122                  1 => $x->modPow($this->exponents[1], $this->primes[1]),
 123                  2 => $x->modPow($this->exponents[2], $this->primes[2])
 124              ];
 125              $h = $m_i[1]->subtract($m_i[2]);
 126              $h = $h->multiply($this->coefficients[2]);
 127              list(, $h) = $h->divide($this->primes[1]);
 128              $m = $m_i[2]->add($h->multiply($this->primes[2]));
 129  
 130              $r = $this->primes[1];
 131              for ($i = 3; $i <= $num_primes; $i++) {
 132                  $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
 133  
 134                  $r = $r->multiply($this->primes[$i - 1]);
 135  
 136                  $h = $m_i->subtract($m);
 137                  $h = $h->multiply($this->coefficients[$i]);
 138                  list(, $h) = $h->divide($this->primes[$i]);
 139  
 140                  $m = $m->add($r->multiply($h));
 141              }
 142          } else {
 143              $smallest = $this->primes[1];
 144              for ($i = 2; $i <= $num_primes; $i++) {
 145                  if ($smallest->compare($this->primes[$i]) > 0) {
 146                      $smallest = $this->primes[$i];
 147                  }
 148              }
 149  
 150              $r = BigInteger::randomRange(self::$one, $smallest->subtract(self::$one));
 151  
 152              $m_i = [
 153                  1 => $this->blind($x, $r, 1),
 154                  2 => $this->blind($x, $r, 2)
 155              ];
 156              $h = $m_i[1]->subtract($m_i[2]);
 157              $h = $h->multiply($this->coefficients[2]);
 158              list(, $h) = $h->divide($this->primes[1]);
 159              $m = $m_i[2]->add($h->multiply($this->primes[2]));
 160  
 161              $r = $this->primes[1];
 162              for ($i = 3; $i <= $num_primes; $i++) {
 163                  $m_i = $this->blind($x, $r, $i);
 164  
 165                  $r = $r->multiply($this->primes[$i - 1]);
 166  
 167                  $h = $m_i->subtract($m);
 168                  $h = $h->multiply($this->coefficients[$i]);
 169                  list(, $h) = $h->divide($this->primes[$i]);
 170  
 171                  $m = $m->add($r->multiply($h));
 172              }
 173          }
 174  
 175          return $m;
 176      }
 177  
 178      /**
 179       * Performs RSA Blinding
 180       *
 181       * Protects against timing attacks by employing RSA Blinding.
 182       * Returns $x->modPow($this->exponents[$i], $this->primes[$i])
 183       *
 184       * @access private
 185       * @param \phpseclib3\Math\BigInteger $x
 186       * @param \phpseclib3\Math\BigInteger $r
 187       * @param int $i
 188       * @return \phpseclib3\Math\BigInteger
 189       */
 190      private function blind($x, $r, $i)
 191      {
 192          $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
 193          $x = $x->modPow($this->exponents[$i], $this->primes[$i]);
 194  
 195          $r = $r->modInverse($this->primes[$i]);
 196          $x = $x->multiply($r);
 197          list(, $x) = $x->divide($this->primes[$i]);
 198  
 199          return $x;
 200      }
 201  
 202      /**
 203       * EMSA-PSS-ENCODE
 204       *
 205       * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
 206       *
 207       * @return string
 208       * @access private
 209       * @param string $m
 210       * @throws \RuntimeException on encoding error
 211       * @param int $emBits
 212       */
 213      private function emsa_pss_encode($m, $emBits)
 214      {
 215          // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
 216          // be output.
 217  
 218          $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
 219          $sLen = $this->sLen !== null ? $this->sLen : $this->hLen;
 220  
 221          $mHash = $this->hash->hash($m);
 222          if ($emLen < $this->hLen + $sLen + 2) {
 223              throw new \LengthException('RSA modulus too short');
 224          }
 225  
 226          $salt = Random::string($sLen);
 227          $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
 228          $h = $this->hash->hash($m2);
 229          $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
 230          $db = $ps . chr(1) . $salt;
 231          $dbMask = $this->mgf1($h, $emLen - $this->hLen - 1); // ie. stlren($db)
 232          $maskedDB = $db ^ $dbMask;
 233          $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
 234          $em = $maskedDB . $h . chr(0xBC);
 235  
 236          return $em;
 237      }
 238  
 239      /**
 240       * RSASSA-PSS-SIGN
 241       *
 242       * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
 243       *
 244       * @access private
 245       * @param string $m
 246       * @return bool|string
 247       */
 248      private function rsassa_pss_sign($m)
 249      {
 250          // EMSA-PSS encoding
 251  
 252          $em = $this->emsa_pss_encode($m, 8 * $this->k - 1);
 253  
 254          // RSA signature
 255  
 256          $m = $this->os2ip($em);
 257          $s = $this->rsasp1($m);
 258          $s = $this->i2osp($s, $this->k);
 259  
 260          // Output the signature S
 261  
 262          return $s;
 263      }
 264  
 265      /**
 266       * RSASSA-PKCS1-V1_5-SIGN
 267       *
 268       * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
 269       *
 270       * @access private
 271       * @param string $m
 272       * @throws \LengthException if the RSA modulus is too short
 273       * @return bool|string
 274       */
 275      private function rsassa_pkcs1_v1_5_sign($m)
 276      {
 277          // EMSA-PKCS1-v1_5 encoding
 278  
 279          // If the encoding operation outputs "intended encoded message length too short," output "RSA modulus
 280          // too short" and stop.
 281          try {
 282              $em = $this->emsa_pkcs1_v1_5_encode($m, $this->k);
 283          } catch (\LengthException $e) {
 284              throw new \LengthException('RSA modulus too short');
 285          }
 286  
 287          // RSA signature
 288  
 289          $m = $this->os2ip($em);
 290          $s = $this->rsasp1($m);
 291          $s = $this->i2osp($s, $this->k);
 292  
 293          // Output the signature S
 294  
 295          return $s;
 296      }
 297  
 298      /**
 299       * Create a signature
 300       *
 301       * @see self::verify()
 302       * @access public
 303       * @param string $message
 304       * @return string
 305       */
 306      public function sign($message)
 307      {
 308          switch ($this->signaturePadding) {
 309              case self::SIGNATURE_PKCS1:
 310              case self::SIGNATURE_RELAXED_PKCS1:
 311                  return $this->rsassa_pkcs1_v1_5_sign($message);
 312              //case self::SIGNATURE_PSS:
 313              default:
 314                  return $this->rsassa_pss_sign($message);
 315          }
 316      }
 317  
 318      /**
 319       * RSAES-PKCS1-V1_5-DECRYPT
 320       *
 321       * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
 322       *
 323       * @access private
 324       * @param string $c
 325       * @return bool|string
 326       */
 327      private function rsaes_pkcs1_v1_5_decrypt($c)
 328      {
 329          // Length checking
 330  
 331          if (strlen($c) != $this->k) { // or if k < 11
 332              throw new \LengthException('Ciphertext representative too long');
 333          }
 334  
 335          // RSA decryption
 336  
 337          $c = $this->os2ip($c);
 338          $m = $this->rsadp($c);
 339          $em = $this->i2osp($m, $this->k);
 340  
 341          // EME-PKCS1-v1_5 decoding
 342  
 343          if (ord($em[0]) != 0 || ord($em[1]) > 2) {
 344              throw new \RuntimeException('Decryption error');
 345          }
 346  
 347          $ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
 348          $m = substr($em, strlen($ps) + 3);
 349  
 350          if (strlen($ps) < 8) {
 351              throw new \RuntimeException('Decryption error');
 352          }
 353  
 354          // Output M
 355  
 356          return $m;
 357      }
 358  
 359      /**
 360       * RSAES-OAEP-DECRYPT
 361       *
 362       * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}.  The fact that the error
 363       * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
 364       *
 365       *    Note.  Care must be taken to ensure that an opponent cannot
 366       *    distinguish the different error conditions in Step 3.g, whether by
 367       *    error message or timing, or, more generally, learn partial
 368       *    information about the encoded message EM.  Otherwise an opponent may
 369       *    be able to obtain useful information about the decryption of the
 370       *    ciphertext C, leading to a chosen-ciphertext attack such as the one
 371       *    observed by Manger [36].
 372       *
 373       * @access private
 374       * @param string $c
 375       * @return bool|string
 376       */
 377      private function rsaes_oaep_decrypt($c)
 378      {
 379          // Length checking
 380  
 381          // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
 382          // be output.
 383  
 384          if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
 385              throw new \LengthException('Ciphertext representative too long');
 386          }
 387  
 388          // RSA decryption
 389  
 390          $c = $this->os2ip($c);
 391          $m = $this->rsadp($c);
 392          $em = $this->i2osp($m, $this->k);
 393  
 394          // EME-OAEP decoding
 395  
 396          $lHash = $this->hash->hash($this->label);
 397          $y = ord($em[0]);
 398          $maskedSeed = substr($em, 1, $this->hLen);
 399          $maskedDB = substr($em, $this->hLen + 1);
 400          $seedMask = $this->mgf1($maskedDB, $this->hLen);
 401          $seed = $maskedSeed ^ $seedMask;
 402          $dbMask = $this->mgf1($seed, $this->k - $this->hLen - 1);
 403          $db = $maskedDB ^ $dbMask;
 404          $lHash2 = substr($db, 0, $this->hLen);
 405          $m = substr($db, $this->hLen);
 406          $hashesMatch = hash_equals($lHash, $lHash2);
 407          $leadingZeros = 1;
 408          $patternMatch = 0;
 409          $offset = 0;
 410          for ($i = 0; $i < strlen($m); $i++) {
 411              $patternMatch |= $leadingZeros & ($m[$i] === "\1");
 412              $leadingZeros &= $m[$i] === "\0";
 413              $offset += $patternMatch ? 0 : 1;
 414          }
 415  
 416          // we do | instead of || to avoid https://en.wikipedia.org/wiki/Short-circuit_evaluation
 417          // to protect against timing attacks
 418          if (!$hashesMatch | !$patternMatch) {
 419              throw new \RuntimeException('Decryption error');
 420          }
 421  
 422          // Output the message M
 423  
 424          return substr($m, $offset + 1);
 425      }
 426  
 427      /**
 428       * Raw Encryption / Decryption
 429       *
 430       * Doesn't use padding and is not recommended.
 431       *
 432       * @access private
 433       * @param string $m
 434       * @return bool|string
 435       * @throws \LengthException if strlen($m) > $this->k
 436       */
 437      private function raw_encrypt($m)
 438      {
 439          if (strlen($m) > $this->k) {
 440              throw new \LengthException('Ciphertext representative too long');
 441          }
 442  
 443          $temp = $this->os2ip($m);
 444          $temp = $this->rsadp($temp);
 445          return  $this->i2osp($temp, $this->k);
 446      }
 447  
 448      /**
 449       * Decryption
 450       *
 451       * @see self::encrypt()
 452       * @access public
 453       * @param string $ciphertext
 454       * @return bool|string
 455       */
 456      public function decrypt($ciphertext)
 457      {
 458          switch ($this->encryptionPadding) {
 459              case self::ENCRYPTION_NONE:
 460                  return $this->raw_encrypt($ciphertext);
 461              case self::ENCRYPTION_PKCS1:
 462                  return $this->rsaes_pkcs1_v1_5_decrypt($ciphertext);
 463              //case self::ENCRYPTION_OAEP:
 464              default:
 465                  return $this->rsaes_oaep_decrypt($ciphertext);
 466          }
 467      }
 468  
 469      /**
 470       * Returns the public key
 471       *
 472       * @access public
 473       * @return mixed
 474       */
 475      public function getPublicKey()
 476      {
 477          $type = self::validatePlugin('Keys', 'PKCS8', 'savePublicKey');
 478          if (empty($this->modulus) || empty($this->publicExponent)) {
 479              throw new \RuntimeException('Public key components not found');
 480          }
 481  
 482          $key = $type::savePublicKey($this->modulus, $this->publicExponent);
 483          return RSA::loadFormat('PKCS8', $key)
 484              ->withHash($this->hash->getHash())
 485              ->withMGFHash($this->mgfHash->getHash())
 486              ->withSaltLength($this->sLen)
 487              ->withLabel($this->label)
 488              ->withPadding($this->signaturePadding | $this->encryptionPadding);
 489      }
 490  
 491      /**
 492       * Returns the private key
 493       *
 494       * @param string $type
 495       * @param array $options optional
 496       * @return string
 497       */
 498      public function toString($type, array $options = [])
 499      {
 500          $type = self::validatePlugin(
 501              'Keys',
 502              $type,
 503              empty($this->primes) ? 'savePublicKey' : 'savePrivateKey'
 504          );
 505  
 506          if ($type == PSS::class) {
 507              if ($this->signaturePadding == self::SIGNATURE_PSS) {
 508                  $options += [
 509                      'hash' => $this->hash->getHash(),
 510                      'MGFHash' => $this->mgfHash->getHash(),
 511                      'saltLength' => $this->getSaltLength()
 512                  ];
 513              } else {
 514                  throw new UnsupportedFormatException('The PSS format can only be used when the signature method has been explicitly set to PSS');
 515              }
 516          }
 517  
 518          if (empty($this->primes)) {
 519              return $type::savePublicKey($this->modulus, $this->exponent, $options);
 520          }
 521  
 522          return $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients, $this->password, $options);
 523  
 524          /*
 525          $key = $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients, $this->password, $options);
 526          if ($key !== false || count($this->primes) == 2) {
 527              return $key;
 528          }
 529  
 530          $nSize = $this->getSize() >> 1;
 531  
 532          $primes = [1 => clone self::$one, clone self::$one];
 533          $i = 1;
 534          foreach ($this->primes as $prime) {
 535              $primes[$i] = $primes[$i]->multiply($prime);
 536              if ($primes[$i]->getLength() >= $nSize) {
 537                  $i++;
 538              }
 539          }
 540  
 541          $exponents = [];
 542          $coefficients = [2 => $primes[2]->modInverse($primes[1])];
 543  
 544          foreach ($primes as $i => $prime) {
 545              $temp = $prime->subtract(self::$one);
 546              $exponents[$i] = $this->modulus->modInverse($temp);
 547          }
 548  
 549          return $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $primes, $exponents, $coefficients, $this->password, $options);
 550          */
 551      }
 552  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer