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