PluginProbe
ManageWP Worker / 3.9.28
ManageWP Worker v3.9.28
4.9.38 4.9.37 4.9.36 4.9.35 4.9.34 3.8.7 3.8.8 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.18 3.9.19 3.9.2 3.9.20 3.9.21 3.9.22 3.9.23 3.9.24 All 73 releases
worker / lib / PHPSecLib / Crypt / RSA.php

RSA.php in ManageWP Worker 3.9.28, at lib/PHPSecLib/Crypt/RSA.php

2,694 lines 92.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
4 /**
5 * Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA.
6 *
7 * PHP versions 4 and 5
8 *
9 * Here's an example of how to encrypt and decrypt text with this library:
10 * <code>
11 * <?php
12 * include('Crypt/RSA.php');
13 *
14 * $rsa = new Crypt_RSA();
15 * extract($rsa->createKey());
16 *
17 * $plaintext = 'terrafrost';
18 *
19 * $rsa->loadKey($privatekey);
20 * $ciphertext = $rsa->encrypt($plaintext);
21 *
22 * $rsa->loadKey($publickey);
23 * echo $rsa->decrypt($ciphertext);
24 * ?>
25 * </code>
26 *
27 * Here's an example of how to create signatures and verify signatures with this library:
28 * <code>
29 * <?php
30 * include('Crypt/RSA.php');
31 *
32 * $rsa = new Crypt_RSA();
33 * extract($rsa->createKey());
34 *
35 * $plaintext = 'terrafrost';
36 *
37 * $rsa->loadKey($privatekey);
38 * $signature = $rsa->sign($plaintext);
39 *
40 * $rsa->loadKey($publickey);
41 * echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified';
42 * ?>
43 * </code>
44 *
45 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
46 * of this software and associated documentation files (the "Software"), to deal
47 * in the Software without restriction, including without limitation the rights
48 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
49 * copies of the Software, and to permit persons to whom the Software is
50 * furnished to do so, subject to the following conditions:
51 *
52 * The above copyright notice and this permission notice shall be included in
53 * all copies or substantial portions of the Software.
54 *
55 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
58 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
59 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
60 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
61 * THE SOFTWARE.
62 *
63 * @category Crypt
64 * @package Crypt_RSA
65 * @author Jim Wigginton <terrafrost@php.net>
66 * @copyright MMIX Jim Wigginton
67 * @license http://www.opensource.org/licenses/mit-license.html MIT License
68 * @link http://phpseclib.sourceforge.net
69 */
70
71 /**
72 * Include Crypt_Random
73 */
74 // the class_exists() will only be called if the crypt_random_string function hasn't been defined and
75 // will trigger a call to __autoload() if you're wanting to auto-load classes
76 // call function_exists() a second time to stop the require_once from being called outside
77 // of the auto loader
78 if (!function_exists('crypt_random_string')) {
79 require_once('Random.php');
80 }
81
82 /**
83 * Include Crypt_Hash
84 */
85 if (!class_exists('Crypt_Hash')) {
86 require_once('Hash.php');
87 }
88
89 /**#@+
90 * @access public
91 * @see Crypt_RSA::encrypt()
92 * @see Crypt_RSA::decrypt()
93 */
94 /**
95 * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
96 * (OAEP) for encryption / decryption.
97 *
98 * Uses sha1 by default.
99 *
100 * @see Crypt_RSA::setHash()
101 * @see Crypt_RSA::setMGFHash()
102 */
103 define('CRYPT_RSA_ENCRYPTION_OAEP', 1);
104 /**
105 * Use PKCS#1 padding.
106 *
107 * Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
108 * compatability with protocols (like SSH-1) written before OAEP's introduction.
109 */
110 define('CRYPT_RSA_ENCRYPTION_PKCS1', 2);
111 /**#@-*/
112
113 /**#@+
114 * @access public
115 * @see Crypt_RSA::sign()
116 * @see Crypt_RSA::verify()
117 * @see Crypt_RSA::setHash()
118 */
119 /**
120 * Use the Probabilistic Signature Scheme for signing
121 *
122 * Uses sha1 by default.
123 *
124 * @see Crypt_RSA::setSaltLength()
125 * @see Crypt_RSA::setMGFHash()
126 */
127 define('CRYPT_RSA_SIGNATURE_PSS', 1);
128 /**
129 * Use the PKCS#1 scheme by default.
130 *
131 * Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
132 * compatability with protocols (like SSH-2) written before PSS's introduction.
133 */
134 define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
135 /**#@-*/
136
137 /**#@+
138 * @access private
139 * @see Crypt_RSA::createKey()
140 */
141 /**
142 * ASN1 Integer
143 */
144 define('CRYPT_RSA_ASN1_INTEGER', 2);
145 /**
146 * ASN1 Bit String
147 */
148 define('CRYPT_RSA_ASN1_BITSTRING', 3);
149 /**
150 * ASN1 Sequence (with the constucted bit set)
151 */
152 define('CRYPT_RSA_ASN1_SEQUENCE', 48);
153 /**#@-*/
154
155 /**#@+
156 * @access private
157 * @see Crypt_RSA::Crypt_RSA()
158 */
159 /**
160 * To use the pure-PHP implementation
161 */
162 define('CRYPT_RSA_MODE_INTERNAL', 1);
163 /**
164 * To use the OpenSSL library
165 *
166 * (if enabled; otherwise, the internal implementation will be used)
167 */
168 define('CRYPT_RSA_MODE_OPENSSL', 2);
169 /**#@-*/
170
171 /**
172 * Default openSSL configuration file.
173 */
174 define('CRYPT_RSA_OPENSSL_CONFIG', dirname(__FILE__) . '/../openssl.cnf');
175
176
177 /**#@+
178 * @access public
179 * @see Crypt_RSA::createKey()
180 * @see Crypt_RSA::setPrivateKeyFormat()
181 */
182 /**
183 * PKCS#1 formatted private key
184 *
185 * Used by OpenSSH
186 */
187 define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0);
188 /**
189 * PuTTY formatted private key
190 */
191 define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1);
192 /**
193 * XML formatted private key
194 */
195 define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2);
196 /**#@-*/
197
198 /**#@+
199 * @access public
200 * @see Crypt_RSA::createKey()
201 * @see Crypt_RSA::setPublicKeyFormat()
202 */
203 /**
204 * Raw public key
205 *
206 * An array containing two Math_BigInteger objects.
207 *
208 * The exponent can be indexed with any of the following:
209 *
210 * 0, e, exponent, publicExponent
211 *
212 * The modulus can be indexed with any of the following:
213 *
214 * 1, n, modulo, modulus
215 */
216 define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3);
217 /**
218 * PKCS#1 formatted public key (raw)
219 *
220 * Used by File/X509.php
221 */
222 define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW', 4);
223 /**
224 * XML formatted public key
225 */
226 define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5);
227 /**
228 * OpenSSH formatted public key
229 *
230 * Place in $HOME/.ssh/authorized_keys
231 */
232 define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6);
233 /**
234 * PKCS#1 formatted public key (encapsulated)
235 *
236 * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
237 */
238 define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 7);
239 /**#@-*/
240
241 /**
242 * Pure-PHP PKCS#1 compliant implementation of RSA.
243 *
244 * @author Jim Wigginton <terrafrost@php.net>
245 * @version 0.1.0
246 * @access public
247 * @package Crypt_RSA
248 */
249 class Crypt_RSA {
250 /**
251 * Precomputed Zero
252 *
253 * @var Array
254 * @access private
255 */
256 var $zero;
257
258 /**
259 * Precomputed One
260 *
261 * @var Array
262 * @access private
263 */
264 var $one;
265
266 /**
267 * Private Key Format
268 *
269 * @var Integer
270 * @access private
271 */
272 var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1;
273
274 /**
275 * Public Key Format
276 *
277 * @var Integer
278 * @access public
279 */
280 var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS1;
281
282 /**
283 * Modulus (ie. n)
284 *
285 * @var Math_BigInteger
286 * @access private
287 */
288 var $modulus;
289
290 /**
291 * Modulus length
292 *
293 * @var Math_BigInteger
294 * @access private
295 */
296 var $k;
297
298 /**
299 * Exponent (ie. e or d)
300 *
301 * @var Math_BigInteger
302 * @access private
303 */
304 var $exponent;
305
306 /**
307 * Primes for Chinese Remainder Theorem (ie. p and q)
308 *
309 * @var Array
310 * @access private
311 */
312 var $primes;
313
314 /**
315 * Exponents for Chinese Remainder Theorem (ie. dP and dQ)
316 *
317 * @var Array
318 * @access private
319 */
320 var $exponents;
321
322 /**
323 * Coefficients for Chinese Remainder Theorem (ie. qInv)
324 *
325 * @var Array
326 * @access private
327 */
328 var $coefficients;
329
330 /**
331 * Hash name
332 *
333 * @var String
334 * @access private
335 */
336 var $hashName;
337
338 /**
339 * Hash function
340 *
341 * @var Crypt_Hash
342 * @access private
343 */
344 var $hash;
345
346 /**
347 * Length of hash function output
348 *
349 * @var Integer
350 * @access private
351 */
352 var $hLen;
353
354 /**
355 * Length of salt
356 *
357 * @var Integer
358 * @access private
359 */
360 var $sLen;
361
362 /**
363 * Hash function for the Mask Generation Function
364 *
365 * @var Crypt_Hash
366 * @access private
367 */
368 var $mgfHash;
369
370 /**
371 * Length of MGF hash function output
372 *
373 * @var Integer
374 * @access private
375 */
376 var $mgfHLen;
377
378 /**
379 * Encryption mode
380 *
381 * @var Integer
382 * @access private
383 */
384 var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP;
385
386 /**
387 * Signature mode
388 *
389 * @var Integer
390 * @access private
391 */
392 var $signatureMode = CRYPT_RSA_SIGNATURE_PSS;
393
394 /**
395 * Public Exponent
396 *
397 * @var Mixed
398 * @access private
399 */
400 var $publicExponent = false;
401
402 /**
403 * Password
404 *
405 * @var String
406 * @access private
407 */
408 var $password = false;
409
410 /**
411 * Components
412 *
413 * For use with parsing XML formatted keys. PHP's XML Parser functions use utilized - instead of PHP's DOM functions -
414 * because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't.
415 *
416 * @see Crypt_RSA::_start_element_handler()
417 * @var Array
418 * @access private
419 */
420 var $components = array();
421
422 /**
423 * Current String
424 *
425 * For use with parsing XML formatted keys.
426 *
427 * @see Crypt_RSA::_character_handler()
428 * @see Crypt_RSA::_stop_element_handler()
429 * @var Mixed
430 * @access private
431 */
432 var $current;
433
434 /**
435 * OpenSSL configuration file name.
436 *
437 * Set to NULL to use system configuration file.
438 * @see Crypt_RSA::createKey()
439 * @var Mixed
440 * @Access public
441 */
442 var $configFile;
443
444 /**
445 * Public key comment field.
446 *
447 * @var String
448 * @access private
449 */
450 var $comment = 'phpseclib-generated-key';
451
452 /**
453 * The constructor
454 *
455 * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason
456 * Crypt_RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires
457 * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late.
458 *
459 * @return Crypt_RSA
460 * @access public
461 */
462 function Crypt_RSA()
463 {
464 if (!class_exists('Math_BigInteger')) {
465 require_once('Math/BigInteger.php');
466 }
467
468 $this->configFile = CRYPT_RSA_OPENSSL_CONFIG;
469
470 if ( !defined('CRYPT_RSA_MODE') ) {
471 switch (true) {
472 case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>=') && file_exists($this->configFile):
473 define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
474 break;
475 default:
476 define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
477 }
478 }
479
480 $this->zero = new Math_BigInteger();
481 $this->one = new Math_BigInteger(1);
482
483 $this->hash = new Crypt_Hash('sha1');
484 $this->hLen = $this->hash->getLength();
485 $this->hashName = 'sha1';
486 $this->mgfHash = new Crypt_Hash('sha1');
487 $this->mgfHLen = $this->mgfHash->getLength();
488 }
489
490 /**
491 * Create public / private key pair
492 *
493 * Returns an array with the following three elements:
494 * - 'privatekey': The private key.
495 * - 'publickey': The public key.
496 * - 'partialkey': A partially computed key (if the execution time exceeded $timeout).
497 * Will need to be passed back to Crypt_RSA::createKey() as the third parameter for further processing.
498 *
499 * @access public
500 * @param optional Integer $bits
501 * @param optional Integer $timeout
502 * @param optional Math_BigInteger $p
503 */
504 function createKey($bits = 1024, $timeout = false, $partial = array())
505 {
506 if (!defined('CRYPT_RSA_EXPONENT')) {
507 // http://en.wikipedia.org/wiki/65537_%28number%29
508 define('CRYPT_RSA_EXPONENT', '65537');
509 }
510 // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
511 // than 256 bits. as a consequence if the key you're trying to create is 1024 bits and you've set CRYPT_RSA_SMALLEST_PRIME
512 // to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if
513 // CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_INTERNAL. if CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_OPENSSL then
514 // CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key
515 // generation when there's a chance neither gmp nor OpenSSL are installed)
516 if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
517 define('CRYPT_RSA_SMALLEST_PRIME', 4096);
518 }
519
520 // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
521 if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
522 $config = array();
523 if (isset($this->configFile)) {
524 $config['config'] = $this->configFile;
525 }
526 $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config);
527 openssl_pkey_export($rsa, $privatekey, NULL, $config);
528 $publickey = openssl_pkey_get_details($rsa);
529 $publickey = $publickey['key'];
530
531 $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1)));
532 $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
533
534 // clear the buffer of error strings stemming from a minimalistic openssl.cnf
535 while (openssl_error_string() !== false);
536
537 return array(
538 'privatekey' => $privatekey,
539 'publickey' => $publickey,
540 'partialkey' => false
541 );
542 }
543
544 static $e;
545 if (!isset($e)) {
546 $e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
547 }
548
549 extract($this->_generateMinMax($bits));
550 $absoluteMin = $min;
551 $temp = $bits >> 1; // divide by two to see how many bits P and Q would be
552 if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
553 $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
554 $temp = CRYPT_RSA_SMALLEST_PRIME;
555 } else {
556 $num_primes = 2;
557 }
558 extract($this->_generateMinMax($temp + $bits % $temp));
559 $finalMax = $max;
560 extract($this->_generateMinMax($temp));
561
562 $generator = new Math_BigInteger();
563
564 $n = $this->one->copy();
565 if (!empty($partial)) {
566 extract(unserialize($partial));
567 } else {
568 $exponents = $coefficients = $primes = array();
569 $lcm = array(
570 'top' => $this->one->copy(),
571 'bottom' => false
572 );
573 }
574
575 $start = time();
576 $i0 = count($primes) + 1;
577
578 do {
579 for ($i = $i0; $i <= $num_primes; $i++) {
580 if ($timeout !== false) {
581 $timeout-= time() - $start;
582 $start = time();
583 if ($timeout <= 0) {
584 return array(
585 'privatekey' => '',
586 'publickey' => '',
587 'partialkey' => serialize(array(
588 'primes' => $primes,
589 'coefficients' => $coefficients,
590 'lcm' => $lcm,
591 'exponents' => $exponents
592 ))
593 );
594 }
595 }
596
597 if ($i == $num_primes) {
598 list($min, $temp) = $absoluteMin->divide($n);
599 if (!$temp->equals($this->zero)) {
600 $min = $min->add($this->one); // ie. ceil()
601 }
602 $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
603 } else {
604 $primes[$i] = $generator->randomPrime($min, $max, $timeout);
605 }
606
607 if ($primes[$i] === false) { // if we've reached the timeout
608 if (count($primes) > 1) {
609 $partialkey = '';
610 } else {
611 array_pop($primes);
612 $partialkey = serialize(array(
613 'primes' => $primes,
614 'coefficients' => $coefficients,
615 'lcm' => $lcm,
616 'exponents' => $exponents
617 ));
618 }
619
620 return array(
621 'privatekey' => '',
622 'publickey' => '',
623 'partialkey' => $partialkey
624 );
625 }
626
627 // the first coefficient is calculated differently from the rest
628 // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
629 if ($i > 2) {
630 $coefficients[$i] = $n->modInverse($primes[$i]);
631 }
632
633 $n = $n->multiply($primes[$i]);
634
635 $temp = $primes[$i]->subtract($this->one);
636
637 // textbook RSA implementations use Euler's totient function instead of the least common multiple.
638 // see http://en.wikipedia.org/wiki/Euler%27s_totient_function
639 $lcm['top'] = $lcm['top']->multiply($temp);
640 $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
641
642 $exponents[$i] = $e->modInverse($temp);
643 }
644
645 list($lcm) = $lcm['top']->divide($lcm['bottom']);
646 $gcd = $lcm->gcd($e);
647 $i0 = 1;
648 } while (!$gcd->equals($this->one));
649
650 $d = $e->modInverse($lcm);
651
652 $coefficients[2] = $primes[2]->modInverse($primes[1]);
653
654 // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
655 // RSAPrivateKey ::= SEQUENCE {
656 // version Version,
657 // modulus INTEGER, -- n
658 // publicExponent INTEGER, -- e
659 // privateExponent INTEGER, -- d
660 // prime1 INTEGER, -- p
661 // prime2 INTEGER, -- q
662 // exponent1 INTEGER, -- d mod (p-1)
663 // exponent2 INTEGER, -- d mod (q-1)
664 // coefficient INTEGER, -- (inverse of q) mod p
665 // otherPrimeInfos OtherPrimeInfos OPTIONAL
666 // }
667
668 return array(
669 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
670 'publickey' => $this->_convertPublicKey($n, $e),
671 'partialkey' => false
672 );
673 }
674
675 /**
676 * Convert a private key to the appropriate format.
677 *
678 * @access private
679 * @see setPrivateKeyFormat()
680 * @param String $RSAPrivateKey
681 * @return String
682 */
683 function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
684 {
685 $num_primes = count($primes);
686 $raw = array(
687 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
688 'modulus' => $n->toBytes(true),
689 'publicExponent' => $e->toBytes(true),
690 'privateExponent' => $d->toBytes(true),
691 'prime1' => $primes[1]->toBytes(true),
692 'prime2' => $primes[2]->toBytes(true),
693 'exponent1' => $exponents[1]->toBytes(true),
694 'exponent2' => $exponents[2]->toBytes(true),
695 'coefficient' => $coefficients[2]->toBytes(true)
696 );
697
698 // if the format in question does not support multi-prime rsa and multi-prime rsa was used,
699 // call _convertPublicKey() instead.
700 switch ($this->privateKeyFormat) {
701 case CRYPT_RSA_PRIVATE_FORMAT_XML:
702 if ($num_primes != 2) {
703 return false;
704 }
705 return "<RSAKeyValue>\r\n" .
706 ' <Modulus>' . base64_encode($raw['modulus']) . "</Modulus>\r\n" .
707 ' <Exponent>' . base64_encode($raw['publicExponent']) . "</Exponent>\r\n" .
708 ' <P>' . base64_encode($raw['prime1']) . "</P>\r\n" .
709 ' <Q>' . base64_encode($raw['prime2']) . "</Q>\r\n" .
710 ' <DP>' . base64_encode($raw['exponent1']) . "</DP>\r\n" .
711 ' <DQ>' . base64_encode($raw['exponent2']) . "</DQ>\r\n" .
712 ' <InverseQ>' . base64_encode($raw['coefficient']) . "</InverseQ>\r\n" .
713 ' <D>' . base64_encode($raw['privateExponent']) . "</D>\r\n" .
714 '</RSAKeyValue>';
715 break;
716 case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
717 if ($num_primes != 2) {
718 return false;
719 }
720 $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
721 $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
722 $key.= $encryption;
723 $key.= "\r\nComment: " . $this->comment . "\r\n";
724 $public = pack('Na*Na*Na*',
725 strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus']
726 );
727 $source = pack('Na*Na*Na*Na*',
728 strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption,
729 strlen($this->comment), $this->comment, strlen($public), $public
730 );
731 $public = base64_encode($public);
732 $key.= "Public-Lines: " . ((strlen($public) + 32) >> 6) . "\r\n";
733 $key.= chunk_split($public, 64);
734 $private = pack('Na*Na*Na*Na*',
735 strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'],
736 strlen($raw['prime2']), $raw['prime2'], strlen($raw['coefficient']), $raw['coefficient']
737 );
738 if (empty($this->password) && !is_string($this->password)) {
739 $source.= pack('Na*', strlen($private), $private);
740 $hashkey = 'putty-private-key-file-mac-key';
741 } else {
742 $private.= crypt_random_string(16 - (strlen($private) & 15));
743 $source.= pack('Na*', strlen($private), $private);
744 if (!class_exists('Crypt_AES')) {
745 require_once('Crypt/AES.php');
746 }
747 $sequence = 0;
748 $symkey = '';
749 while (strlen($symkey) < 32) {
750 $temp = pack('Na*', $sequence++, $this->password);
751 $symkey.= pack('H*', sha1($temp));
752 }
753 $symkey = substr($symkey, 0, 32);
754 $crypto = new Crypt_AES();
755
756 $crypto->setKey($symkey);
757 $crypto->disablePadding();
758 $private = $crypto->encrypt($private);
759 $hashkey = 'putty-private-key-file-mac-key' . $this->password;
760 }
761
762 $private = base64_encode($private);
763 $key.= 'Private-Lines: ' . ((strlen($private) + 32) >> 6) . "\r\n";
764 $key.= chunk_split($private, 64);
765 if (!class_exists('Crypt_Hash')) {
766 require_once('Crypt/Hash.php');
767 }
768 $hash = new Crypt_Hash('sha1');
769 $hash->setKey(pack('H*', sha1($hashkey)));
770 $key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
771
772 return $key;
773 default: // eg. CRYPT_RSA_PRIVATE_FORMAT_PKCS1
774 $components = array();
775 foreach ($raw as $name => $value) {
776 $components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
777 }
778
779 $RSAPrivateKey = implode('', $components);
780
781 if ($num_primes > 2) {
782 $OtherPrimeInfos = '';
783 for ($i = 3; $i <= $num_primes; $i++) {
784 // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
785 //
786 // OtherPrimeInfo ::= SEQUENCE {
787 // prime INTEGER, -- ri
788 // exponent INTEGER, -- di
789 // coefficient INTEGER -- ti
790 // }
791 $OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
792 $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
793 $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
794 $OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
795 }
796 $RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
797 }
798
799 $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
800
801 if (!empty($this->password) || is_string($this->password)) {
802 $iv = crypt_random_string(8);
803 $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
804 $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
805 if (!class_exists('Crypt_TripleDES')) {
806 require_once('Crypt/TripleDES.php');
807 }
808 $des = new Crypt_TripleDES();
809 $des->setKey($symkey);
810 $des->setIV($iv);
811 $iv = strtoupper(bin2hex($iv));
812 $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
813 "Proc-Type: 4,ENCRYPTED\r\n" .
814 "DEK-Info: DES-EDE3-CBC,$iv\r\n" .
815 "\r\n" .
816 chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) .
817 '-----END RSA PRIVATE KEY-----';
818 } else {
819 $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
820 chunk_split(base64_encode($RSAPrivateKey), 64) .
821 '-----END RSA PRIVATE KEY-----';
822 }
823
824 return $RSAPrivateKey;
825 }
826 }
827
828 /**
829 * Convert a public key to the appropriate format
830 *
831 * @access private
832 * @see setPublicKeyFormat()
833 * @param String $RSAPrivateKey
834 * @return String
835 */
836 function _convertPublicKey($n, $e)
837 {
838 $modulus = $n->toBytes(true);
839 $publicExponent = $e->toBytes(true);
840
841 switch ($this->publicKeyFormat) {
842 case CRYPT_RSA_PUBLIC_FORMAT_RAW:
843 return array('e' => $e->copy(), 'n' => $n->copy());
844 case CRYPT_RSA_PUBLIC_FORMAT_XML:
845 return "<RSAKeyValue>\r\n" .
846 ' <Modulus>' . base64_encode($modulus) . "</Modulus>\r\n" .
847 ' <Exponent>' . base64_encode($publicExponent) . "</Exponent>\r\n" .
848 '</RSAKeyValue>';
849 break;
850 case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
851 // from <http://tools.ietf.org/html/rfc4253#page-15>:
852 // string "ssh-rsa"
853 // mpint e
854 // mpint n
855 $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
856 $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $this->comment;
857
858 return $RSAPublicKey;
859 default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW or CRYPT_RSA_PUBLIC_FORMAT_PKCS1
860 // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
861 // RSAPublicKey ::= SEQUENCE {
862 // modulus INTEGER, -- n
863 // publicExponent INTEGER -- e
864 // }
865 $components = array(
866 'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
867 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
868 );
869
870 $RSAPublicKey = pack('Ca*a*a*',
871 CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
872 $components['modulus'], $components['publicExponent']
873 );
874
875 if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1) {
876 // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
877 $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
878 $RSAPublicKey = chr(0) . $RSAPublicKey;
879 $RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
880
881 $RSAPublicKey = pack('Ca*a*',
882 CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey
883 );
884 }
885
886 $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
887 chunk_split(base64_encode($RSAPublicKey), 64) .
888 '-----END PUBLIC KEY-----';
889
890 return $RSAPublicKey;
891 }
892 }
893
894 /**
895 * Break a public or private key down into its constituant components
896 *
897 * @access private
898 * @see _convertPublicKey()
899 * @see _convertPrivateKey()
900 * @param String $key
901 * @param Integer $type
902 * @return Array
903 */
904 function _parseKey($key, $type)
905 {
906 if ($type != CRYPT_RSA_PUBLIC_FORMAT_RAW && !is_string($key)) {
907 return false;
908 }
909
910 switch ($type) {
911 case CRYPT_RSA_PUBLIC_FORMAT_RAW:
912 if (!is_array($key)) {
913 return false;
914 }
915 $components = array();
916 switch (true) {
917 case isset($key['e']):
918 $components['publicExponent'] = $key['e']->copy();
919 break;
920 case isset($key['exponent']):
921 $components['publicExponent'] = $key['exponent']->copy();
922 break;
923 case isset($key['publicExponent']):
924 $components['publicExponent'] = $key['publicExponent']->copy();
925 break;
926 case isset($key[0]):
927 $components['publicExponent'] = $key[0]->copy();
928 }
929 switch (true) {
930 case isset($key['n']):
931 $components['modulus'] = $key['n']->copy();
932 break;
933 case isset($key['modulo']):
934 $components['modulus'] = $key['modulo']->copy();
935 break;
936 case isset($key['modulus']):
937 $components['modulus'] = $key['modulus']->copy();
938 break;
939 case isset($key[1]):
940 $components['modulus'] = $key[1]->copy();
941 }
942 return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
943 case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
944 case CRYPT_RSA_PUBLIC_FORMAT_PKCS1:
945 /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
946 "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
947 protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
948 two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
949
950 http://tools.ietf.org/html/rfc1421#section-4.6.1.1
951 http://tools.ietf.org/html/rfc1421#section-4.6.1.3
952
953 DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
954 DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
955 function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
956 own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
957 implementation are part of the standard, as well.
958
959 * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
960 if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
961 $iv = pack('H*', trim($matches[2]));
962 $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key
963 $symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8)));
964 $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-| #s', '', $key);
965 $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false;
966 if ($ciphertext === false) {
967 $ciphertext = $key;
968 }
969 switch ($matches[1]) {
970 case 'AES-256-CBC':
971 if (!class_exists('Crypt_AES')) {
972 require_once('Crypt/AES.php');
973 }
974 $crypto = new Crypt_AES();
975 break;
976 case 'AES-128-CBC':
977 if (!class_exists('Crypt_AES')) {
978 require_once('Crypt/AES.php');
979 }
980 $symkey = substr($symkey, 0, 16);
981 $crypto = new Crypt_AES();
982 break;
983 case 'DES-EDE3-CFB':
984 if (!class_exists('Crypt_TripleDES')) {
985 require_once('Crypt/TripleDES.php');
986 }
987 $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB);
988 break;
989 case 'DES-EDE3-CBC':
990 if (!class_exists('Crypt_TripleDES')) {
991 require_once('Crypt/TripleDES.php');
992 }
993 $symkey = substr($symkey, 0, 24);
994 $crypto = new Crypt_TripleDES();
995 break;
996 case 'DES-CBC':
997 if (!class_exists('Crypt_DES')) {
998 require_once('Crypt/DES.php');
999 }
1000 $crypto = new Crypt_DES();
1001 break;
1002 default:
1003 return false;
1004 }
1005 $crypto->setKey($symkey);
1006 $crypto->setIV($iv);
1007 $decoded = $crypto->decrypt($ciphertext);
1008 } else {
1009 $decoded = preg_replace('#-.+-|[\r\n]| #', '', $key);
1010 $decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false;
1011 }
1012
1013 if ($decoded !== false) {
1014 $key = $decoded;
1015 }
1016
1017 $components = array();
1018
1019 if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1020 return false;
1021 }
1022 if ($this->_decodeLength($key) != strlen($key)) {
1023 return false;
1024 }
1025
1026 $tag = ord($this->_string_shift($key));
1027 /* intended for keys for which OpenSSL's asn1parse returns the following:
1028
1029 0:d=0 hl=4 l= 631 cons: SEQUENCE
1030 4:d=1 hl=2 l= 1 prim: INTEGER :00
1031 7:d=1 hl=2 l= 13 cons: SEQUENCE
1032 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
1033 20:d=2 hl=2 l= 0 prim: NULL
1034 22:d=1 hl=4 l= 609 prim: OCTET STRING */
1035
1036 if ($tag == CRYPT_RSA_ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
1037 $this->_string_shift($key, 3);
1038 $tag = CRYPT_RSA_ASN1_SEQUENCE;
1039 }
1040
1041 if ($tag == CRYPT_RSA_ASN1_SEQUENCE) {
1042 /* intended for keys for which OpenSSL's asn1parse returns the following:
1043
1044 0:d=0 hl=4 l= 290 cons: SEQUENCE
1045 4:d=1 hl=2 l= 13 cons: SEQUENCE
1046 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
1047 17:d=2 hl=2 l= 0 prim: NULL
1048 19:d=1 hl=4 l= 271 prim: BIT STRING */
1049 $this->_string_shift($key, $this->_decodeLength($key));
1050 $tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
1051 $this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
1052 // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
1053 // unused bits in the final subsequent octet. The number shall be in the range zero to seven."
1054 // -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
1055 if ($tag == CRYPT_RSA_ASN1_BITSTRING) {
1056 $this->_string_shift($key);
1057 }
1058 if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1059 return false;
1060 }
1061 if ($this->_decodeLength($key) != strlen($key)) {
1062 return false;
1063 }
1064 $tag = ord($this->_string_shift($key));
1065 }
1066 if ($tag != CRYPT_RSA_ASN1_INTEGER) {
1067 return false;
1068 }
1069
1070 $length = $this->_decodeLength($key);
1071 $temp = $this->_string_shift($key, $length);
1072 if (strlen($temp) != 1 || ord($temp) > 2) {
1073 $components['modulus'] = new Math_BigInteger($temp, 256);
1074 $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
1075 $length = $this->_decodeLength($key);
1076 $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1077
1078 return $components;
1079 }
1080 if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) {
1081 return false;
1082 }
1083 $length = $this->_decodeLength($key);
1084 $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1085 $this->_string_shift($key);
1086 $length = $this->_decodeLength($key);
1087 $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1088 $this->_string_shift($key);
1089 $length = $this->_decodeLength($key);
1090 $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1091 $this->_string_shift($key);
1092 $length = $this->_decodeLength($key);
1093 $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1094 $this->_string_shift($key);
1095 $length = $this->_decodeLength($key);
1096 $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1097 $this->_string_shift($key);
1098 $length = $this->_decodeLength($key);
1099 $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1100 $this->_string_shift($key);
1101 $length = $this->_decodeLength($key);
1102 $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1103 $this->_string_shift($key);
1104 $length = $this->_decodeLength($key);
1105 $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1106
1107 if (!empty($key)) {
1108 if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1109 return false;
1110 }
1111 $this->_decodeLength($key);
1112 while (!empty($key)) {
1113 if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1114 return false;
1115 }
1116 $this->_decodeLength($key);
1117 $key = substr($key, 1);
1118 $length = $this->_decodeLength($key);
1119 $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1120 $this->_string_shift($key);
1121 $length = $this->_decodeLength($key);
1122 $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1123 $this->_string_shift($key);
1124 $length = $this->_decodeLength($key);
1125 $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1126 }
1127 }
1128
1129 return $components;
1130 case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
1131 $parts = explode(' ', $key, 3);
1132
1133 $key = isset($parts[1]) ? base64_decode($parts[1]) : false;
1134 if ($key === false) {
1135 return false;
1136 }
1137
1138 $comment = isset($parts[2]) ? $parts[2] : false;
1139
1140 $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
1141
1142 if (strlen($key) <= 4) {
1143 return false;
1144 }
1145 extract(unpack('Nlength', $this->_string_shift($key, 4)));
1146 $publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256);
1147 if (strlen($key) <= 4) {
1148 return false;
1149 }
1150 extract(unpack('Nlength', $this->_string_shift($key, 4)));
1151 $modulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
1152
1153 if ($cleanup && strlen($key)) {
1154 if (strlen($key) <= 4) {
1155 return false;
1156 }
1157 extract(unpack('Nlength', $this->_string_shift($key, 4)));
1158 $realModulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
1159 return strlen($key) ? false : array(
1160 'modulus' => $realModulus,
1161 'publicExponent' => $modulus,
1162 'comment' => $comment
1163 );
1164 } else {
1165 return strlen($key) ? false : array(
1166 'modulus' => $modulus,
1167 'publicExponent' => $publicExponent,
1168 'comment' => $comment
1169 );
1170 }
1171 // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
1172 // http://en.wikipedia.org/wiki/XML_Signature
1173 case CRYPT_RSA_PRIVATE_FORMAT_XML:
1174 case CRYPT_RSA_PUBLIC_FORMAT_XML:
1175 $this->components = array();
1176
1177 $xml = xml_parser_create('UTF-8');
1178 xml_set_object($xml, $this);
1179 xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
1180 xml_set_character_data_handler($xml, '_data_handler');
1181 // add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
1182 if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
1183 return false;
1184 }
1185
1186 return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
1187 // from PuTTY's SSHPUBK.C
1188 case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
1189 $components = array();
1190 $key = preg_split('#\r\n|\r|\n#', $key);
1191 $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
1192 if ($type != 'ssh-rsa') {
1193 return false;
1194 }
1195 $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
1196 $comment = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
1197
1198 $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
1199 $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
1200 $public = substr($public, 11);
1201 extract(unpack('Nlength', $this->_string_shift($public, 4)));
1202 $components['publicExponent'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
1203 extract(unpack('Nlength', $this->_string_shift($public, 4)));
1204 $components['modulus'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
1205
1206 $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
1207 $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
1208
1209 switch ($encryption) {
1210 case 'aes256-cbc':
1211 if (!class_exists('Crypt_AES')) {
1212 require_once('Crypt/AES.php');
1213 }
1214 $symkey = '';
1215 $sequence = 0;
1216 while (strlen($symkey) < 32) {
1217 $temp = pack('Na*', $sequence++, $this->password);
1218 $symkey.= pack('H*', sha1($temp));
1219 }
1220 $symkey = substr($symkey, 0, 32);
1221 $crypto = new Crypt_AES();
1222 }
1223
1224 if ($encryption != 'none') {
1225 $crypto->setKey($symkey);
1226 $crypto->disablePadding();
1227 $private = $crypto->decrypt($private);
1228 if ($private === false) {
1229 return false;
1230 }
1231 }
1232
1233 extract(unpack('Nlength', $this->_string_shift($private, 4)));
1234 if (strlen($private) < $length) {
1235 return false;
1236 }
1237 $components['privateExponent'] = new Math_BigInteger($this->_string_shift($private, $length), -256);
1238 extract(unpack('Nlength', $this->_string_shift($private, 4)));
1239 if (strlen($private) < $length) {
1240 return false;
1241 }
1242 $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($private, $length), -256));
1243 extract(unpack('Nlength', $this->_string_shift($private, 4)));
1244 if (strlen($private) < $length) {
1245 return false;
1246 }
1247 $components['primes'][] = new Math_BigInteger($this->_string_shift($private, $length), -256);
1248
1249 $temp = $components['primes'][1]->subtract($this->one);
1250 $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
1251 $temp = $components['primes'][2]->subtract($this->one);
1252 $components['exponents'][] = $components['publicExponent']->modInverse($temp);
1253
1254 extract(unpack('Nlength', $this->_string_shift($private, 4)));
1255 if (strlen($private) < $length) {
1256 return false;
1257 }
1258 $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($private, $length), -256));
1259
1260 return $components;
1261 }
1262 }
1263
1264 /**
1265 * Returns the key size
1266 *
1267 * More specifically, this returns the size of the modulo in bits.
1268 *
1269 * @access public
1270 * @return Integer
1271 */
1272 function getSize()
1273 {
1274 return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits());
1275 }
1276
1277 /**
1278 * Start Element Handler
1279 *
1280 * Called by xml_set_element_handler()
1281 *
1282 * @access private
1283 * @param Resource $parser
1284 * @param String $name
1285 * @param Array $attribs
1286 */
1287 function _start_element_handler($parser, $name, $attribs)
1288 {
1289 //$name = strtoupper($name);
1290 switch ($name) {
1291 case 'MODULUS':
1292 $this->current = &$this->components['modulus'];
1293 break;
1294 case 'EXPONENT':
1295 $this->current = &$this->components['publicExponent'];
1296 break;
1297 case 'P':
1298 $this->current = &$this->components['primes'][1];
1299 break;
1300 case 'Q':
1301 $this->current = &$this->components['primes'][2];
1302 break;
1303 case 'DP':
1304 $this->current = &$this->components['exponents'][1];
1305 break;
1306 case 'DQ':
1307 $this->current = &$this->components['exponents'][2];
1308 break;
1309 case 'INVERSEQ':
1310 $this->current = &$this->components['coefficients'][2];
1311 break;
1312 case 'D':
1313 $this->current = &$this->components['privateExponent'];
1314 break;
1315 default:
1316 unset($this->current);
1317 }
1318 $this->current = '';
1319 }
1320
1321 /**
1322 * Stop Element Handler
1323 *
1324 * Called by xml_set_element_handler()
1325 *
1326 * @access private
1327 * @param Resource $parser
1328 * @param String $name
1329 */
1330 function _stop_element_handler($parser, $name)
1331 {
1332 //$name = strtoupper($name);
1333 if ($name == 'RSAKEYVALUE') {
1334 return;
1335 }
1336 $this->current = new Math_BigInteger(base64_decode($this->current), 256);
1337 }
1338
1339 /**
1340 * Data Handler
1341 *
1342 * Called by xml_set_character_data_handler()
1343 *
1344 * @access private
1345 * @param Resource $parser
1346 * @param String $data
1347 */
1348 function _data_handler($parser, $data)
1349 {
1350 if (!isset($this->current) || is_object($this->current)) {
1351 return;
1352 }
1353 $this->current.= trim($data);
1354 }
1355
1356 /**
1357 * Loads a public or private key
1358 *
1359 * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
1360 *
1361 * @access public
1362 * @param String $key
1363 * @param Integer $type optional
1364 */
1365 function loadKey($key, $type = false)
1366 {
1367 if ($type === false) {
1368 $types = array(
1369 CRYPT_RSA_PUBLIC_FORMAT_RAW,
1370 CRYPT_RSA_PRIVATE_FORMAT_PKCS1,
1371 CRYPT_RSA_PRIVATE_FORMAT_XML,
1372 CRYPT_RSA_PRIVATE_FORMAT_PUTTY,
1373 CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
1374 );
1375 foreach ($types as $type) {
1376 $components = $this->_parseKey($key, $type);
1377 if ($components !== false) {
1378 break;
1379 }
1380 }
1381
1382 } else {
1383 $components = $this->_parseKey($key, $type);
1384 }
1385
1386 if ($components === false) {
1387 return false;
1388 }
1389
1390 if (isset($components['comment']) && $components['comment'] !== false) {
1391 $this->comment = $components['comment'];
1392 }
1393 $this->modulus = $components['modulus'];
1394 $this->k = strlen($this->modulus->toBytes());
1395 $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
1396 if (isset($components['primes'])) {
1397 $this->primes = $components['primes'];
1398 $this->exponents = $components['exponents'];
1399 $this->coefficients = $components['coefficients'];
1400 $this->publicExponent = $components['publicExponent'];
1401 } else {
1402 $this->primes = array();
1403 $this->exponents = array();
1404 $this->coefficients = array();
1405 $this->publicExponent = false;
1406 }
1407
1408 return true;
1409 }
1410
1411 /**
1412 * Sets the password
1413 *
1414 * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
1415 * Or rather, pass in $password such that empty($password) && !is_string($password) is true.
1416 *
1417 * @see createKey()
1418 * @see loadKey()
1419 * @access public
1420 * @param String $password
1421 */
1422 function setPassword($password = false)
1423 {
1424 $this->password = $password;
1425 }
1426
1427 /**
1428 * Defines the public key
1429 *
1430 * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when
1431 * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a
1432 * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys
1433 * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public
1434 * exponent this won't work unless you manually add the public exponent.
1435 *
1436 * Do note that when a new key is loaded the index will be cleared.
1437 *
1438 * Returns true on success, false on failure
1439 *
1440 * @see getPublicKey()
1441 * @access public
1442 * @param String $key optional
1443 * @param Integer $type optional
1444 * @return Boolean
1445 */
1446 function setPublicKey($key = false, $type = false)
1447 {
1448 if ($key === false && !empty($this->modulus)) {
1449 $this->publicExponent = $this->exponent;
1450 return true;
1451 }
1452
1453 if ($type === false) {
1454 $types = array(
1455 CRYPT_RSA_PUBLIC_FORMAT_RAW,
1456 CRYPT_RSA_PUBLIC_FORMAT_PKCS1,
1457 CRYPT_RSA_PUBLIC_FORMAT_XML,
1458 CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
1459 );
1460 foreach ($types as $type) {
1461 $components = $this->_parseKey($key, $type);
1462 if ($components !== false) {
1463 break;
1464 }
1465 }
1466 } else {
1467 $components = $this->_parseKey($key, $type);
1468 }
1469
1470 if ($components === false) {
1471 return false;
1472 }
1473
1474 if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
1475 $this->modulus = $components['modulus'];
1476 $this->exponent = $this->publicExponent = $components['publicExponent'];
1477 return true;
1478 }
1479
1480 $this->publicExponent = $components['publicExponent'];
1481
1482 return true;
1483 }
1484
1485 /**
1486 * Returns the public key
1487 *
1488 * The public key is only returned under two circumstances - if the private key had the public key embedded within it
1489 * or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this
1490 * function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
1491 *
1492 * @see getPublicKey()
1493 * @access public
1494 * @param String $key
1495 * @param Integer $type optional
1496 */
1497 function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
1498 {
1499 if (empty($this->modulus) || empty($this->publicExponent)) {
1500 return false;
1501 }
1502
1503 $oldFormat = $this->publicKeyFormat;
1504 $this->publicKeyFormat = $type;
1505 $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
1506 $this->publicKeyFormat = $oldFormat;
1507 return $temp;
1508 }
1509
1510 /**
1511 * Returns the private key
1512 *
1513 * The private key is only returned if the currently loaded key contains the constituent prime numbers.
1514 *
1515 * @see getPublicKey()
1516 * @access public
1517 * @param String $key
1518 * @param Integer $type optional
1519 */
1520 function getPrivateKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
1521 {
1522 if (empty($this->primes)) {
1523 return false;
1524 }
1525
1526 $oldFormat = $this->privateKeyFormat;
1527 $this->privateKeyFormat = $type;
1528 $temp = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients);
1529 $this->privateKeyFormat = $oldFormat;
1530 return $temp;
1531 }
1532
1533 /**
1534 * Returns a minimalistic private key
1535 *
1536 * Returns the private key without the prime number constituants. Structurally identical to a public key that
1537 * hasn't been set as the public key
1538 *
1539 * @see getPrivateKey()
1540 * @access private
1541 * @param String $key
1542 * @param Integer $type optional
1543 */
1544 function _getPrivatePublicKey($mode = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
1545 {
1546 if (empty($this->modulus) || empty($this->exponent)) {
1547 return false;
1548 }
1549
1550 $oldFormat = $this->publicKeyFormat;
1551 $this->publicKeyFormat = $mode;
1552 $temp = $this->_convertPublicKey($this->modulus, $this->exponent);
1553 $this->publicKeyFormat = $oldFormat;
1554 return $temp;
1555 }
1556
1557 /**
1558 * __toString() magic method
1559 *
1560 * @access public
1561 */
1562 function __toString()
1563 {
1564 $key = $this->getPrivateKey($this->privateKeyFormat);
1565 if ($key !== false) {
1566 return $key;
1567 }
1568 $key = $this->_getPrivatePublicKey($this->publicKeyFormat);
1569 return $key !== false ? $key : '';
1570 }
1571
1572 /**
1573 * Generates the smallest and largest numbers requiring $bits bits
1574 *
1575 * @access private
1576 * @param Integer $bits
1577 * @return Array
1578 */
1579 function _generateMinMax($bits)
1580 {
1581 $bytes = $bits >> 3;
1582 $min = str_repeat(chr(0), $bytes);
1583 $max = str_repeat(chr(0xFF), $bytes);
1584 $msb = $bits & 7;
1585 if ($msb) {
1586 $min = chr(1 << ($msb - 1)) . $min;
1587 $max = chr((1 << $msb) - 1) . $max;
1588 } else {
1589 $min[0] = chr(0x80);
1590 }
1591
1592 return array(
1593 'min' => new Math_BigInteger($min, 256),
1594 'max' => new Math_BigInteger($max, 256)
1595 );
1596 }
1597
1598 /**
1599 * DER-decode the length
1600 *
1601 * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
1602 * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
1603 *
1604 * @access private
1605 * @param String $string
1606 * @return Integer
1607 */
1608 function _decodeLength(&$string)
1609 {
1610 $length = ord($this->_string_shift($string));
1611 if ( $length & 0x80 ) { // definite length, long form
1612 $length&= 0x7F;
1613 $temp = $this->_string_shift($string, $length);
1614 list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
1615 }
1616 return $length;
1617 }
1618
1619 /**
1620 * DER-encode the length
1621 *
1622 * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
1623 * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
1624 *
1625 * @access private
1626 * @param Integer $length
1627 * @return String
1628 */
1629 function _encodeLength($length)
1630 {
1631 if ($length <= 0x7F) {
1632 return chr($length);
1633 }
1634
1635 $temp = ltrim(pack('N', $length), chr(0));
1636 return pack('Ca*', 0x80 | strlen($temp), $temp);
1637 }
1638
1639 /**
1640 * String Shift
1641 *
1642 * Inspired by array_shift
1643 *
1644 * @param String $string
1645 * @param optional Integer $index
1646 * @return String
1647 * @access private
1648 */
1649 function _string_shift(&$string, $index = 1)
1650 {
1651 $substr = substr($string, 0, $index);
1652 $string = substr($string, $index);
1653 return $substr;
1654 }
1655
1656 /**
1657 * Determines the private key format
1658 *
1659 * @see createKey()
1660 * @access public
1661 * @param Integer $format
1662 */
1663 function setPrivateKeyFormat($format)
1664 {
1665 $this->privateKeyFormat = $format;
1666 }
1667
1668 /**
1669 * Determines the public key format
1670 *
1671 * @see createKey()
1672 * @access public
1673 * @param Integer $format
1674 */
1675 function setPublicKeyFormat($format)
1676 {
1677 $this->publicKeyFormat = $format;
1678 }
1679
1680 /**
1681 * Determines which hashing function should be used
1682 *
1683 * Used with signature production / verification and (if the encryption mode is CRYPT_RSA_ENCRYPTION_OAEP) encryption and
1684 * decryption. If $hash isn't supported, sha1 is used.
1685 *
1686 * @access public
1687 * @param String $hash
1688 */
1689 function setHash($hash)
1690 {
1691 // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
1692 switch ($hash) {
1693 case 'md2':
1694 case 'md5':
1695 case 'sha1':
1696 case 'sha256':
1697 case 'sha384':
1698 case 'sha512':
1699 $this->hash = new Crypt_Hash($hash);
1700 $this->hashName = $hash;
1701 break;
1702 default:
1703 $this->hash = new Crypt_Hash('sha1');
1704 $this->hashName = 'sha1';
1705 }
1706 $this->hLen = $this->hash->getLength();
1707 }
1708
1709 /**
1710 * Determines which hashing function should be used for the mask generation function
1711 *
1712 * The mask generation function is used by CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_SIGNATURE_PSS and although it's
1713 * best if Hash and MGFHash are set to the same thing this is not a requirement.
1714 *
1715 * @access public
1716 * @param String $hash
1717 */
1718 function setMGFHash($hash)
1719 {
1720 // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
1721 switch ($hash) {
1722 case 'md2':
1723 case 'md5':
1724 case 'sha1':
1725 case 'sha256':
1726 case 'sha384':
1727 case 'sha512':
1728 $this->mgfHash = new Crypt_Hash($hash);
1729 break;
1730 default:
1731 $this->mgfHash = new Crypt_Hash('sha1');
1732 }
1733 $this->mgfHLen = $this->mgfHash->getLength();
1734 }
1735
1736 /**
1737 * Determines the salt length
1738 *
1739 * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
1740 *
1741 * Typical salt lengths in octets are hLen (the length of the output
1742 * of the hash function Hash) and 0.
1743 *
1744 * @access public
1745 * @param Integer $format
1746 */
1747 function setSaltLength($sLen)
1748 {
1749 $this->sLen = $sLen;
1750 }
1751
1752 /**
1753 * Integer-to-Octet-String primitive
1754 *
1755 * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
1756 *
1757 * @access private
1758 * @param Math_BigInteger $x
1759 * @param Integer $xLen
1760 * @return String
1761 */
1762 function _i2osp($x, $xLen)
1763 {
1764 $x = $x->toBytes();
1765 if (strlen($x) > $xLen) {
1766 user_error('Integer too large');
1767 return false;
1768 }
1769 return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
1770 }
1771
1772 /**
1773 * Octet-String-to-Integer primitive
1774 *
1775 * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
1776 *
1777 * @access private
1778 * @param String $x
1779 * @return Math_BigInteger
1780 */
1781 function _os2ip($x)
1782 {
1783 return new Math_BigInteger($x, 256);
1784 }
1785
1786 /**
1787 * Exponentiate with or without Chinese Remainder Theorem
1788 *
1789 * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
1790 *
1791 * @access private
1792 * @param Math_BigInteger $x
1793 * @return Math_BigInteger
1794 */
1795 function _exponentiate($x)
1796 {
1797 if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) {
1798 return $x->modPow($this->exponent, $this->modulus);
1799 }
1800
1801 $num_primes = count($this->primes);
1802
1803 if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
1804 $m_i = array(
1805 1 => $x->modPow($this->exponents[1], $this->primes[1]),
1806 2 => $x->modPow($this->exponents[2], $this->primes[2])
1807 );
1808 $h = $m_i[1]->subtract($m_i[2]);
1809 $h = $h->multiply($this->coefficients[2]);
1810 list(, $h) = $h->divide($this->primes[1]);
1811 $m = $m_i[2]->add($h->multiply($this->primes[2]));
1812
1813 $r = $this->primes[1];
1814 for ($i = 3; $i <= $num_primes; $i++) {
1815 $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
1816
1817 $r = $r->multiply($this->primes[$i - 1]);
1818
1819 $h = $m_i->subtract($m);
1820 $h = $h->multiply($this->coefficients[$i]);
1821 list(, $h) = $h->divide($this->primes[$i]);
1822
1823 $m = $m->add($r->multiply($h));
1824 }
1825 } else {
1826 $smallest = $this->primes[1];
1827 for ($i = 2; $i <= $num_primes; $i++) {
1828 if ($smallest->compare($this->primes[$i]) > 0) {
1829 $smallest = $this->primes[$i];
1830 }
1831 }
1832
1833 $one = new Math_BigInteger(1);
1834
1835 $r = $one->random($one, $smallest->subtract($one));
1836
1837 $m_i = array(
1838 1 => $this->_blind($x, $r, 1),
1839 2 => $this->_blind($x, $r, 2)
1840 );
1841 $h = $m_i[1]->subtract($m_i[2]);
1842 $h = $h->multiply($this->coefficients[2]);
1843 list(, $h) = $h->divide($this->primes[1]);
1844 $m = $m_i[2]->add($h->multiply($this->primes[2]));
1845
1846 $r = $this->primes[1];
1847 for ($i = 3; $i <= $num_primes; $i++) {
1848 $m_i = $this->_blind($x, $r, $i);
1849
1850 $r = $r->multiply($this->primes[$i - 1]);
1851
1852 $h = $m_i->subtract($m);
1853 $h = $h->multiply($this->coefficients[$i]);
1854 list(, $h) = $h->divide($this->primes[$i]);
1855
1856 $m = $m->add($r->multiply($h));
1857 }
1858 }
1859
1860 return $m;
1861 }
1862
1863 /**
1864 * Performs RSA Blinding
1865 *
1866 * Protects against timing attacks by employing RSA Blinding.
1867 * Returns $x->modPow($this->exponents[$i], $this->primes[$i])
1868 *
1869 * @access private
1870 * @param Math_BigInteger $x
1871 * @param Math_BigInteger $r
1872 * @param Integer $i
1873 * @return Math_BigInteger
1874 */
1875 function _blind($x, $r, $i)
1876 {
1877 $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
1878 $x = $x->modPow($this->exponents[$i], $this->primes[$i]);
1879
1880 $r = $r->modInverse($this->primes[$i]);
1881 $x = $x->multiply($r);
1882 list(, $x) = $x->divide($this->primes[$i]);
1883
1884 return $x;
1885 }
1886
1887 /**
1888 * Performs blinded RSA equality testing
1889 *
1890 * Protects against a particular type of timing attack described.
1891 *
1892 * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)}
1893 *
1894 * Thanks for the heads up singpolyma!
1895 *
1896 * @access private
1897 * @param String $x
1898 * @param String $y
1899 * @return Boolean
1900 */
1901 function _equals($x, $y)
1902 {
1903 if (strlen($x) != strlen($y)) {
1904 return false;
1905 }
1906
1907 $result = 0;
1908 for ($i = 0; $i < strlen($x); $i++) {
1909 $result |= ord($x[$i]) ^ ord($y[$i]);
1910 }
1911
1912 return $result == 0;
1913 }
1914
1915 /**
1916 * RSAEP
1917 *
1918 * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
1919 *
1920 * @access private
1921 * @param Math_BigInteger $m
1922 * @return Math_BigInteger
1923 */
1924 function _rsaep($m)
1925 {
1926 if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1927 user_error('Message representative out of range');
1928 return false;
1929 }
1930 return $this->_exponentiate($m);
1931 }
1932
1933 /**
1934 * RSADP
1935 *
1936 * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
1937 *
1938 * @access private
1939 * @param Math_BigInteger $c
1940 * @return Math_BigInteger
1941 */
1942 function _rsadp($c)
1943 {
1944 if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
1945 user_error('Ciphertext representative out of range');
1946 return false;
1947 }
1948 return $this->_exponentiate($c);
1949 }
1950
1951 /**
1952 * RSASP1
1953 *
1954 * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
1955 *
1956 * @access private
1957 * @param Math_BigInteger $m
1958 * @return Math_BigInteger
1959 */
1960 function _rsasp1($m)
1961 {
1962 if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1963 user_error('Message representative out of range');
1964 return false;
1965 }
1966 return $this->_exponentiate($m);
1967 }
1968
1969 /**
1970 * RSAVP1
1971 *
1972 * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
1973 *
1974 * @access private
1975 * @param Math_BigInteger $s
1976 * @return Math_BigInteger
1977 */
1978 function _rsavp1($s)
1979 {
1980 if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
1981 user_error('Signature representative out of range');
1982 return false;
1983 }
1984 return $this->_exponentiate($s);
1985 }
1986
1987 /**
1988 * MGF1
1989 *
1990 * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
1991 *
1992 * @access private
1993 * @param String $mgfSeed
1994 * @param Integer $mgfLen
1995 * @return String
1996 */
1997 function _mgf1($mgfSeed, $maskLen)
1998 {
1999 // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
2000
2001 $t = '';
2002 $count = ceil($maskLen / $this->mgfHLen);
2003 for ($i = 0; $i < $count; $i++) {
2004 $c = pack('N', $i);
2005 $t.= $this->mgfHash->hash($mgfSeed . $c);
2006 }
2007
2008 return substr($t, 0, $maskLen);
2009 }
2010
2011 /**
2012 * RSAES-OAEP-ENCRYPT
2013 *
2014 * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and
2015 * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}.
2016 *
2017 * @access private
2018 * @param String $m
2019 * @param String $l
2020 * @return String
2021 */
2022 function _rsaes_oaep_encrypt($m, $l = '')
2023 {
2024 $mLen = strlen($m);
2025
2026 // Length checking
2027
2028 // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2029 // be output.
2030
2031 if ($mLen > $this->k - 2 * $this->hLen - 2) {
2032 user_error('Message too long');
2033 return false;
2034 }
2035
2036 // EME-OAEP encoding
2037
2038 $lHash = $this->hash->hash($l);
2039 $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
2040 $db = $lHash . $ps . chr(1) . $m;
2041 $seed = crypt_random_string($this->hLen);
2042 $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2043 $maskedDB = $db ^ $dbMask;
2044 $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2045 $maskedSeed = $seed ^ $seedMask;
2046 $em = chr(0) . $maskedSeed . $maskedDB;
2047
2048 // RSA encryption
2049
2050 $m = $this->_os2ip($em);
2051 $c = $this->_rsaep($m);
2052 $c = $this->_i2osp($c, $this->k);
2053
2054 // Output the ciphertext C
2055
2056 return $c;
2057 }
2058
2059 /**
2060 * RSAES-OAEP-DECRYPT
2061 *
2062 * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error
2063 * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
2064 *
2065 * Note. Care must be taken to ensure that an opponent cannot
2066 * distinguish the different error conditions in Step 3.g, whether by
2067 * error message or timing, or, more generally, learn partial
2068 * information about the encoded message EM. Otherwise an opponent may
2069 * be able to obtain useful information about the decryption of the
2070 * ciphertext C, leading to a chosen-ciphertext attack such as the one
2071 * observed by Manger [36].
2072 *
2073 * As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
2074 *
2075 * Both the encryption and the decryption operations of RSAES-OAEP take
2076 * the value of a label L as input. In this version of PKCS #1, L is
2077 * the empty string; other uses of the label are outside the scope of
2078 * this document.
2079 *
2080 * @access private
2081 * @param String $c
2082 * @param String $l
2083 * @return String
2084 */
2085 function _rsaes_oaep_decrypt($c, $l = '')
2086 {
2087 // Length checking
2088
2089 // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2090 // be output.
2091
2092 if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
2093 user_error('Decryption error');
2094 return false;
2095 }
2096
2097 // RSA decryption
2098
2099 $c = $this->_os2ip($c);
2100 $m = $this->_rsadp($c);
2101 if ($m === false) {
2102 user_error('Decryption error');
2103 return false;
2104 }
2105 $em = $this->_i2osp($m, $this->k);
2106
2107 // EME-OAEP decoding
2108
2109 $lHash = $this->hash->hash($l);
2110 $y = ord($em[0]);
2111 $maskedSeed = substr($em, 1, $this->hLen);
2112 $maskedDB = substr($em, $this->hLen + 1);
2113 $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2114 $seed = $maskedSeed ^ $seedMask;
2115 $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2116 $db = $maskedDB ^ $dbMask;
2117 $lHash2 = substr($db, 0, $this->hLen);
2118 $m = substr($db, $this->hLen);
2119 if ($lHash != $lHash2) {
2120 user_error('Decryption error');
2121 return false;
2122 }
2123 $m = ltrim($m, chr(0));
2124 if (ord($m[0]) != 1) {
2125 user_error('Decryption error');
2126 return false;
2127 }
2128
2129 // Output the message M
2130
2131 return substr($m, 1);
2132 }
2133
2134 /**
2135 * RSAES-PKCS1-V1_5-ENCRYPT
2136 *
2137 * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
2138 *
2139 * @access private
2140 * @param String $m
2141 * @return String
2142 */
2143 function _rsaes_pkcs1_v1_5_encrypt($m)
2144 {
2145 $mLen = strlen($m);
2146
2147 // Length checking
2148
2149 if ($mLen > $this->k - 11) {
2150 user_error('Message too long');
2151 return false;
2152 }
2153
2154 // EME-PKCS1-v1_5 encoding
2155
2156 $psLen = $this->k - $mLen - 3;
2157 $ps = '';
2158 while (strlen($ps) != $psLen) {
2159 $temp = crypt_random_string($psLen - strlen($ps));
2160 $temp = str_replace("\x00", '', $temp);
2161 $ps.= $temp;
2162 }
2163 $type = 2;
2164 // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done
2165 if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) {
2166 $type = 1;
2167 // "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF"
2168 $ps = str_repeat("\xFF", $psLen);
2169 }
2170 $em = chr(0) . chr($type) . $ps . chr(0) . $m;
2171
2172 // RSA encryption
2173 $m = $this->_os2ip($em);
2174 $c = $this->_rsaep($m);
2175 $c = $this->_i2osp($c, $this->k);
2176
2177 // Output the ciphertext C
2178
2179 return $c;
2180 }
2181
2182 /**
2183 * RSAES-PKCS1-V1_5-DECRYPT
2184 *
2185 * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
2186 *
2187 * For compatability purposes, this function departs slightly from the description given in RFC3447.
2188 * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
2189 * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
2190 * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed
2191 * to be 2 regardless of which key is used. For compatability purposes, we'll just check to make sure the
2192 * second byte is 2 or less. If it is, we'll accept the decrypted string as valid.
2193 *
2194 * As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt
2195 * with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but
2196 * not private key encrypted ciphertext's.
2197 *
2198 * @access private
2199 * @param String $c
2200 * @return String
2201 */
2202 function _rsaes_pkcs1_v1_5_decrypt($c)
2203 {
2204 // Length checking
2205
2206 if (strlen($c) != $this->k) { // or if k < 11
2207 user_error('Decryption error');
2208 return false;
2209 }
2210
2211 // RSA decryption
2212
2213 $c = $this->_os2ip($c);
2214 $m = $this->_rsadp($c);
2215
2216 if ($m === false) {
2217 user_error('Decryption error');
2218 return false;
2219 }
2220 $em = $this->_i2osp($m, $this->k);
2221
2222 // EME-PKCS1-v1_5 decoding
2223
2224 if (ord($em[0]) != 0 || ord($em[1]) > 2) {
2225 user_error('Decryption error');
2226 return false;
2227 }
2228
2229 $ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
2230 $m = substr($em, strlen($ps) + 3);
2231
2232 if (strlen($ps) < 8) {
2233 user_error('Decryption error');
2234 return false;
2235 }
2236
2237 // Output M
2238
2239 return $m;
2240 }
2241
2242 /**
2243 * EMSA-PSS-ENCODE
2244 *
2245 * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
2246 *
2247 * @access private
2248 * @param String $m
2249 * @param Integer $emBits
2250 */
2251 function _emsa_pss_encode($m, $emBits)
2252 {
2253 // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2254 // be output.
2255
2256 $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
2257 $sLen = $this->sLen == false ? $this->hLen : $this->sLen;
2258
2259 $mHash = $this->hash->hash($m);
2260 if ($emLen < $this->hLen + $sLen + 2) {
2261 user_error('Encoding error');
2262 return false;
2263 }
2264
2265 $salt = crypt_random_string($sLen);
2266 $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2267 $h = $this->hash->hash($m2);
2268 $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
2269 $db = $ps . chr(1) . $salt;
2270 $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
2271 $maskedDB = $db ^ $dbMask;
2272 $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
2273 $em = $maskedDB . $h . chr(0xBC);
2274
2275 return $em;
2276 }
2277
2278 /**
2279 * EMSA-PSS-VERIFY
2280 *
2281 * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
2282 *
2283 * @access private
2284 * @param String $m
2285 * @param String $em
2286 * @param Integer $emBits
2287 * @return String
2288 */
2289 function _emsa_pss_verify($m, $em, $emBits)
2290 {
2291 // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2292 // be output.
2293
2294 $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
2295 $sLen = $this->sLen == false ? $this->hLen : $this->sLen;
2296
2297 $mHash = $this->hash->hash($m);
2298 if ($emLen < $this->hLen + $sLen + 2) {
2299 return false;
2300 }
2301
2302 if ($em[strlen($em) - 1] != chr(0xBC)) {
2303 return false;
2304 }
2305
2306 $maskedDB = substr($em, 0, -$this->hLen - 1);
2307 $h = substr($em, -$this->hLen - 1, $this->hLen);
2308 $temp = chr(0xFF << ($emBits & 7));
2309 if ((~$maskedDB[0] & $temp) != $temp) {
2310 return false;
2311 }
2312 $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
2313 $db = $maskedDB ^ $dbMask;
2314 $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
2315 $temp = $emLen - $this->hLen - $sLen - 2;
2316 if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
2317 return false;
2318 }
2319 $salt = substr($db, $temp + 1); // should be $sLen long
2320 $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2321 $h2 = $this->hash->hash($m2);
2322 return $this->_equals($h, $h2);
2323 }
2324
2325 /**
2326 * RSASSA-PSS-SIGN
2327 *
2328 * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
2329 *
2330 * @access private
2331 * @param String $m
2332 * @return String
2333 */
2334 function _rsassa_pss_sign($m)
2335 {
2336 // EMSA-PSS encoding
2337
2338 $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);
2339
2340 // RSA signature
2341
2342 $m = $this->_os2ip($em);
2343 $s = $this->_rsasp1($m);
2344 $s = $this->_i2osp($s, $this->k);
2345
2346 // Output the signature S
2347
2348 return $s;
2349 }
2350
2351 /**
2352 * RSASSA-PSS-VERIFY
2353 *
2354 * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
2355 *
2356 * @access private
2357 * @param String $m
2358 * @param String $s
2359 * @return String
2360 */
2361 function _rsassa_pss_verify($m, $s)
2362 {
2363 // Length checking
2364
2365 if (strlen($s) != $this->k) {
2366 user_error('Invalid signature');
2367 return false;
2368 }
2369
2370 // RSA verification
2371
2372 $modBits = 8 * $this->k;
2373
2374 $s2 = $this->_os2ip($s);
2375 $m2 = $this->_rsavp1($s2);
2376 if ($m2 === false) {
2377 user_error('Invalid signature');
2378 return false;
2379 }
2380 $em = $this->_i2osp($m2, $modBits >> 3);
2381 if ($em === false) {
2382 user_error('Invalid signature');
2383 return false;
2384 }
2385
2386 // EMSA-PSS verification
2387
2388 return $this->_emsa_pss_verify($m, $em, $modBits - 1);
2389 }
2390
2391 /**
2392 * EMSA-PKCS1-V1_5-ENCODE
2393 *
2394 * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
2395 *
2396 * @access private
2397 * @param String $m
2398 * @param Integer $emLen
2399 * @return String
2400 */
2401 function _emsa_pkcs1_v1_5_encode($m, $emLen)
2402 {
2403 $h = $this->hash->hash($m);
2404 if ($h === false) {
2405 return false;
2406 }
2407
2408 // see http://tools.ietf.org/html/rfc3447#page-43
2409 switch ($this->hashName) {
2410 case 'md2':
2411 $t = pack('H*', '3020300c06082a864886f70d020205000410');
2412 break;
2413 case 'md5':
2414 $t = pack('H*', '3020300c06082a864886f70d020505000410');
2415 break;
2416 case 'sha1':
2417 $t = pack('H*', '3021300906052b0e03021a05000414');
2418 break;
2419 case 'sha256':
2420 $t = pack('H*', '3031300d060960864801650304020105000420');
2421 break;
2422 case 'sha384':
2423 $t = pack('H*', '3041300d060960864801650304020205000430');
2424 break;
2425 case 'sha512':
2426 $t = pack('H*', '3051300d060960864801650304020305000440');
2427 }
2428 $t.= $h;
2429 $tLen = strlen($t);
2430
2431 if ($emLen < $tLen + 11) {
2432 user_error('Intended encoded message length too short');
2433 return false;
2434 }
2435
2436 $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
2437
2438 $em = "\0\1$ps\0$t";
2439
2440 return $em;
2441 }
2442
2443 /**
2444 * RSASSA-PKCS1-V1_5-SIGN
2445 *
2446 * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
2447 *
2448 * @access private
2449 * @param String $m
2450 * @return String
2451 */
2452 function _rsassa_pkcs1_v1_5_sign($m)
2453 {
2454 // EMSA-PKCS1-v1_5 encoding
2455
2456 $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2457 if ($em === false) {
2458 user_error('RSA modulus too short');
2459 return false;
2460 }
2461
2462 // RSA signature
2463
2464 $m = $this->_os2ip($em);
2465 $s = $this->_rsasp1($m);
2466 $s = $this->_i2osp($s, $this->k);
2467
2468 // Output the signature S
2469
2470 return $s;
2471 }
2472
2473 /**
2474 * RSASSA-PKCS1-V1_5-VERIFY
2475 *
2476 * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}.
2477 *
2478 * @access private
2479 * @param String $m
2480 * @return String
2481 */
2482 function _rsassa_pkcs1_v1_5_verify($m, $s)
2483 {
2484 // Length checking
2485
2486 if (strlen($s) != $this->k) {
2487 user_error('Invalid signature');
2488 return false;
2489 }
2490
2491 // RSA verification
2492
2493 $s = $this->_os2ip($s);
2494 $m2 = $this->_rsavp1($s);
2495 if ($m2 === false) {
2496 user_error('Invalid signature');
2497 return false;
2498 }
2499 $em = $this->_i2osp($m2, $this->k);
2500 if ($em === false) {
2501 user_error('Invalid signature');
2502 return false;
2503 }
2504
2505 // EMSA-PKCS1-v1_5 encoding
2506
2507 $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2508 if ($em2 === false) {
2509 user_error('RSA modulus too short');
2510 return false;
2511 }
2512
2513 // Compare
2514 return $this->_equals($em, $em2);
2515 }
2516
2517 /**
2518 * Set Encryption Mode
2519 *
2520 * Valid values include CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1.
2521 *
2522 * @access public
2523 * @param Integer $mode
2524 */
2525 function setEncryptionMode($mode)
2526 {
2527 $this->encryptionMode = $mode;
2528 }
2529
2530 /**
2531 * Set Signature Mode
2532 *
2533 * Valid values include CRYPT_RSA_SIGNATURE_PSS and CRYPT_RSA_SIGNATURE_PKCS1
2534 *
2535 * @access public
2536 * @param Integer $mode
2537 */
2538 function setSignatureMode($mode)
2539 {
2540 $this->signatureMode = $mode;
2541 }
2542
2543 /**
2544 * Set public key comment.
2545 *
2546 * @access public
2547 * @param String $comment
2548 */
2549 function setComment($comment)
2550 {
2551 $this->comment = $comment;
2552 }
2553
2554 /**
2555 * Get public key comment.
2556 *
2557 * @access public
2558 * @return String
2559 */
2560 function getComment()
2561 {
2562 return $this->comment;
2563 }
2564
2565 /**
2566 * Encryption
2567 *
2568 * Both CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1 both place limits on how long $plaintext can be.
2569 * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
2570 * be concatenated together.
2571 *
2572 * @see decrypt()
2573 * @access public
2574 * @param String $plaintext
2575 * @return String
2576 */
2577 function encrypt($plaintext)
2578 {
2579 switch ($this->encryptionMode) {
2580 case CRYPT_RSA_ENCRYPTION_PKCS1:
2581 $length = $this->k - 11;
2582 if ($length <= 0) {
2583 return false;
2584 }
2585
2586 $plaintext = str_split($plaintext, $length);
2587 $ciphertext = '';
2588 foreach ($plaintext as $m) {
2589 $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m);
2590 }
2591 return $ciphertext;
2592 //case CRYPT_RSA_ENCRYPTION_OAEP:
2593 default:
2594 $length = $this->k - 2 * $this->hLen - 2;
2595 if ($length <= 0) {
2596 return false;
2597 }
2598
2599 $plaintext = str_split($plaintext, $length);
2600 $ciphertext = '';
2601 foreach ($plaintext as $m) {
2602 $ciphertext.= $this->_rsaes_oaep_encrypt($m);
2603 }
2604 return $ciphertext;
2605 }
2606 }
2607
2608 /**
2609 * Decryption
2610 *
2611 * @see encrypt()
2612 * @access public
2613 * @param String $plaintext
2614 * @return String
2615 */
2616 function decrypt($ciphertext)
2617 {
2618 if ($this->k <= 0) {
2619 return false;
2620 }
2621
2622 $ciphertext = str_split($ciphertext, $this->k);
2623 $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);
2624
2625 $plaintext = '';
2626
2627 switch ($this->encryptionMode) {
2628 case CRYPT_RSA_ENCRYPTION_PKCS1:
2629 $decrypt = '_rsaes_pkcs1_v1_5_decrypt';
2630 break;
2631 //case CRYPT_RSA_ENCRYPTION_OAEP:
2632 default:
2633 $decrypt = '_rsaes_oaep_decrypt';
2634 }
2635
2636 foreach ($ciphertext as $c) {
2637 $temp = $this->$decrypt($c);
2638 if ($temp === false) {
2639 return false;
2640 }
2641 $plaintext.= $temp;
2642 }
2643
2644 return $plaintext;
2645 }
2646
2647 /**
2648 * Create a signature
2649 *
2650 * @see verify()
2651 * @access public
2652 * @param String $message
2653 * @return String
2654 */
2655 function sign($message)
2656 {
2657 if (empty($this->modulus) || empty($this->exponent)) {
2658 return false;
2659 }
2660
2661 switch ($this->signatureMode) {
2662 case CRYPT_RSA_SIGNATURE_PKCS1:
2663 return $this->_rsassa_pkcs1_v1_5_sign($message);
2664 //case CRYPT_RSA_SIGNATURE_PSS:
2665 default:
2666 return $this->_rsassa_pss_sign($message);
2667 }
2668 }
2669
2670 /**
2671 * Verifies a signature
2672 *
2673 * @see sign()
2674 * @access public
2675 * @param String $message
2676 * @param String $signature
2677 * @return Boolean
2678 */
2679 function verify($message, $signature)
2680 {
2681 if (empty($this->modulus) || empty($this->exponent)) {
2682 return false;
2683 }
2684
2685 switch ($this->signatureMode) {
2686 case CRYPT_RSA_SIGNATURE_PKCS1:
2687 return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
2688 //case CRYPT_RSA_SIGNATURE_PSS:
2689 default:
2690 return $this->_rsassa_pss_verify($message, $signature);
2691 }
2692 }
2693 }
2694