Diff: STRATO-apps/wordpress_03/app/wp-content/plugins/tutor-pro/vendor/web-token/jwt-core/Util/RSAKey.php

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
1 -
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 + }
316 +