ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
RSA.php
Go to the documentation of this file.
1<?php
2
52namespace phpseclib\Crypt;
53
62
70class RSA
71{
86 const ENCRYPTION_OAEP = 1;
117 const SIGNATURE_PSS = 1;
134 const ASN1_INTEGER = 2;
138 const ASN1_BITSTRING = 3;
146 const ASN1_OBJECT = 6;
150 const ASN1_SEQUENCE = 48;
160 const MODE_INTERNAL = 1;
166 const MODE_OPENSSL = 2;
258 var $zero;
259
266 var $one;
267
275
283
291
298 var $k;
299
307
315
323
331
339
346 var $hash;
347
354 var $hLen;
355
362 var $sLen;
363
371
379
387
395
402 var $publicExponent = false;
403
410 var $password = false;
411
422 var $components = array();
423
435
445
452 var $comment = 'phpseclib-generated-key';
453
464 function __construct()
465 {
466 $this->configFile = dirname(__FILE__) . '/../openssl.cnf';
467
468 if (!defined('CRYPT_RSA_MODE')) {
469 switch (true) {
470 // Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular,
471 // Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger
472 // can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either.
473 case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'):
474 define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
475 break;
476 case extension_loaded('openssl') && file_exists($this->configFile):
477 // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
478 ob_start();
479 @phpinfo();
480 $content = ob_get_contents();
481 ob_end_clean();
482
483 preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
484
485 $versions = array();
486 if (!empty($matches[1])) {
487 for ($i = 0; $i < count($matches[1]); $i++) {
488 $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
489
490 // Remove letter part in OpenSSL version
491 if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
492 $versions[$matches[1][$i]] = $fullVersion;
493 } else {
494 $versions[$matches[1][$i]] = $m[0];
495 }
496 }
497 }
498
499 // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
500 switch (true) {
501 case !isset($versions['Header']):
502 case !isset($versions['Library']):
503 case $versions['Header'] == $versions['Library']:
504 define('CRYPT_RSA_MODE', self::MODE_OPENSSL);
505 break;
506 default:
507 define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
508 define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
509 }
510 break;
511 default:
512 define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
513 }
514 }
515
516 $this->zero = new BigInteger();
517 $this->one = new BigInteger(1);
518
519 $this->hash = new Hash('sha1');
520 $this->hLen = $this->hash->getLength();
521 $this->hashName = 'sha1';
522 $this->mgfHash = new Hash('sha1');
523 $this->mgfHLen = $this->mgfHash->getLength();
524 }
525
540 function createKey($bits = 1024, $timeout = false, $partial = array())
541 {
542 if (!defined('CRYPT_RSA_EXPONENT')) {
543 // http://en.wikipedia.org/wiki/65537_%28number%29
544 define('CRYPT_RSA_EXPONENT', '65537');
545 }
546 // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
547 // 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
548 // to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if
549 // CRYPT_RSA_MODE is set to self::MODE_INTERNAL. if CRYPT_RSA_MODE is set to self::MODE_OPENSSL then
550 // CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key
551 // generation when there's a chance neither gmp nor OpenSSL are installed)
552 if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
553 define('CRYPT_RSA_SMALLEST_PRIME', 4096);
554 }
555
556 // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
557 if (CRYPT_RSA_MODE == self::MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
558 $config = array();
559 if (isset($this->configFile)) {
560 $config['config'] = $this->configFile;
561 }
562 $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config);
563 openssl_pkey_export($rsa, $privatekey, null, $config);
564 $publickey = openssl_pkey_get_details($rsa);
565 $publickey = $publickey['key'];
566
567 $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, self::PRIVATE_FORMAT_PKCS1)));
568 $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, self::PUBLIC_FORMAT_PKCS1)));
569
570 // clear the buffer of error strings stemming from a minimalistic openssl.cnf
571 while (openssl_error_string() !== false) {
572 }
573
574 return array(
575 'privatekey' => $privatekey,
576 'publickey' => $publickey,
577 'partialkey' => false
578 );
579 }
580
581 static $e;
582 if (!isset($e)) {
583 $e = new BigInteger(CRYPT_RSA_EXPONENT);
584 }
585
586 extract($this->_generateMinMax($bits));
587 $absoluteMin = $min;
588 $temp = $bits >> 1; // divide by two to see how many bits P and Q would be
589 if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
590 $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
591 $temp = CRYPT_RSA_SMALLEST_PRIME;
592 } else {
593 $num_primes = 2;
594 }
595 extract($this->_generateMinMax($temp + $bits % $temp));
596 $finalMax = $max;
597 extract($this->_generateMinMax($temp));
598
599 $generator = new BigInteger();
600
601 $n = $this->one->copy();
602 if (!empty($partial)) {
603 extract(unserialize($partial));
604 } else {
605 $exponents = $coefficients = $primes = array();
606 $lcm = array(
607 'top' => $this->one->copy(),
608 'bottom' => false
609 );
610 }
611
612 $start = time();
613 $i0 = count($primes) + 1;
614
615 do {
616 for ($i = $i0; $i <= $num_primes; $i++) {
617 if ($timeout !== false) {
618 $timeout-= time() - $start;
619 $start = time();
620 if ($timeout <= 0) {
621 return array(
622 'privatekey' => '',
623 'publickey' => '',
624 'partialkey' => serialize(array(
625 'primes' => $primes,
626 'coefficients' => $coefficients,
627 'lcm' => $lcm,
628 'exponents' => $exponents
629 ))
630 );
631 }
632 }
633
634 if ($i == $num_primes) {
635 list($min, $temp) = $absoluteMin->divide($n);
636 if (!$temp->equals($this->zero)) {
637 $min = $min->add($this->one); // ie. ceil()
638 }
639 $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
640 } else {
641 $primes[$i] = $generator->randomPrime($min, $max, $timeout);
642 }
643
644 if ($primes[$i] === false) { // if we've reached the timeout
645 if (count($primes) > 1) {
646 $partialkey = '';
647 } else {
648 array_pop($primes);
649 $partialkey = serialize(array(
650 'primes' => $primes,
651 'coefficients' => $coefficients,
652 'lcm' => $lcm,
653 'exponents' => $exponents
654 ));
655 }
656
657 return array(
658 'privatekey' => '',
659 'publickey' => '',
660 'partialkey' => $partialkey
661 );
662 }
663
664 // the first coefficient is calculated differently from the rest
665 // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
666 if ($i > 2) {
667 $coefficients[$i] = $n->modInverse($primes[$i]);
668 }
669
670 $n = $n->multiply($primes[$i]);
671
672 $temp = $primes[$i]->subtract($this->one);
673
674 // textbook RSA implementations use Euler's totient function instead of the least common multiple.
675 // see http://en.wikipedia.org/wiki/Euler%27s_totient_function
676 $lcm['top'] = $lcm['top']->multiply($temp);
677 $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
678
679 $exponents[$i] = $e->modInverse($temp);
680 }
681
682 list($temp) = $lcm['top']->divide($lcm['bottom']);
683 $gcd = $temp->gcd($e);
684 $i0 = 1;
685 } while (!$gcd->equals($this->one));
686
687 $d = $e->modInverse($temp);
688
689 $coefficients[2] = $primes[2]->modInverse($primes[1]);
690
691 // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
692 // RSAPrivateKey ::= SEQUENCE {
693 // version Version,
694 // modulus INTEGER, -- n
695 // publicExponent INTEGER, -- e
696 // privateExponent INTEGER, -- d
697 // prime1 INTEGER, -- p
698 // prime2 INTEGER, -- q
699 // exponent1 INTEGER, -- d mod (p-1)
700 // exponent2 INTEGER, -- d mod (q-1)
701 // coefficient INTEGER, -- (inverse of q) mod p
702 // otherPrimeInfos OtherPrimeInfos OPTIONAL
703 // }
704
705 return array(
706 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
707 'publickey' => $this->_convertPublicKey($n, $e),
708 'partialkey' => false
709 );
710 }
711
721 {
722 $signed = $this->privateKeyFormat != self::PRIVATE_FORMAT_XML;
723 $num_primes = count($primes);
724 $raw = array(
725 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
726 'modulus' => $n->toBytes($signed),
727 'publicExponent' => $e->toBytes($signed),
728 'privateExponent' => $d->toBytes($signed),
729 'prime1' => $primes[1]->toBytes($signed),
730 'prime2' => $primes[2]->toBytes($signed),
731 'exponent1' => $exponents[1]->toBytes($signed),
732 'exponent2' => $exponents[2]->toBytes($signed),
733 'coefficient' => $coefficients[2]->toBytes($signed)
734 );
735
736 // if the format in question does not support multi-prime rsa and multi-prime rsa was used,
737 // call _convertPublicKey() instead.
738 switch ($this->privateKeyFormat) {
740 if ($num_primes != 2) {
741 return false;
742 }
743 return "<RSAKeyValue>\r\n" .
744 ' <Modulus>' . base64_encode($raw['modulus']) . "</Modulus>\r\n" .
745 ' <Exponent>' . base64_encode($raw['publicExponent']) . "</Exponent>\r\n" .
746 ' <P>' . base64_encode($raw['prime1']) . "</P>\r\n" .
747 ' <Q>' . base64_encode($raw['prime2']) . "</Q>\r\n" .
748 ' <DP>' . base64_encode($raw['exponent1']) . "</DP>\r\n" .
749 ' <DQ>' . base64_encode($raw['exponent2']) . "</DQ>\r\n" .
750 ' <InverseQ>' . base64_encode($raw['coefficient']) . "</InverseQ>\r\n" .
751 ' <D>' . base64_encode($raw['privateExponent']) . "</D>\r\n" .
752 '</RSAKeyValue>';
753 break;
755 if ($num_primes != 2) {
756 return false;
757 }
758 $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
759 $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
760 $key.= $encryption;
761 $key.= "\r\nComment: " . $this->comment . "\r\n";
762 $public = pack(
763 'Na*Na*Na*',
764 strlen('ssh-rsa'),
765 'ssh-rsa',
766 strlen($raw['publicExponent']),
767 $raw['publicExponent'],
768 strlen($raw['modulus']),
769 $raw['modulus']
770 );
771 $source = pack(
772 'Na*Na*Na*Na*',
773 strlen('ssh-rsa'),
774 'ssh-rsa',
775 strlen($encryption),
776 $encryption,
777 strlen($this->comment),
778 $this->comment,
779 strlen($public),
780 $public
781 );
782 $public = base64_encode($public);
783 $key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";
784 $key.= chunk_split($public, 64);
785 $private = pack(
786 'Na*Na*Na*Na*',
787 strlen($raw['privateExponent']),
788 $raw['privateExponent'],
789 strlen($raw['prime1']),
790 $raw['prime1'],
791 strlen($raw['prime2']),
792 $raw['prime2'],
793 strlen($raw['coefficient']),
794 $raw['coefficient']
795 );
796 if (empty($this->password) && !is_string($this->password)) {
797 $source.= pack('Na*', strlen($private), $private);
798 $hashkey = 'putty-private-key-file-mac-key';
799 } else {
800 $private.= Random::string(16 - (strlen($private) & 15));
801 $source.= pack('Na*', strlen($private), $private);
802 $sequence = 0;
803 $symkey = '';
804 while (strlen($symkey) < 32) {
805 $temp = pack('Na*', $sequence++, $this->password);
806 $symkey.= pack('H*', sha1($temp));
807 }
808 $symkey = substr($symkey, 0, 32);
809 $crypto = new AES();
810
811 $crypto->setKey($symkey);
812 $crypto->disablePadding();
813 $private = $crypto->encrypt($private);
814 $hashkey = 'putty-private-key-file-mac-key' . $this->password;
815 }
816
817 $private = base64_encode($private);
818 $key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n";
819 $key.= chunk_split($private, 64);
820 $hash = new Hash('sha1');
821 $hash->setKey(pack('H*', sha1($hashkey)));
822 $key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
823
824 return $key;
825 default: // eg. self::PRIVATE_FORMAT_PKCS1
826 $components = array();
827 foreach ($raw as $name => $value) {
828 $components[$name] = pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
829 }
830
831 $RSAPrivateKey = implode('', $components);
832
833 if ($num_primes > 2) {
834 $OtherPrimeInfos = '';
835 for ($i = 3; $i <= $num_primes; $i++) {
836 // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
837 //
838 // OtherPrimeInfo ::= SEQUENCE {
839 // prime INTEGER, -- ri
840 // exponent INTEGER, -- di
841 // coefficient INTEGER -- ti
842 // }
843 $OtherPrimeInfo = pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
844 $OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
845 $OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
846 $OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
847 }
848 $RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
849 }
850
851 $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
852
853 if ($this->privateKeyFormat == self::PRIVATE_FORMAT_PKCS8) {
854 $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
855 $RSAPrivateKey = pack(
856 'Ca*a*Ca*a*',
857 self::ASN1_INTEGER,
858 "\01\00",
859 $rsaOID,
860 4,
861 $this->_encodeLength(strlen($RSAPrivateKey)),
862 $RSAPrivateKey
863 );
864 $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
865 if (!empty($this->password) || is_string($this->password)) {
866 $salt = Random::string(8);
867 $iterationCount = 2048;
868
869 $crypto = new DES();
870 $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
871 $RSAPrivateKey = $crypto->encrypt($RSAPrivateKey);
872
873 $parameters = pack(
874 'Ca*a*Ca*N',
875 self::ASN1_OCTETSTRING,
876 $this->_encodeLength(strlen($salt)),
877 $salt,
878 self::ASN1_INTEGER,
879 $this->_encodeLength(4),
880 $iterationCount
881 );
882 $pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03";
883
884 $encryptionAlgorithm = pack(
885 'Ca*a*Ca*a*',
886 self::ASN1_OBJECT,
887 $this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)),
888 $pbeWithMD5AndDES_CBC,
889 self::ASN1_SEQUENCE,
890 $this->_encodeLength(strlen($parameters)),
891 $parameters
892 );
893
894 $RSAPrivateKey = pack(
895 'Ca*a*Ca*a*',
896 self::ASN1_SEQUENCE,
897 $this->_encodeLength(strlen($encryptionAlgorithm)),
898 $encryptionAlgorithm,
899 self::ASN1_OCTETSTRING,
900 $this->_encodeLength(strlen($RSAPrivateKey)),
901 $RSAPrivateKey
902 );
903
904 $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
905
906 $RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" .
907 chunk_split(base64_encode($RSAPrivateKey), 64) .
908 '-----END ENCRYPTED PRIVATE KEY-----';
909 } else {
910 $RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" .
911 chunk_split(base64_encode($RSAPrivateKey), 64) .
912 '-----END PRIVATE KEY-----';
913 }
914 return $RSAPrivateKey;
915 }
916
917 if (!empty($this->password) || is_string($this->password)) {
918 $iv = Random::string(8);
919 $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
920 $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
921 $des = new TripleDES();
922 $des->setKey($symkey);
923 $des->setIV($iv);
924 $iv = strtoupper(bin2hex($iv));
925 $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
926 "Proc-Type: 4,ENCRYPTED\r\n" .
927 "DEK-Info: DES-EDE3-CBC,$iv\r\n" .
928 "\r\n" .
929 chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) .
930 '-----END RSA PRIVATE KEY-----';
931 } else {
932 $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
933 chunk_split(base64_encode($RSAPrivateKey), 64) .
934 '-----END RSA PRIVATE KEY-----';
935 }
936
937 return $RSAPrivateKey;
938 }
939 }
940
949 function _convertPublicKey($n, $e)
950 {
951 $signed = $this->publicKeyFormat != self::PUBLIC_FORMAT_XML;
952
953 $modulus = $n->toBytes($signed);
954 $publicExponent = $e->toBytes($signed);
955
956 switch ($this->publicKeyFormat) {
958 return array('e' => $e->copy(), 'n' => $n->copy());
960 return "<RSAKeyValue>\r\n" .
961 ' <Modulus>' . base64_encode($modulus) . "</Modulus>\r\n" .
962 ' <Exponent>' . base64_encode($publicExponent) . "</Exponent>\r\n" .
963 '</RSAKeyValue>';
964 break;
966 // from <http://tools.ietf.org/html/rfc4253#page-15>:
967 // string "ssh-rsa"
968 // mpint e
969 // mpint n
970 $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
971 $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $this->comment;
972
973 return $RSAPublicKey;
974 default: // eg. self::PUBLIC_FORMAT_PKCS1_RAW or self::PUBLIC_FORMAT_PKCS1
975 // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
976 // RSAPublicKey ::= SEQUENCE {
977 // modulus INTEGER, -- n
978 // publicExponent INTEGER -- e
979 // }
980 $components = array(
981 'modulus' => pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
982 'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
983 );
984
985 $RSAPublicKey = pack(
986 'Ca*a*a*',
987 self::ASN1_SEQUENCE,
988 $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
989 $components['modulus'],
990 $components['publicExponent']
991 );
992
993 if ($this->publicKeyFormat == self::PUBLIC_FORMAT_PKCS1_RAW) {
994 $RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" .
995 chunk_split(base64_encode($RSAPublicKey), 64) .
996 '-----END RSA PUBLIC KEY-----';
997 } else {
998 // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
999 $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
1000 $RSAPublicKey = chr(0) . $RSAPublicKey;
1001 $RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
1002
1003 $RSAPublicKey = pack(
1004 'Ca*a*',
1005 self::ASN1_SEQUENCE,
1006 $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)),
1007 $rsaOID . $RSAPublicKey
1008 );
1009
1010 $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
1011 chunk_split(base64_encode($RSAPublicKey), 64) .
1012 '-----END PUBLIC KEY-----';
1013 }
1014
1015 return $RSAPublicKey;
1016 }
1017 }
1018
1030 {
1031 if ($type != self::PUBLIC_FORMAT_RAW && !is_string($key)) {
1032 return false;
1033 }
1034
1035 switch ($type) {
1037 if (!is_array($key)) {
1038 return false;
1039 }
1040 $components = array();
1041 switch (true) {
1042 case isset($key['e']):
1043 $components['publicExponent'] = $key['e']->copy();
1044 break;
1045 case isset($key['exponent']):
1046 $components['publicExponent'] = $key['exponent']->copy();
1047 break;
1048 case isset($key['publicExponent']):
1049 $components['publicExponent'] = $key['publicExponent']->copy();
1050 break;
1051 case isset($key[0]):
1052 $components['publicExponent'] = $key[0]->copy();
1053 }
1054 switch (true) {
1055 case isset($key['n']):
1056 $components['modulus'] = $key['n']->copy();
1057 break;
1058 case isset($key['modulo']):
1059 $components['modulus'] = $key['modulo']->copy();
1060 break;
1061 case isset($key['modulus']):
1062 $components['modulus'] = $key['modulus']->copy();
1063 break;
1064 case isset($key[1]):
1065 $components['modulus'] = $key[1]->copy();
1066 }
1067 return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
1071 /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
1072 "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
1073 protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
1074 two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
1075
1076 http://tools.ietf.org/html/rfc1421#section-4.6.1.1
1077 http://tools.ietf.org/html/rfc1421#section-4.6.1.3
1078
1079 DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
1080 DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
1081 function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
1082 own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
1083 implementation are part of the standard, as well.
1084
1085 * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
1086 if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
1087 $iv = pack('H*', trim($matches[2]));
1088 $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key
1089 $symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8)));
1090 // remove the Proc-Type / DEK-Info sections as they're no longer needed
1091 $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
1092 $ciphertext = $this->_extractBER($key);
1093 if ($ciphertext === false) {
1094 $ciphertext = $key;
1095 }
1096 switch ($matches[1]) {
1097 case 'AES-256-CBC':
1098 $crypto = new AES();
1099 break;
1100 case 'AES-128-CBC':
1101 $symkey = substr($symkey, 0, 16);
1102 $crypto = new AES();
1103 break;
1104 case 'DES-EDE3-CFB':
1105 $crypto = new TripleDES(Base::MODE_CFB);
1106 break;
1107 case 'DES-EDE3-CBC':
1108 $symkey = substr($symkey, 0, 24);
1109 $crypto = new TripleDES();
1110 break;
1111 case 'DES-CBC':
1112 $crypto = new DES();
1113 break;
1114 default:
1115 return false;
1116 }
1117 $crypto->setKey($symkey);
1118 $crypto->setIV($iv);
1119 $decoded = $crypto->decrypt($ciphertext);
1120 } else {
1121 $decoded = $this->_extractBER($key);
1122 }
1123
1124 if ($decoded !== false) {
1125 $key = $decoded;
1126 }
1127
1128 $components = array();
1129
1130 if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
1131 return false;
1132 }
1133 if ($this->_decodeLength($key) != strlen($key)) {
1134 return false;
1135 }
1136
1137 $tag = ord($this->_string_shift($key));
1138 /* intended for keys for which OpenSSL's asn1parse returns the following:
1139
1140 0:d=0 hl=4 l= 631 cons: SEQUENCE
1141 4:d=1 hl=2 l= 1 prim: INTEGER :00
1142 7:d=1 hl=2 l= 13 cons: SEQUENCE
1143 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
1144 20:d=2 hl=2 l= 0 prim: NULL
1145 22:d=1 hl=4 l= 609 prim: OCTET STRING
1146
1147 ie. PKCS8 keys*/
1148
1149 if ($tag == self::ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
1150 $this->_string_shift($key, 3);
1152 }
1153
1154 if ($tag == self::ASN1_SEQUENCE) {
1155 $temp = $this->_string_shift($key, $this->_decodeLength($key));
1156 if (ord($this->_string_shift($temp)) != self::ASN1_OBJECT) {
1157 return false;
1158 }
1159 $length = $this->_decodeLength($temp);
1160 switch ($this->_string_shift($temp, $length)) {
1161 case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption
1162 break;
1163 case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC
1164 /*
1165 PBEParameter ::= SEQUENCE {
1166 salt OCTET STRING (SIZE(8)),
1167 iterationCount INTEGER }
1168 */
1169 if (ord($this->_string_shift($temp)) != self::ASN1_SEQUENCE) {
1170 return false;
1171 }
1172 if ($this->_decodeLength($temp) != strlen($temp)) {
1173 return false;
1174 }
1175 $this->_string_shift($temp); // assume it's an octet string
1176 $salt = $this->_string_shift($temp, $this->_decodeLength($temp));
1177 if (ord($this->_string_shift($temp)) != self::ASN1_INTEGER) {
1178 return false;
1179 }
1180 $this->_decodeLength($temp);
1181 list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
1182 $this->_string_shift($key); // assume it's an octet string
1183 $length = $this->_decodeLength($key);
1184 if (strlen($key) != $length) {
1185 return false;
1186 }
1187
1188 $crypto = new DES();
1189 $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
1190 $key = $crypto->decrypt($key);
1191 if ($key === false) {
1192 return false;
1193 }
1194 return $this->_parseKey($key, self::PRIVATE_FORMAT_PKCS1);
1195 default:
1196 return false;
1197 }
1198 /* intended for keys for which OpenSSL's asn1parse returns the following:
1199
1200 0:d=0 hl=4 l= 290 cons: SEQUENCE
1201 4:d=1 hl=2 l= 13 cons: SEQUENCE
1202 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
1203 17:d=2 hl=2 l= 0 prim: NULL
1204 19:d=1 hl=4 l= 271 prim: BIT STRING */
1205 $tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
1206 $this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
1207 // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
1208 // unused bits in the final subsequent octet. The number shall be in the range zero to seven."
1209 // -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
1210 if ($tag == self::ASN1_BITSTRING) {
1211 $this->_string_shift($key);
1212 }
1213 if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
1214 return false;
1215 }
1216 if ($this->_decodeLength($key) != strlen($key)) {
1217 return false;
1218 }
1219 $tag = ord($this->_string_shift($key));
1220 }
1221 if ($tag != self::ASN1_INTEGER) {
1222 return false;
1223 }
1224
1225 $length = $this->_decodeLength($key);
1226 $temp = $this->_string_shift($key, $length);
1227 if (strlen($temp) != 1 || ord($temp) > 2) {
1228 $components['modulus'] = new BigInteger($temp, 256);
1229 $this->_string_shift($key); // skip over self::ASN1_INTEGER
1230 $length = $this->_decodeLength($key);
1231 $components[$type == self::PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new BigInteger($this->_string_shift($key, $length), 256);
1232
1233 return $components;
1234 }
1235 if (ord($this->_string_shift($key)) != self::ASN1_INTEGER) {
1236 return false;
1237 }
1238 $length = $this->_decodeLength($key);
1239 $components['modulus'] = new BigInteger($this->_string_shift($key, $length), 256);
1240 $this->_string_shift($key);
1241 $length = $this->_decodeLength($key);
1242 $components['publicExponent'] = new BigInteger($this->_string_shift($key, $length), 256);
1243 $this->_string_shift($key);
1244 $length = $this->_decodeLength($key);
1245 $components['privateExponent'] = new BigInteger($this->_string_shift($key, $length), 256);
1246 $this->_string_shift($key);
1247 $length = $this->_decodeLength($key);
1248 $components['primes'] = array(1 => new BigInteger($this->_string_shift($key, $length), 256));
1249 $this->_string_shift($key);
1250 $length = $this->_decodeLength($key);
1251 $components['primes'][] = new BigInteger($this->_string_shift($key, $length), 256);
1252 $this->_string_shift($key);
1253 $length = $this->_decodeLength($key);
1254 $components['exponents'] = array(1 => new BigInteger($this->_string_shift($key, $length), 256));
1255 $this->_string_shift($key);
1256 $length = $this->_decodeLength($key);
1257 $components['exponents'][] = new BigInteger($this->_string_shift($key, $length), 256);
1258 $this->_string_shift($key);
1259 $length = $this->_decodeLength($key);
1260 $components['coefficients'] = array(2 => new BigInteger($this->_string_shift($key, $length), 256));
1261
1262 if (!empty($key)) {
1263 if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
1264 return false;
1265 }
1266 $this->_decodeLength($key);
1267 while (!empty($key)) {
1268 if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
1269 return false;
1270 }
1271 $this->_decodeLength($key);
1272 $key = substr($key, 1);
1273 $length = $this->_decodeLength($key);
1274 $components['primes'][] = new BigInteger($this->_string_shift($key, $length), 256);
1275 $this->_string_shift($key);
1276 $length = $this->_decodeLength($key);
1277 $components['exponents'][] = new BigInteger($this->_string_shift($key, $length), 256);
1278 $this->_string_shift($key);
1279 $length = $this->_decodeLength($key);
1280 $components['coefficients'][] = new BigInteger($this->_string_shift($key, $length), 256);
1281 }
1282 }
1283
1284 return $components;
1286 $parts = explode(' ', $key, 3);
1287
1288 $key = isset($parts[1]) ? base64_decode($parts[1]) : false;
1289 if ($key === false) {
1290 return false;
1291 }
1292
1293 $comment = isset($parts[2]) ? $parts[2] : false;
1294
1295 $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
1296
1297 if (strlen($key) <= 4) {
1298 return false;
1299 }
1300 extract(unpack('Nlength', $this->_string_shift($key, 4)));
1301 $publicExponent = new BigInteger($this->_string_shift($key, $length), -256);
1302 if (strlen($key) <= 4) {
1303 return false;
1304 }
1305 extract(unpack('Nlength', $this->_string_shift($key, 4)));
1306 $modulus = new BigInteger($this->_string_shift($key, $length), -256);
1307
1308 if ($cleanup && strlen($key)) {
1309 if (strlen($key) <= 4) {
1310 return false;
1311 }
1312 extract(unpack('Nlength', $this->_string_shift($key, 4)));
1313 $realModulus = new BigInteger($this->_string_shift($key, $length), -256);
1314 return strlen($key) ? false : array(
1315 'modulus' => $realModulus,
1316 'publicExponent' => $modulus,
1317 'comment' => $comment
1318 );
1319 } else {
1320 return strlen($key) ? false : array(
1321 'modulus' => $modulus,
1322 'publicExponent' => $publicExponent,
1323 'comment' => $comment
1324 );
1325 }
1326 // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
1327 // http://en.wikipedia.org/wiki/XML_Signature
1330 $this->components = array();
1331
1332 $xml = xml_parser_create('UTF-8');
1333 xml_set_object($xml, $this);
1334 xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
1335 xml_set_character_data_handler($xml, '_data_handler');
1336 // add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
1337 if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
1338 return false;
1339 }
1340
1341 return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
1342 // from PuTTY's SSHPUBK.C
1344 $components = array();
1345 $key = preg_split('#\r\n|\r|\n#', $key);
1346 $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
1347 if ($type != 'ssh-rsa') {
1348 return false;
1349 }
1350 $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
1351 $comment = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
1352
1353 $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
1354 $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
1355 $public = substr($public, 11);
1356 extract(unpack('Nlength', $this->_string_shift($public, 4)));
1357 $components['publicExponent'] = new BigInteger($this->_string_shift($public, $length), -256);
1358 extract(unpack('Nlength', $this->_string_shift($public, 4)));
1359 $components['modulus'] = new BigInteger($this->_string_shift($public, $length), -256);
1360
1361 $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
1362 $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
1363
1364 switch ($encryption) {
1365 case 'aes256-cbc':
1366 $symkey = '';
1367 $sequence = 0;
1368 while (strlen($symkey) < 32) {
1369 $temp = pack('Na*', $sequence++, $this->password);
1370 $symkey.= pack('H*', sha1($temp));
1371 }
1372 $symkey = substr($symkey, 0, 32);
1373 $crypto = new AES();
1374 }
1375
1376 if ($encryption != 'none') {
1377 $crypto->setKey($symkey);
1378 $crypto->disablePadding();
1379 $private = $crypto->decrypt($private);
1380 if ($private === false) {
1381 return false;
1382 }
1383 }
1384
1385 extract(unpack('Nlength', $this->_string_shift($private, 4)));
1386 if (strlen($private) < $length) {
1387 return false;
1388 }
1389 $components['privateExponent'] = new BigInteger($this->_string_shift($private, $length), -256);
1390 extract(unpack('Nlength', $this->_string_shift($private, 4)));
1391 if (strlen($private) < $length) {
1392 return false;
1393 }
1394 $components['primes'] = array(1 => new BigInteger($this->_string_shift($private, $length), -256));
1395 extract(unpack('Nlength', $this->_string_shift($private, 4)));
1396 if (strlen($private) < $length) {
1397 return false;
1398 }
1399 $components['primes'][] = new BigInteger($this->_string_shift($private, $length), -256);
1400
1401 $temp = $components['primes'][1]->subtract($this->one);
1402 $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
1403 $temp = $components['primes'][2]->subtract($this->one);
1404 $components['exponents'][] = $components['publicExponent']->modInverse($temp);
1405
1406 extract(unpack('Nlength', $this->_string_shift($private, 4)));
1407 if (strlen($private) < $length) {
1408 return false;
1409 }
1410 $components['coefficients'] = array(2 => new BigInteger($this->_string_shift($private, $length), -256));
1411
1412 return $components;
1413 }
1414 }
1415
1424 function getSize()
1425 {
1426 return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits());
1427 }
1428
1440 {
1441 //$name = strtoupper($name);
1442 switch ($name) {
1443 case 'MODULUS':
1444 $this->current = &$this->components['modulus'];
1445 break;
1446 case 'EXPONENT':
1447 $this->current = &$this->components['publicExponent'];
1448 break;
1449 case 'P':
1450 $this->current = &$this->components['primes'][1];
1451 break;
1452 case 'Q':
1453 $this->current = &$this->components['primes'][2];
1454 break;
1455 case 'DP':
1456 $this->current = &$this->components['exponents'][1];
1457 break;
1458 case 'DQ':
1459 $this->current = &$this->components['exponents'][2];
1460 break;
1461 case 'INVERSEQ':
1462 $this->current = &$this->components['coefficients'][2];
1463 break;
1464 case 'D':
1465 $this->current = &$this->components['privateExponent'];
1466 }
1467 $this->current = '';
1468 }
1469
1480 {
1481 if (isset($this->current)) {
1482 $this->current = new BigInteger(base64_decode($this->current), 256);
1483 unset($this->current);
1484 }
1485 }
1486
1497 {
1498 if (!isset($this->current) || is_object($this->current)) {
1499 return;
1500 }
1501 $this->current.= trim($data);
1502 }
1503
1513 function loadKey($key, $type = false)
1514 {
1515 if ($key instanceof RSA) {
1516 $this->privateKeyFormat = $key->privateKeyFormat;
1517 $this->publicKeyFormat = $key->publicKeyFormat;
1518 $this->k = $key->k;
1519 $this->hLen = $key->hLen;
1520 $this->sLen = $key->sLen;
1521 $this->mgfHLen = $key->mgfHLen;
1522 $this->encryptionMode = $key->encryptionMode;
1523 $this->signatureMode = $key->signatureMode;
1524 $this->password = $key->password;
1525 $this->configFile = $key->configFile;
1526 $this->comment = $key->comment;
1527
1528 if (is_object($key->hash)) {
1529 $this->hash = new Hash($key->hash->getHash());
1530 }
1531 if (is_object($key->mgfHash)) {
1532 $this->mgfHash = new Hash($key->mgfHash->getHash());
1533 }
1534
1535 if (is_object($key->modulus)) {
1536 $this->modulus = $key->modulus->copy();
1537 }
1538 if (is_object($key->exponent)) {
1539 $this->exponent = $key->exponent->copy();
1540 }
1541 if (is_object($key->publicExponent)) {
1542 $this->publicExponent = $key->publicExponent->copy();
1543 }
1544
1545 $this->primes = array();
1546 $this->exponents = array();
1547 $this->coefficients = array();
1548
1549 foreach ($this->primes as $prime) {
1550 $this->primes[] = $prime->copy();
1551 }
1552 foreach ($this->exponents as $exponent) {
1553 $this->exponents[] = $exponent->copy();
1554 }
1555 foreach ($this->coefficients as $coefficient) {
1556 $this->coefficients[] = $coefficient->copy();
1557 }
1558
1559 return true;
1560 }
1561
1562 if ($type === false) {
1563 $types = array(
1564 self::PUBLIC_FORMAT_RAW,
1565 self::PRIVATE_FORMAT_PKCS1,
1566 self::PRIVATE_FORMAT_XML,
1567 self::PRIVATE_FORMAT_PUTTY,
1568 self::PUBLIC_FORMAT_OPENSSH
1569 );
1570 foreach ($types as $type) {
1571 $components = $this->_parseKey($key, $type);
1572 if ($components !== false) {
1573 break;
1574 }
1575 }
1576 } else {
1577 $components = $this->_parseKey($key, $type);
1578 }
1579
1580 if ($components === false) {
1581 return false;
1582 }
1583
1584 if (isset($components['comment']) && $components['comment'] !== false) {
1585 $this->comment = $components['comment'];
1586 }
1587 $this->modulus = $components['modulus'];
1588 $this->k = strlen($this->modulus->toBytes());
1589 $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
1590 if (isset($components['primes'])) {
1591 $this->primes = $components['primes'];
1592 $this->exponents = $components['exponents'];
1593 $this->coefficients = $components['coefficients'];
1594 $this->publicExponent = $components['publicExponent'];
1595 } else {
1596 $this->primes = array();
1597 $this->exponents = array();
1598 $this->coefficients = array();
1599 $this->publicExponent = false;
1600 }
1601
1602 switch ($type) {
1605 $this->setPublicKey();
1606 break;
1608 switch (true) {
1609 case strpos($key, '-BEGIN PUBLIC KEY-') !== false:
1610 case strpos($key, '-BEGIN RSA PUBLIC KEY-') !== false:
1611 $this->setPublicKey();
1612 }
1613 }
1614
1615 return true;
1616 }
1617
1629 function setPassword($password = false)
1630 {
1631 $this->password = $password;
1632 }
1633
1655 function setPublicKey($key = false, $type = false)
1656 {
1657 // if a public key has already been loaded return false
1658 if (!empty($this->publicExponent)) {
1659 return false;
1660 }
1661
1662 if ($key === false && !empty($this->modulus)) {
1663 $this->publicExponent = $this->exponent;
1664 return true;
1665 }
1666
1667 if ($type === false) {
1668 $types = array(
1669 self::PUBLIC_FORMAT_RAW,
1670 self::PUBLIC_FORMAT_PKCS1,
1671 self::PUBLIC_FORMAT_XML,
1672 self::PUBLIC_FORMAT_OPENSSH
1673 );
1674 foreach ($types as $type) {
1675 $components = $this->_parseKey($key, $type);
1676 if ($components !== false) {
1677 break;
1678 }
1679 }
1680 } else {
1681 $components = $this->_parseKey($key, $type);
1682 }
1683
1684 if ($components === false) {
1685 return false;
1686 }
1687
1688 if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
1689 $this->modulus = $components['modulus'];
1690 $this->exponent = $this->publicExponent = $components['publicExponent'];
1691 return true;
1692 }
1693
1694 $this->publicExponent = $components['publicExponent'];
1695
1696 return true;
1697 }
1698
1715 function setPrivateKey($key = false, $type = false)
1716 {
1717 if ($key === false && !empty($this->publicExponent)) {
1718 unset($this->publicExponent);
1719 return true;
1720 }
1721
1722 $rsa = new RSA();
1723 if (!$rsa->loadKey($key, $type)) {
1724 return false;
1725 }
1726 unset($rsa->publicExponent);
1727
1728 // don't overwrite the old key if the new key is invalid
1729 $this->loadKey($rsa);
1730 return true;
1731 }
1732
1745 function getPublicKey($type = self::PUBLIC_FORMAT_PKCS8)
1746 {
1747 if (empty($this->modulus) || empty($this->publicExponent)) {
1748 return false;
1749 }
1750
1751 $oldFormat = $this->publicKeyFormat;
1752 $this->publicKeyFormat = $type;
1753 $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
1754 $this->publicKeyFormat = $oldFormat;
1755 return $temp;
1756 }
1757
1770 public function getPublicKeyFingerprint($algorithm = 'md5')
1771 {
1772 if (empty($this->modulus) || empty($this->publicExponent)) {
1773 return false;
1774 }
1775
1776 $modulus = $this->modulus->toBytes(true);
1777 $publicExponent = $this->publicExponent->toBytes(true);
1778
1779 $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
1780
1781 switch ($algorithm) {
1782 case 'sha256':
1783 $hash = new Hash('sha256');
1784 $base = base64_encode($hash->hash($RSAPublicKey));
1785 return substr($base, 0, strlen($base) - 1);
1786 case 'md5':
1787 return substr(chunk_split(md5($RSAPublicKey), 2, ':'), 0, -1);
1788 default:
1789 return false;
1790 }
1791 }
1792
1804 function getPrivateKey($type = self::PUBLIC_FORMAT_PKCS1)
1805 {
1806 if (empty($this->primes)) {
1807 return false;
1808 }
1809
1810 $oldFormat = $this->privateKeyFormat;
1811 $this->privateKeyFormat = $type;
1812 $temp = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients);
1813 $this->privateKeyFormat = $oldFormat;
1814 return $temp;
1815 }
1816
1828 function _getPrivatePublicKey($mode = self::PUBLIC_FORMAT_PKCS8)
1829 {
1830 if (empty($this->modulus) || empty($this->exponent)) {
1831 return false;
1832 }
1833
1834 $oldFormat = $this->publicKeyFormat;
1835 $this->publicKeyFormat = $mode;
1836 $temp = $this->_convertPublicKey($this->modulus, $this->exponent);
1837 $this->publicKeyFormat = $oldFormat;
1838 return $temp;
1839 }
1840
1847 function __toString()
1848 {
1849 $key = $this->getPrivateKey($this->privateKeyFormat);
1850 if ($key !== false) {
1851 return $key;
1852 }
1853 $key = $this->_getPrivatePublicKey($this->publicKeyFormat);
1854 return $key !== false ? $key : '';
1855 }
1856
1863 function __clone()
1864 {
1865 $key = new RSA();
1866 $key->loadKey($this);
1867 return $key;
1868 }
1869
1877 function _generateMinMax($bits)
1878 {
1879 $bytes = $bits >> 3;
1880 $min = str_repeat(chr(0), $bytes);
1881 $max = str_repeat(chr(0xFF), $bytes);
1882 $msb = $bits & 7;
1883 if ($msb) {
1884 $min = chr(1 << ($msb - 1)) . $min;
1885 $max = chr((1 << $msb) - 1) . $max;
1886 } else {
1887 $min[0] = chr(0x80);
1888 }
1889
1890 return array(
1891 'min' => new BigInteger($min, 256),
1892 'max' => new BigInteger($max, 256)
1893 );
1894 }
1895
1906 function _decodeLength(&$string)
1907 {
1908 $length = ord($this->_string_shift($string));
1909 if ($length & 0x80) { // definite length, long form
1910 $length&= 0x7F;
1911 $temp = $this->_string_shift($string, $length);
1912 list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
1913 }
1914 return $length;
1915 }
1916
1927 function _encodeLength($length)
1928 {
1929 if ($length <= 0x7F) {
1930 return chr($length);
1931 }
1932
1933 $temp = ltrim(pack('N', $length), chr(0));
1934 return pack('Ca*', 0x80 | strlen($temp), $temp);
1935 }
1936
1947 function _string_shift(&$string, $index = 1)
1948 {
1949 $substr = substr($string, 0, $index);
1950 $string = substr($string, $index);
1951 return $substr;
1952 }
1953
1962 {
1963 $this->privateKeyFormat = $format;
1964 }
1965
1974 {
1975 $this->publicKeyFormat = $format;
1976 }
1977
1987 function setHash($hash)
1988 {
1989 // \phpseclib\Crypt\Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
1990 switch ($hash) {
1991 case 'md2':
1992 case 'md5':
1993 case 'sha1':
1994 case 'sha256':
1995 case 'sha384':
1996 case 'sha512':
1997 $this->hash = new Hash($hash);
1998 $this->hashName = $hash;
1999 break;
2000 default:
2001 $this->hash = new Hash('sha1');
2002 $this->hashName = 'sha1';
2003 }
2004 $this->hLen = $this->hash->getLength();
2005 }
2006
2016 function setMGFHash($hash)
2017 {
2018 // \phpseclib\Crypt\Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
2019 switch ($hash) {
2020 case 'md2':
2021 case 'md5':
2022 case 'sha1':
2023 case 'sha256':
2024 case 'sha384':
2025 case 'sha512':
2026 $this->mgfHash = new Hash($hash);
2027 break;
2028 default:
2029 $this->mgfHash = new Hash('sha1');
2030 }
2031 $this->mgfHLen = $this->mgfHash->getLength();
2032 }
2033
2046 {
2047 $this->sLen = $sLen;
2048 }
2049
2060 function _i2osp($x, $xLen)
2061 {
2062 $x = $x->toBytes();
2063 if (strlen($x) > $xLen) {
2064 user_error('Integer too large');
2065 return false;
2066 }
2067 return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
2068 }
2069
2079 function _os2ip($x)
2080 {
2081 return new BigInteger($x, 256);
2082 }
2083
2094 {
2095 if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) {
2096 return $x->modPow($this->exponent, $this->modulus);
2097 }
2098
2099 $num_primes = count($this->primes);
2100
2101 if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
2102 $m_i = array(
2103 1 => $x->modPow($this->exponents[1], $this->primes[1]),
2104 2 => $x->modPow($this->exponents[2], $this->primes[2])
2105 );
2106 $h = $m_i[1]->subtract($m_i[2]);
2107 $h = $h->multiply($this->coefficients[2]);
2108 list(, $h) = $h->divide($this->primes[1]);
2109 $m = $m_i[2]->add($h->multiply($this->primes[2]));
2110
2111 $r = $this->primes[1];
2112 for ($i = 3; $i <= $num_primes; $i++) {
2113 $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
2114
2115 $r = $r->multiply($this->primes[$i - 1]);
2116
2117 $h = $m_i->subtract($m);
2118 $h = $h->multiply($this->coefficients[$i]);
2119 list(, $h) = $h->divide($this->primes[$i]);
2120
2121 $m = $m->add($r->multiply($h));
2122 }
2123 } else {
2124 $smallest = $this->primes[1];
2125 for ($i = 2; $i <= $num_primes; $i++) {
2126 if ($smallest->compare($this->primes[$i]) > 0) {
2127 $smallest = $this->primes[$i];
2128 }
2129 }
2130
2131 $one = new BigInteger(1);
2132
2133 $r = $one->random($one, $smallest->subtract($one));
2134
2135 $m_i = array(
2136 1 => $this->_blind($x, $r, 1),
2137 2 => $this->_blind($x, $r, 2)
2138 );
2139 $h = $m_i[1]->subtract($m_i[2]);
2140 $h = $h->multiply($this->coefficients[2]);
2141 list(, $h) = $h->divide($this->primes[1]);
2142 $m = $m_i[2]->add($h->multiply($this->primes[2]));
2143
2144 $r = $this->primes[1];
2145 for ($i = 3; $i <= $num_primes; $i++) {
2146 $m_i = $this->_blind($x, $r, $i);
2147
2148 $r = $r->multiply($this->primes[$i - 1]);
2149
2150 $h = $m_i->subtract($m);
2151 $h = $h->multiply($this->coefficients[$i]);
2152 list(, $h) = $h->divide($this->primes[$i]);
2153
2154 $m = $m->add($r->multiply($h));
2155 }
2156 }
2157
2158 return $m;
2159 }
2160
2173 function _blind($x, $r, $i)
2174 {
2175 $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
2176 $x = $x->modPow($this->exponents[$i], $this->primes[$i]);
2177
2178 $r = $r->modInverse($this->primes[$i]);
2179 $x = $x->multiply($r);
2180 list(, $x) = $x->divide($this->primes[$i]);
2181
2182 return $x;
2183 }
2184
2199 function _equals($x, $y)
2200 {
2201 if (strlen($x) != strlen($y)) {
2202 return false;
2203 }
2204
2205 $result = 0;
2206 for ($i = 0; $i < strlen($x); $i++) {
2207 $result |= ord($x[$i]) ^ ord($y[$i]);
2208 }
2209
2210 return $result == 0;
2211 }
2212
2222 function _rsaep($m)
2223 {
2224 if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
2225 user_error('Message representative out of range');
2226 return false;
2227 }
2228 return $this->_exponentiate($m);
2229 }
2230
2240 function _rsadp($c)
2241 {
2242 if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
2243 user_error('Ciphertext representative out of range');
2244 return false;
2245 }
2246 return $this->_exponentiate($c);
2247 }
2248
2258 function _rsasp1($m)
2259 {
2260 if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
2261 user_error('Message representative out of range');
2262 return false;
2263 }
2264 return $this->_exponentiate($m);
2265 }
2266
2276 function _rsavp1($s)
2277 {
2278 if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
2279 user_error('Signature representative out of range');
2280 return false;
2281 }
2282 return $this->_exponentiate($s);
2283 }
2284
2295 function _mgf1($mgfSeed, $maskLen)
2296 {
2297 // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
2298
2299 $t = '';
2300 $count = ceil($maskLen / $this->mgfHLen);
2301 for ($i = 0; $i < $count; $i++) {
2302 $c = pack('N', $i);
2303 $t.= $this->mgfHash->hash($mgfSeed . $c);
2304 }
2305
2306 return substr($t, 0, $maskLen);
2307 }
2308
2320 function _rsaes_oaep_encrypt($m, $l = '')
2321 {
2322 $mLen = strlen($m);
2323
2324 // Length checking
2325
2326 // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2327 // be output.
2328
2329 if ($mLen > $this->k - 2 * $this->hLen - 2) {
2330 user_error('Message too long');
2331 return false;
2332 }
2333
2334 // EME-OAEP encoding
2335
2336 $lHash = $this->hash->hash($l);
2337 $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
2338 $db = $lHash . $ps . chr(1) . $m;
2339 $seed = Random::string($this->hLen);
2340 $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2341 $maskedDB = $db ^ $dbMask;
2342 $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2343 $maskedSeed = $seed ^ $seedMask;
2344 $em = chr(0) . $maskedSeed . $maskedDB;
2345
2346 // RSA encryption
2347
2348 $m = $this->_os2ip($em);
2349 $c = $this->_rsaep($m);
2350 $c = $this->_i2osp($c, $this->k);
2351
2352 // Output the ciphertext C
2353
2354 return $c;
2355 }
2356
2383 function _rsaes_oaep_decrypt($c, $l = '')
2384 {
2385 // Length checking
2386
2387 // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2388 // be output.
2389
2390 if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
2391 user_error('Decryption error');
2392 return false;
2393 }
2394
2395 // RSA decryption
2396
2397 $c = $this->_os2ip($c);
2398 $m = $this->_rsadp($c);
2399 if ($m === false) {
2400 user_error('Decryption error');
2401 return false;
2402 }
2403 $em = $this->_i2osp($m, $this->k);
2404
2405 // EME-OAEP decoding
2406
2407 $lHash = $this->hash->hash($l);
2408 $y = ord($em[0]);
2409 $maskedSeed = substr($em, 1, $this->hLen);
2410 $maskedDB = substr($em, $this->hLen + 1);
2411 $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2412 $seed = $maskedSeed ^ $seedMask;
2413 $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2414 $db = $maskedDB ^ $dbMask;
2415 $lHash2 = substr($db, 0, $this->hLen);
2416 $m = substr($db, $this->hLen);
2417 if ($lHash != $lHash2) {
2418 user_error('Decryption error');
2419 return false;
2420 }
2421 $m = ltrim($m, chr(0));
2422 if (ord($m[0]) != 1) {
2423 user_error('Decryption error');
2424 return false;
2425 }
2426
2427 // Output the message M
2428
2429 return substr($m, 1);
2430 }
2431
2442 {
2443 $temp = $this->_os2ip($m);
2444 $temp = $this->_rsaep($temp);
2445 return $this->_i2osp($temp, $this->k);
2446 }
2447
2458 {
2459 $mLen = strlen($m);
2460
2461 // Length checking
2462
2463 if ($mLen > $this->k - 11) {
2464 user_error('Message too long');
2465 return false;
2466 }
2467
2468 // EME-PKCS1-v1_5 encoding
2469
2470 $psLen = $this->k - $mLen - 3;
2471 $ps = '';
2472 while (strlen($ps) != $psLen) {
2473 $temp = Random::string($psLen - strlen($ps));
2474 $temp = str_replace("\x00", '', $temp);
2475 $ps.= $temp;
2476 }
2477 $type = 2;
2478 // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done
2479 if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) {
2480 $type = 1;
2481 // "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF"
2482 $ps = str_repeat("\xFF", $psLen);
2483 }
2484 $em = chr(0) . chr($type) . $ps . chr(0) . $m;
2485
2486 // RSA encryption
2487 $m = $this->_os2ip($em);
2488 $c = $this->_rsaep($m);
2489 $c = $this->_i2osp($c, $this->k);
2490
2491 // Output the ciphertext C
2492
2493 return $c;
2494 }
2495
2517 {
2518 // Length checking
2519
2520 if (strlen($c) != $this->k) { // or if k < 11
2521 user_error('Decryption error');
2522 return false;
2523 }
2524
2525 // RSA decryption
2526
2527 $c = $this->_os2ip($c);
2528 $m = $this->_rsadp($c);
2529
2530 if ($m === false) {
2531 user_error('Decryption error');
2532 return false;
2533 }
2534 $em = $this->_i2osp($m, $this->k);
2535
2536 // EME-PKCS1-v1_5 decoding
2537
2538 if (ord($em[0]) != 0 || ord($em[1]) > 2) {
2539 user_error('Decryption error');
2540 return false;
2541 }
2542
2543 $ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
2544 $m = substr($em, strlen($ps) + 3);
2545
2546 if (strlen($ps) < 8) {
2547 user_error('Decryption error');
2548 return false;
2549 }
2550
2551 // Output M
2552
2553 return $m;
2554 }
2555
2565 function _emsa_pss_encode($m, $emBits)
2566 {
2567 // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2568 // be output.
2569
2570 $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
2571 $sLen = $this->sLen ? $this->sLen : $this->hLen;
2572
2573 $mHash = $this->hash->hash($m);
2574 if ($emLen < $this->hLen + $sLen + 2) {
2575 user_error('Encoding error');
2576 return false;
2577 }
2578
2579 $salt = Random::string($sLen);
2580 $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2581 $h = $this->hash->hash($m2);
2582 $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
2583 $db = $ps . chr(1) . $salt;
2584 $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
2585 $maskedDB = $db ^ $dbMask;
2586 $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
2587 $em = $maskedDB . $h . chr(0xBC);
2588
2589 return $em;
2590 }
2591
2603 function _emsa_pss_verify($m, $em, $emBits)
2604 {
2605 // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2606 // be output.
2607
2608 $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
2609 $sLen = $this->sLen ? $this->sLen : $this->hLen;
2610
2611 $mHash = $this->hash->hash($m);
2612 if ($emLen < $this->hLen + $sLen + 2) {
2613 return false;
2614 }
2615
2616 if ($em[strlen($em) - 1] != chr(0xBC)) {
2617 return false;
2618 }
2619
2620 $maskedDB = substr($em, 0, -$this->hLen - 1);
2621 $h = substr($em, -$this->hLen - 1, $this->hLen);
2622 $temp = chr(0xFF << ($emBits & 7));
2623 if ((~$maskedDB[0] & $temp) != $temp) {
2624 return false;
2625 }
2626 $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
2627 $db = $maskedDB ^ $dbMask;
2628 $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
2629 $temp = $emLen - $this->hLen - $sLen - 2;
2630 if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
2631 return false;
2632 }
2633 $salt = substr($db, $temp + 1); // should be $sLen long
2634 $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2635 $h2 = $this->hash->hash($m2);
2636 return $this->_equals($h, $h2);
2637 }
2638
2649 {
2650 // EMSA-PSS encoding
2651
2652 $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);
2653
2654 // RSA signature
2655
2656 $m = $this->_os2ip($em);
2657 $s = $this->_rsasp1($m);
2658 $s = $this->_i2osp($s, $this->k);
2659
2660 // Output the signature S
2661
2662 return $s;
2663 }
2664
2676 {
2677 // Length checking
2678
2679 if (strlen($s) != $this->k) {
2680 user_error('Invalid signature');
2681 return false;
2682 }
2683
2684 // RSA verification
2685
2686 $modBits = 8 * $this->k;
2687
2688 $s2 = $this->_os2ip($s);
2689 $m2 = $this->_rsavp1($s2);
2690 if ($m2 === false) {
2691 user_error('Invalid signature');
2692 return false;
2693 }
2694 $em = $this->_i2osp($m2, $modBits >> 3);
2695 if ($em === false) {
2696 user_error('Invalid signature');
2697 return false;
2698 }
2699
2700 // EMSA-PSS verification
2701
2702 return $this->_emsa_pss_verify($m, $em, $modBits - 1);
2703 }
2704
2715 function _emsa_pkcs1_v1_5_encode($m, $emLen)
2716 {
2717 $h = $this->hash->hash($m);
2718 if ($h === false) {
2719 return false;
2720 }
2721
2722 // see http://tools.ietf.org/html/rfc3447#page-43
2723 switch ($this->hashName) {
2724 case 'md2':
2725 $t = pack('H*', '3020300c06082a864886f70d020205000410');
2726 break;
2727 case 'md5':
2728 $t = pack('H*', '3020300c06082a864886f70d020505000410');
2729 break;
2730 case 'sha1':
2731 $t = pack('H*', '3021300906052b0e03021a05000414');
2732 break;
2733 case 'sha256':
2734 $t = pack('H*', '3031300d060960864801650304020105000420');
2735 break;
2736 case 'sha384':
2737 $t = pack('H*', '3041300d060960864801650304020205000430');
2738 break;
2739 case 'sha512':
2740 $t = pack('H*', '3051300d060960864801650304020305000440');
2741 }
2742 $t.= $h;
2743 $tLen = strlen($t);
2744
2745 if ($emLen < $tLen + 11) {
2746 user_error('Intended encoded message length too short');
2747 return false;
2748 }
2749
2750 $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
2751
2752 $em = "\0\1$ps\0$t";
2753
2754 return $em;
2755 }
2756
2767 {
2768 // EMSA-PKCS1-v1_5 encoding
2769
2770 $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2771 if ($em === false) {
2772 user_error('RSA modulus too short');
2773 return false;
2774 }
2775
2776 // RSA signature
2777
2778 $m = $this->_os2ip($em);
2779 $s = $this->_rsasp1($m);
2780 $s = $this->_i2osp($s, $this->k);
2781
2782 // Output the signature S
2783
2784 return $s;
2785 }
2786
2797 {
2798 // Length checking
2799
2800 if (strlen($s) != $this->k) {
2801 user_error('Invalid signature');
2802 return false;
2803 }
2804
2805 // RSA verification
2806
2807 $s = $this->_os2ip($s);
2808 $m2 = $this->_rsavp1($s);
2809 if ($m2 === false) {
2810 user_error('Invalid signature');
2811 return false;
2812 }
2813 $em = $this->_i2osp($m2, $this->k);
2814 if ($em === false) {
2815 user_error('Invalid signature');
2816 return false;
2817 }
2818
2819 // EMSA-PKCS1-v1_5 encoding
2820
2821 $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2822 if ($em2 === false) {
2823 user_error('RSA modulus too short');
2824 return false;
2825 }
2826
2827 // Compare
2828 return $this->_equals($em, $em2);
2829 }
2830
2839 function setEncryptionMode($mode)
2840 {
2841 $this->encryptionMode = $mode;
2842 }
2843
2852 function setSignatureMode($mode)
2853 {
2854 $this->signatureMode = $mode;
2855 }
2856
2864 {
2865 $this->comment = $comment;
2866 }
2867
2874 function getComment()
2875 {
2876 return $this->comment;
2877 }
2878
2891 function encrypt($plaintext)
2892 {
2893 switch ($this->encryptionMode) {
2895 $plaintext = str_split($plaintext, $this->k);
2896 $ciphertext = '';
2897 foreach ($plaintext as $m) {
2898 $ciphertext.= $this->_raw_encrypt($m);
2899 }
2900 return $ciphertext;
2902 $length = $this->k - 11;
2903 if ($length <= 0) {
2904 return false;
2905 }
2906
2907 $plaintext = str_split($plaintext, $length);
2908 $ciphertext = '';
2909 foreach ($plaintext as $m) {
2910 $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m);
2911 }
2912 return $ciphertext;
2913 //case self::ENCRYPTION_OAEP:
2914 default:
2915 $length = $this->k - 2 * $this->hLen - 2;
2916 if ($length <= 0) {
2917 return false;
2918 }
2919
2920 $plaintext = str_split($plaintext, $length);
2921 $ciphertext = '';
2922 foreach ($plaintext as $m) {
2923 $ciphertext.= $this->_rsaes_oaep_encrypt($m);
2924 }
2925 return $ciphertext;
2926 }
2927 }
2928
2937 function decrypt($ciphertext)
2938 {
2939 if ($this->k <= 0) {
2940 return false;
2941 }
2942
2943 $ciphertext = str_split($ciphertext, $this->k);
2944 $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);
2945
2946 $plaintext = '';
2947
2948 switch ($this->encryptionMode) {
2950 $decrypt = '_raw_encrypt';
2951 break;
2953 $decrypt = '_rsaes_pkcs1_v1_5_decrypt';
2954 break;
2955 //case self::ENCRYPTION_OAEP:
2956 default:
2957 $decrypt = '_rsaes_oaep_decrypt';
2958 }
2959
2960 foreach ($ciphertext as $c) {
2961 $temp = $this->$decrypt($c);
2962 if ($temp === false) {
2963 return false;
2964 }
2965 $plaintext.= $temp;
2966 }
2967
2968 return $plaintext;
2969 }
2970
2979 function sign($message)
2980 {
2981 if (empty($this->modulus) || empty($this->exponent)) {
2982 return false;
2983 }
2984
2985 switch ($this->signatureMode) {
2987 return $this->_rsassa_pkcs1_v1_5_sign($message);
2988 //case self::SIGNATURE_PSS:
2989 default:
2990 return $this->_rsassa_pss_sign($message);
2991 }
2992 }
2993
3003 function verify($message, $signature)
3004 {
3005 if (empty($this->modulus) || empty($this->exponent)) {
3006 return false;
3007 }
3008
3009 switch ($this->signatureMode) {
3011 return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
3012 //case self::SIGNATURE_PSS:
3013 default:
3014 return $this->_rsassa_pss_verify($message, $signature);
3015 }
3016 }
3017
3025 function _extractBER($str)
3026 {
3027 /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
3028 * above and beyond the ceritificate.
3029 * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
3030 *
3031 * Bag Attributes
3032 * localKeyID: 01 00 00 00
3033 * subject=/O=organization/OU=org unit/CN=common name
3034 * issuer=/O=organization/CN=common name
3035 */
3036 $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
3037 // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
3038 $temp = preg_replace('#-+[^-]+-+#', '', $temp);
3039 // remove new lines
3040 $temp = str_replace(array("\r", "\n", ' '), '', $temp);
3041 $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
3042 return $temp != false ? $temp : $str;
3043 }
3044}
$parser
Definition: BPMN2Parser.php:23
$result
$n
Definition: RandomTest.php:85
global $l
Definition: afr.php:30
$source
Definition: linkback.php:22
An exception for terminatinating execution or to throw for unit testing.
const MODE_CFB
Encrypt / decrypt using the Cipher Feedback mode.
Definition: Base.php:80
_rsasp1($m)
RSASP1.
Definition: RSA.php:2258
_encodeLength($length)
DER-encode the length.
Definition: RSA.php:1927
_exponentiate($x)
Exponentiate with or without Chinese Remainder Theorem.
Definition: RSA.php:2093
const ASN1_INTEGER
#-
Definition: RSA.php:134
_convertPublicKey($n, $e)
Convert a public key to the appropriate format.
Definition: RSA.php:949
_data_handler($parser, $data)
Data Handler.
Definition: RSA.php:1496
__toString()
__toString() magic method
Definition: RSA.php:1847
setPublicKeyFormat($format)
Determines the public key format.
Definition: RSA.php:1973
_emsa_pss_verify($m, $em, $emBits)
EMSA-PSS-VERIFY.
Definition: RSA.php:2603
setMGFHash($hash)
Determines which hashing function should be used for the mask generation function.
Definition: RSA.php:2016
getSize()
Returns the key size.
Definition: RSA.php:1424
_rsavp1($s)
RSAVP1.
Definition: RSA.php:2276
_generateMinMax($bits)
Generates the smallest and largest numbers requiring $bits bits.
Definition: RSA.php:1877
_mgf1($mgfSeed, $maskLen)
MGF1.
Definition: RSA.php:2295
_rsassa_pkcs1_v1_5_sign($m)
RSASSA-PKCS1-V1_5-SIGN.
Definition: RSA.php:2766
__clone()
__clone() magic method
Definition: RSA.php:1863
const PRIVATE_FORMAT_XML
XML formatted private key.
Definition: RSA.php:187
getPrivateKey($type=self::PUBLIC_FORMAT_PKCS1)
Returns the private key.
Definition: RSA.php:1804
_decodeLength(&$string)
DER-decode the length.
Definition: RSA.php:1906
const ENCRYPTION_NONE
Do not use any padding.
Definition: RSA.php:100
const PUBLIC_FORMAT_PKCS1_RAW
Definition: RSA.php:225
_stop_element_handler($parser, $name)
Stop Element Handler.
Definition: RSA.php:1479
_i2osp($x, $xLen)
Integer-to-Octet-String primitive.
Definition: RSA.php:2060
setSaltLength($sLen)
Determines the salt length.
Definition: RSA.php:2045
setSignatureMode($mode)
Set Signature Mode.
Definition: RSA.php:2852
_rsaes_pkcs1_v1_5_decrypt($c)
RSAES-PKCS1-V1_5-DECRYPT.
Definition: RSA.php:2516
const SIGNATURE_PSS
#-
Definition: RSA.php:117
loadKey($key, $type=false)
Loads a public or private key.
Definition: RSA.php:1513
setPublicKey($key=false, $type=false)
Defines the public key.
Definition: RSA.php:1655
_parseKey($key, $type)
Break a public or private key down into its constituant components.
Definition: RSA.php:1029
_rsaep($m)
RSAEP.
Definition: RSA.php:2222
const ENCRYPTION_PKCS1
Use PKCS#1 padding.
Definition: RSA.php:93
_blind($x, $r, $i)
Performs RSA Blinding.
Definition: RSA.php:2173
_rsassa_pss_verify($m, $s)
RSASSA-PSS-VERIFY.
Definition: RSA.php:2675
_rsadp($c)
RSADP.
Definition: RSA.php:2240
_os2ip($x)
Octet-String-to-Integer primitive.
Definition: RSA.php:2079
const ASN1_OCTETSTRING
ASN1 Octet String.
Definition: RSA.php:142
verify($message, $signature)
Verifies a signature.
Definition: RSA.php:3003
const ASN1_BITSTRING
ASN1 Bit String.
Definition: RSA.php:138
getComment()
Get public key comment.
Definition: RSA.php:2874
const MODE_INTERNAL
#-
Definition: RSA.php:160
setEncryptionMode($mode)
Set Encryption Mode.
Definition: RSA.php:2839
_raw_encrypt($m)
Raw Encryption / Decryption.
Definition: RSA.php:2441
const PRIVATE_FORMAT_PUTTY
PuTTY formatted private key.
Definition: RSA.php:183
getPublicKey($type=self::PUBLIC_FORMAT_PKCS8)
Returns the public key.
Definition: RSA.php:1745
__construct()
The constructor.
Definition: RSA.php:464
const MODE_OPENSSL
To use the OpenSSL library.
Definition: RSA.php:166
_start_element_handler($parser, $name, $attribs)
Start Element Handler.
Definition: RSA.php:1439
const PUBLIC_FORMAT_PKCS1
PKCS#1 formatted public key (raw)
Definition: RSA.php:224
_emsa_pss_encode($m, $emBits)
EMSA-PSS-ENCODE.
Definition: RSA.php:2565
_extractBER($str)
Extract raw BER from Base64 encoding.
Definition: RSA.php:3025
_rsassa_pkcs1_v1_5_verify($m, $s)
RSASSA-PKCS1-V1_5-VERIFY.
Definition: RSA.php:2796
const ASN1_SEQUENCE
ASN1 Sequence (with the constucted bit set)
Definition: RSA.php:150
sign($message)
Create a signature.
Definition: RSA.php:2979
const PUBLIC_FORMAT_RAW
#-
Definition: RSA.php:212
const PUBLIC_FORMAT_PKCS8
PKCS#1 formatted public key (encapsulated)
Definition: RSA.php:249
_rsaes_oaep_encrypt($m, $l='')
RSAES-OAEP-ENCRYPT.
Definition: RSA.php:2320
_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
Convert a private key to the appropriate format.
Definition: RSA.php:720
setPassword($password=false)
Sets the password.
Definition: RSA.php:1629
_emsa_pkcs1_v1_5_encode($m, $emLen)
EMSA-PKCS1-V1_5-ENCODE.
Definition: RSA.php:2715
encrypt($plaintext)
Encryption.
Definition: RSA.php:2891
setComment($comment)
Set public key comment.
Definition: RSA.php:2863
_equals($x, $y)
Performs blinded RSA equality testing.
Definition: RSA.php:2199
getPublicKeyFingerprint($algorithm='md5')
Returns the public key's fingerprint.
Definition: RSA.php:1770
_rsaes_pkcs1_v1_5_encrypt($m)
RSAES-PKCS1-V1_5-ENCRYPT.
Definition: RSA.php:2457
const ASN1_OBJECT
ASN1 Object Identifier.
Definition: RSA.php:146
setHash($hash)
Determines which hashing function should be used.
Definition: RSA.php:1987
const PRIVATE_FORMAT_PKCS8
PKCS#8 formatted private key.
Definition: RSA.php:191
_getPrivatePublicKey($mode=self::PUBLIC_FORMAT_PKCS8)
Returns a minimalistic private key.
Definition: RSA.php:1828
const PRIVATE_FORMAT_PKCS1
#-
Definition: RSA.php:179
setPrivateKeyFormat($format)
Determines the private key format.
Definition: RSA.php:1961
_rsaes_oaep_decrypt($c, $l='')
RSAES-OAEP-DECRYPT.
Definition: RSA.php:2383
decrypt($ciphertext)
Decryption.
Definition: RSA.php:2937
const SIGNATURE_PKCS1
Use the PKCS#1 scheme by default.
Definition: RSA.php:124
const ENCRYPTION_OAEP
#+ @access public
Definition: RSA.php:86
const PUBLIC_FORMAT_XML
XML formatted public key.
Definition: RSA.php:229
createKey($bits=1024, $timeout=false, $partial=array())
Create public / private key pair.
Definition: RSA.php:540
_string_shift(&$string, $index=1)
String Shift.
Definition: RSA.php:1947
setPrivateKey($key=false, $type=false)
Defines the private key.
Definition: RSA.php:1715
const PUBLIC_FORMAT_OPENSSH
OpenSSH formatted public key.
Definition: RSA.php:235
_rsassa_pss_sign($m)
RSASSA-PSS-SIGN.
Definition: RSA.php:2648
static string($length)
Generate a random string.
Definition: Random.php:54
comment()
Definition: comment.php:2
$x
Definition: complexTest.php:9
$key
Definition: croninfo.php:18
for( $i=6;$i< 13;$i++) for($i=1; $i< 13; $i++) $d
Definition: date.php:296
$i
Definition: disco.tpl.php:19
$y
Definition: example_007.php:83
$h
$r
Definition: example_031.php:79
$base
Definition: index.php:4
$config
Definition: bootstrap.php:15
if(function_exists( 'posix_getuid') &&posix_getuid()===0) if(!array_key_exists('t', $options)) $tag
Definition: cron.php:35
$format
Definition: metadata.php:141
$index
Definition: metadata.php:60
catch(Exception $e) $message
Pure-PHP implementation of AES.
Pure-PHP arbitrary precision integer arithmetic library.
Pure-PHP implementation of DES.
hash(StreamInterface $stream, $algo, $rawOutput=false)
Calculate a hash of a Stream.
Definition: functions.php:406
Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic...
Pure-PHP PKCS#1 compliant implementation of RSA.
Pure-PHP implementation of Triple DES.
Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic...
Definition: AES.php:50
$type
$s
Definition: pwgen.php:45
$start
Definition: bench.php:8
$data
Definition: bench.php:6