PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.7.0
Defender Security – Malware Scanner, Login Security & Firewall v5.7.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / vendor / web-token / jwt-core / Util / RSAKey.php

RSAKey.php in Defender Security – Malware Scanner, Login Security & Firewall 5.7.0, at vendor/web-token/jwt-core/Util/RSAKey.php

316 lines 8.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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