[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |