[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/web-token/jwt-core/Util/ -> RSAKey.php (source)

   1  <?php
   2  
   3  declare(strict_types=1);
   4  
   5  /*
   6   * The MIT License (MIT)
   7   *
   8   * Copyright (c) 2014-2020 Spomky-Labs
   9   *
  10   * This software may be modified and distributed under the terms
  11   * of the MIT license.  See the LICENSE file for details.
  12   */
  13  
  14  namespace Jose\Component\Core\Util;
  15  
  16  use function array_key_exists;
  17  use Base64Url\Base64Url;
  18  use function count;
  19  use FG\ASN1\Universal\BitString;
  20  use FG\ASN1\Universal\Integer;
  21  use FG\ASN1\Universal\NullObject;
  22  use FG\ASN1\Universal\ObjectIdentifier;
  23  use FG\ASN1\Universal\OctetString;
  24  use FG\ASN1\Universal\Sequence;
  25  use InvalidArgumentException;
  26  use function is_array;
  27  use Jose\Component\Core\JWK;
  28  use RuntimeException;
  29  
  30  /**
  31   * @internal
  32   */
  33  class RSAKey
  34  {
  35      /**
  36       * @var Sequence
  37       */
  38      private $sequence;
  39  
  40      /**
  41       * @var bool
  42       */
  43      private $private;
  44  
  45      /**
  46       * @var array
  47       */
  48      private $values;
  49  
  50      /**
  51       * @var BigInteger
  52       */
  53      private $modulus;
  54  
  55      /**
  56       * @var int
  57       */
  58      private $modulus_length;
  59  
  60      /**
  61       * @var BigInteger
  62       */
  63      private $public_exponent;
  64  
  65      /**
  66       * @var null|BigInteger
  67       */
  68      private $private_exponent;
  69  
  70      /**
  71       * @var BigInteger[]
  72       */
  73      private $primes = [];
  74  
  75      /**
  76       * @var BigInteger[]
  77       */
  78      private $exponents = [];
  79  
  80      /**
  81       * @var null|BigInteger
  82       */
  83      private $coefficient;
  84  
  85      private function __construct(JWK $data)
  86      {
  87          $this->values = $data->all();
  88          $this->populateBigIntegers();
  89          $this->private = array_key_exists('d', $this->values);
  90      }
  91  
  92      /**
  93       * @return RSAKey
  94       */
  95      public static function createFromJWK(JWK $jwk): self
  96      {
  97          return new self($jwk);
  98      }
  99  
 100      public function getModulus(): BigInteger
 101      {
 102          return $this->modulus;
 103      }
 104  
 105      public function getModulusLength(): int
 106      {
 107          return $this->modulus_length;
 108      }
 109  
 110      public function getExponent(): BigInteger
 111      {
 112          $d = $this->getPrivateExponent();
 113          if (null !== $d) {
 114              return $d;
 115          }
 116  
 117          return $this->getPublicExponent();
 118      }
 119  
 120      public function getPublicExponent(): BigInteger
 121      {
 122          return $this->public_exponent;
 123      }
 124  
 125      public function getPrivateExponent(): ?BigInteger
 126      {
 127          return $this->private_exponent;
 128      }
 129  
 130      /**
 131       * @return BigInteger[]
 132       */
 133      public function getPrimes(): array
 134      {
 135          return $this->primes;
 136      }
 137  
 138      /**
 139       * @return BigInteger[]
 140       */
 141      public function getExponents(): array
 142      {
 143          return $this->exponents;
 144      }
 145  
 146      public function getCoefficient(): ?BigInteger
 147      {
 148          return $this->coefficient;
 149      }
 150  
 151      public function isPublic(): bool
 152      {
 153          return !array_key_exists('d', $this->values);
 154      }
 155  
 156      /**
 157       * @param RSAKey $private
 158       *
 159       * @return RSAKey
 160       */
 161      public static function toPublic(self $private): self
 162      {
 163          $data = $private->toArray();
 164          $keys = ['p', 'd', 'q', 'dp', 'dq', 'qi'];
 165          foreach ($keys as $key) {
 166              if (array_key_exists($key, $data)) {
 167                  unset($data[$key]);
 168              }
 169          }
 170  
 171          return new self(new JWK($data));
 172      }
 173  
 174      public function toArray(): array
 175      {
 176          return $this->values;
 177      }
 178  
 179      public function toPEM(): string
 180      {
 181          if (null === $this->sequence) {
 182              $this->sequence = new Sequence();
 183              if (array_key_exists('d', $this->values)) {
 184                  $this->initPrivateKey();
 185              } else {
 186                  $this->initPublicKey();
 187              }
 188          }
 189          $result = '-----BEGIN '.($this->private ? 'RSA PRIVATE' : 'PUBLIC').' KEY-----'.PHP_EOL;
 190          $result .= chunk_split(base64_encode($this->sequence->getBinary()), 64, PHP_EOL);
 191          $result .= '-----END '.($this->private ? 'RSA PRIVATE' : 'PUBLIC').' KEY-----'.PHP_EOL;
 192  
 193          return $result;
 194      }
 195  
 196      /**
 197       * Exponentiate with or without Chinese Remainder Theorem.
 198       * Operation with primes 'p' and 'q' is appox. 2x faster.
 199       *
 200       * @param RSAKey $key
 201       *
 202       * @throws RuntimeException if the exponentiation cannot be achieved
 203       */
 204      public static function exponentiate(self $key, BigInteger $c): BigInteger
 205      {
 206          if ($c->compare(BigInteger::createFromDecimal(0)) < 0 || $c->compare($key->getModulus()) > 0) {
 207              throw new RuntimeException();
 208          }
 209          if ($key->isPublic() || null === $key->getCoefficient() || 0 === count($key->getPrimes()) || 0 === count($key->getExponents())) {
 210              return $c->modPow($key->getExponent(), $key->getModulus());
 211          }
 212  
 213          $p = $key->getPrimes()[0];
 214          $q = $key->getPrimes()[1];
 215          $dP = $key->getExponents()[0];
 216          $dQ = $key->getExponents()[1];
 217          $qInv = $key->getCoefficient();
 218  
 219          $m1 = $c->modPow($dP, $p);
 220          $m2 = $c->modPow($dQ, $q);
 221          $h = $qInv->multiply($m1->subtract($m2)->add($p))->mod($p);
 222  
 223          return $m2->add($h->multiply($q));
 224      }
 225  
 226      private function populateBigIntegers(): void
 227      {
 228          $this->modulus = $this->convertBase64StringToBigInteger($this->values['n']);
 229          $this->modulus_length = mb_strlen($this->getModulus()->toBytes(), '8bit');
 230          $this->public_exponent = $this->convertBase64StringToBigInteger($this->values['e']);
 231  
 232          if (!$this->isPublic()) {
 233              $this->private_exponent = $this->convertBase64StringToBigInteger($this->values['d']);
 234  
 235              if (array_key_exists('p', $this->values) && array_key_exists('q', $this->values)) {
 236                  $this->primes = [
 237                      $this->convertBase64StringToBigInteger($this->values['p']),
 238                      $this->convertBase64StringToBigInteger($this->values['q']),
 239                  ];
 240                  if (array_key_exists('dp', $this->values) && array_key_exists('dq', $this->values) && array_key_exists('qi', $this->values)) {
 241                      $this->exponents = [
 242                          $this->convertBase64StringToBigInteger($this->values['dp']),
 243                          $this->convertBase64StringToBigInteger($this->values['dq']),
 244                      ];
 245                      $this->coefficient = $this->convertBase64StringToBigInteger($this->values['qi']);
 246                  }
 247              }
 248          }
 249      }
 250  
 251      private function convertBase64StringToBigInteger(string $value): BigInteger
 252      {
 253          return BigInteger::createFromBinaryString(Base64Url::decode($value));
 254      }
 255  
 256      private function initPublicKey(): void
 257      {
 258          $oid_sequence = new Sequence();
 259          $oid_sequence->addChild(new ObjectIdentifier('1.2.840.113549.1.1.1'));
 260          $oid_sequence->addChild(new NullObject());
 261          $this->sequence->addChild($oid_sequence);
 262          $n = new Integer($this->fromBase64ToInteger($this->values['n']));
 263          $e = new Integer($this->fromBase64ToInteger($this->values['e']));
 264          $key_sequence = new Sequence();
 265          $key_sequence->addChild($n);
 266          $key_sequence->addChild($e);
 267          $key_bit_string = new BitString(bin2hex($key_sequence->getBinary()));
 268          $this->sequence->addChild($key_bit_string);
 269      }
 270  
 271      private function initPrivateKey(): void
 272      {
 273          $this->sequence->addChild(new Integer(0));
 274          $oid_sequence = new Sequence();
 275          $oid_sequence->addChild(new ObjectIdentifier('1.2.840.113549.1.1.1'));
 276          $oid_sequence->addChild(new NullObject());
 277          $this->sequence->addChild($oid_sequence);
 278          $v = new Integer(0);
 279          $n = new Integer($this->fromBase64ToInteger($this->values['n']));
 280          $e = new Integer($this->fromBase64ToInteger($this->values['e']));
 281          $d = new Integer($this->fromBase64ToInteger($this->values['d']));
 282          $p = new Integer($this->fromBase64ToInteger($this->values['p']));
 283          $q = new Integer($this->fromBase64ToInteger($this->values['q']));
 284          $dp = array_key_exists('dp', $this->values) ? new Integer($this->fromBase64ToInteger($this->values['dp'])) : new Integer(0);
 285          $dq = array_key_exists('dq', $this->values) ? new Integer($this->fromBase64ToInteger($this->values['dq'])) : new Integer(0);
 286          $qi = array_key_exists('qi', $this->values) ? new Integer($this->fromBase64ToInteger($this->values['qi'])) : new Integer(0);
 287          $key_sequence = new Sequence();
 288          $key_sequence->addChild($v);
 289          $key_sequence->addChild($n);
 290          $key_sequence->addChild($e);
 291          $key_sequence->addChild($d);
 292          $key_sequence->addChild($p);
 293          $key_sequence->addChild($q);
 294          $key_sequence->addChild($dp);
 295          $key_sequence->addChild($dq);
 296          $key_sequence->addChild($qi);
 297          $key_octet_string = new OctetString(bin2hex($key_sequence->getBinary()));
 298          $this->sequence->addChild($key_octet_string);
 299      }
 300  
 301      /**
 302       * @param string $value
 303       *
 304       * @return string
 305       */
 306      private function fromBase64ToInteger($value)
 307      {
 308          $unpacked = unpack('H*', Base64Url::decode($value));
 309          if (!is_array($unpacked) || 0 === count($unpacked)) {
 310              throw new InvalidArgumentException('Unable to get the private key');
 311          }
 312  
 313          return \Brick\Math\BigInteger::fromBase(current($unpacked), 16)->toBase(10);
 314      }
 315  }


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