openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

RSA.class.php (112113B)


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