PageRenderTime 265ms CodeModel.GetById 81ms app.highlight 103ms RepoModel.GetById 38ms app.codeStats 8ms

/lib/phpseclib/Crypt/RSA.php

https://bitbucket.org/claudiu_marginean/magento-hg-mirror
PHP | 2119 lines | 1020 code | 221 blank | 878 comment | 163 complexity | 579c11f7b2e05cae01b67b31461ca264 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
   3
   4/**
   5 * Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA.
   6 *
   7 * PHP versions 4 and 5
   8 *
   9 * Here's an example of how to encrypt and decrypt text with this library:
  10 * <code>
  11 * <?php
  12 *    include('Crypt/RSA.php');
  13 *
  14 *    $rsa = new Crypt_RSA();
  15 *    extract($rsa->createKey());
  16 *
  17 *    $plaintext = 'terrafrost';
  18 *
  19 *    $rsa->loadKey($privatekey);
  20 *    $ciphertext = $rsa->encrypt($plaintext);
  21 *
  22 *    $rsa->loadKey($publickey);
  23 *    echo $rsa->decrypt($ciphertext);
  24 * ?>
  25 * </code>
  26 *
  27 * Here's an example of how to create signatures and verify signatures with this library:
  28 * <code>
  29 * <?php
  30 *    include('Crypt/RSA.php');
  31 *
  32 *    $rsa = new Crypt_RSA();
  33 *    extract($rsa->createKey());
  34 *
  35 *    $plaintext = 'terrafrost';
  36 *
  37 *    $rsa->loadKey($privatekey);
  38 *    $signature = $rsa->sign($plaintext);
  39 *
  40 *    $rsa->loadKey($publickey);
  41 *    echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified';
  42 * ?>
  43 * </code>
  44 *
  45 * LICENSE: This library is free software; you can redistribute it and/or
  46 * modify it under the terms of the GNU Lesser General Public
  47 * License as published by the Free Software Foundation; either
  48 * version 2.1 of the License, or (at your option) any later version.
  49 *
  50 * This library is distributed in the hope that it will be useful,
  51 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  52 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  53 * Lesser General Public License for more details.
  54 *
  55 * You should have received a copy of the GNU Lesser General Public
  56 * License along with this library; if not, write to the Free Software
  57 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  58 * MA  02111-1307  USA
  59 *
  60 * @category   Crypt
  61 * @package    Crypt_RSA
  62 * @author     Jim Wigginton <terrafrost@php.net>
  63 * @copyright  MMIX Jim Wigginton
  64 * @license    http://www.gnu.org/licenses/lgpl.txt
  65 * @version    $Id: RSA.php,v 1.15 2010/04/10 15:57:02 terrafrost Exp $
  66 * @link       http://phpseclib.sourceforge.net
  67 */
  68
  69/**
  70 * Include Math_BigInteger
  71 */
  72require_once('Math/BigInteger.php');
  73
  74/**
  75 * Include Crypt_Random
  76 */
  77require_once('Crypt/Random.php');
  78
  79/**
  80 * Include Crypt_Hash
  81 */
  82require_once('Crypt/Hash.php');
  83
  84/**#@+
  85 * @access public
  86 * @see Crypt_RSA::encrypt()
  87 * @see Crypt_RSA::decrypt()
  88 */
  89/**
  90 * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
  91 * (OAEP) for encryption / decryption.
  92 *
  93 * Uses sha1 by default.
  94 *
  95 * @see Crypt_RSA::setHash()
  96 * @see Crypt_RSA::setMGFHash()
  97 */
  98define('CRYPT_RSA_ENCRYPTION_OAEP',  1);
  99/**
 100 * Use PKCS#1 padding.
 101 *
 102 * Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
 103 * compatability with protocols (like SSH-1) written before OAEP's introduction.
 104 */
 105define('CRYPT_RSA_ENCRYPTION_PKCS1', 2);
 106/**#@-*/
 107
 108/**#@+
 109 * @access public
 110 * @see Crypt_RSA::sign()
 111 * @see Crypt_RSA::verify()
 112 * @see Crypt_RSA::setHash()
 113 */
 114/**
 115 * Use the Probabilistic Signature Scheme for signing
 116 *
 117 * Uses sha1 by default.
 118 *
 119 * @see Crypt_RSA::setSaltLength()
 120 * @see Crypt_RSA::setMGFHash()
 121 */
 122define('CRYPT_RSA_SIGNATURE_PSS',  1);
 123/**
 124 * Use the PKCS#1 scheme by default.
 125 *
 126 * Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
 127 * compatability with protocols (like SSH-2) written before PSS's introduction.
 128 */
 129define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
 130/**#@-*/
 131
 132/**#@+
 133 * @access private
 134 * @see Crypt_RSA::createKey()
 135 */
 136/**
 137 * ASN1 Integer
 138 */
 139define('CRYPT_RSA_ASN1_INTEGER',   2);
 140/**
 141 * ASN1 Sequence (with the constucted bit set)
 142 */
 143define('CRYPT_RSA_ASN1_SEQUENCE', 48);
 144/**#@-*/
 145
 146/**#@+
 147 * @access private
 148 * @see Crypt_RSA::Crypt_RSA()
 149 */
 150/**
 151 * To use the pure-PHP implementation
 152 */
 153define('CRYPT_RSA_MODE_INTERNAL', 1);
 154/**
 155 * To use the OpenSSL library
 156 *
 157 * (if enabled; otherwise, the internal implementation will be used)
 158 */
 159define('CRYPT_RSA_MODE_OPENSSL', 2);
 160/**#@-*/
 161
 162/**#@+
 163 * @access public
 164 * @see Crypt_RSA::createKey()
 165 * @see Crypt_RSA::setPrivateKeyFormat()
 166 */
 167/**
 168 * PKCS#1 formatted private key
 169 *
 170 * Used by OpenSSH
 171 */
 172define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0);
 173/**#@-*/
 174
 175/**#@+
 176 * @access public
 177 * @see Crypt_RSA::createKey()
 178 * @see Crypt_RSA::setPublicKeyFormat()
 179 */
 180/**
 181 * Raw public key
 182 *
 183 * An array containing two Math_BigInteger objects.
 184 *
 185 * The exponent can be indexed with any of the following:
 186 *
 187 * 0, e, exponent, publicExponent
 188 *
 189 * The modulus can be indexed with any of the following:
 190 *
 191 * 1, n, modulo, modulus
 192 */
 193define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 1);
 194/**
 195 * PKCS#1 formatted public key
 196 */
 197define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 2);
 198/**
 199 * OpenSSH formatted public key
 200 *
 201 * Place in $HOME/.ssh/authorized_keys
 202 */
 203define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 3);
 204/**#@-*/
 205
 206/**
 207 * Pure-PHP PKCS#1 compliant implementation of RSA.
 208 *
 209 * @author  Jim Wigginton <terrafrost@php.net>
 210 * @version 0.1.0
 211 * @access  public
 212 * @package Crypt_RSA
 213 */
 214class Crypt_RSA {
 215    /**
 216     * Precomputed Zero
 217     *
 218     * @var Array
 219     * @access private
 220     */
 221    var $zero;
 222
 223    /**
 224     * Precomputed One
 225     *
 226     * @var Array
 227     * @access private
 228     */
 229    var $one;
 230
 231    /**
 232     * Private Key Format
 233     *
 234     * @var Integer
 235     * @access private
 236     */
 237    var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1;
 238
 239    /**
 240     * Public Key Format
 241     *
 242     * @var Integer
 243     * @access public
 244     */
 245    var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS1;
 246
 247    /**
 248     * Modulus (ie. n)
 249     *
 250     * @var Math_BigInteger
 251     * @access private
 252     */
 253    var $modulus;
 254
 255    /**
 256     * Modulus length
 257     *
 258     * @var Math_BigInteger
 259     * @access private
 260     */
 261    var $k;
 262
 263    /**
 264     * Exponent (ie. e or d)
 265     *
 266     * @var Math_BigInteger
 267     * @access private
 268     */
 269    var $exponent;
 270
 271    /**
 272     * Primes for Chinese Remainder Theorem (ie. p and q)
 273     *
 274     * @var Array
 275     * @access private
 276     */
 277    var $primes;
 278
 279    /**
 280     * Exponents for Chinese Remainder Theorem (ie. dP and dQ)
 281     *
 282     * @var Array
 283     * @access private
 284     */
 285    var $exponents;
 286
 287    /**
 288     * Coefficients for Chinese Remainder Theorem (ie. qInv)
 289     *
 290     * @var Array
 291     * @access private
 292     */
 293    var $coefficients;
 294
 295    /**
 296     * Hash name
 297     *
 298     * @var String
 299     * @access private
 300     */
 301    var $hashName;
 302
 303    /**
 304     * Hash function
 305     *
 306     * @var Crypt_Hash
 307     * @access private
 308     */
 309    var $hash;
 310
 311    /**
 312     * Length of hash function output
 313     *
 314     * @var Integer
 315     * @access private
 316     */
 317    var $hLen;
 318
 319    /**
 320     * Length of salt
 321     *
 322     * @var Integer
 323     * @access private
 324     */
 325    var $sLen;
 326
 327    /**
 328     * Hash function for the Mask Generation Function
 329     *
 330     * @var Crypt_Hash
 331     * @access private
 332     */
 333    var $mgfHash;
 334
 335    /**
 336     * Length of MGF hash function output
 337     *
 338     * @var Integer
 339     * @access private
 340     */
 341    var $mgfHLen;
 342
 343    /**
 344     * Encryption mode
 345     *
 346     * @var Integer
 347     * @access private
 348     */
 349    var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP;
 350
 351    /**
 352     * Signature mode
 353     *
 354     * @var Integer
 355     * @access private
 356     */
 357    var $signatureMode = CRYPT_RSA_SIGNATURE_PSS;
 358
 359    /**
 360     * Public Exponent
 361     *
 362     * @var Mixed
 363     * @access private
 364     */
 365    var $publicExponent = false;
 366
 367    /**
 368     * Password
 369     *
 370     * @var String
 371     * @access private
 372     */
 373    var $password = '';
 374
 375    /**
 376     * The constructor
 377     *
 378     * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself.  The reason
 379     * Crypt_RSA doesn't do it is because OpenSSL doesn't fail gracefully.  openssl_pkey_new(), in particular, requires
 380     * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late.
 381     *
 382     * @return Crypt_RSA
 383     * @access public
 384     */
 385    function Crypt_RSA()
 386    {
 387        if ( !defined('CRYPT_RSA_MODE') ) {
 388            switch (true) {
 389                //case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>='):
 390                //    define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
 391                //    break;
 392                default:
 393                    define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
 394            }
 395        }
 396
 397        $this->zero = new Math_BigInteger();
 398        $this->one = new Math_BigInteger(1);
 399
 400        $this->hash = new Crypt_Hash('sha1');
 401        $this->hLen = $this->hash->getLength();
 402        $this->hashName = 'sha1';
 403        $this->mgfHash = new Crypt_Hash('sha1');
 404        $this->mgfHLen = $this->mgfHash->getLength();
 405    }
 406
 407    /**
 408     * Create public / private key pair
 409     *
 410     * Returns an array with the following three elements:
 411     *  - 'privatekey': The private key.
 412     *  - 'publickey':  The public key.
 413     *  - 'partialkey': A partially computed key (if the execution time exceeded $timeout).
 414     *                  Will need to be passed back to Crypt_RSA::createKey() as the third parameter for further processing.
 415     *
 416     * @access public
 417     * @param optional Integer $bits
 418     * @param optional Integer $timeout
 419     * @param optional Math_BigInteger $p
 420     */
 421    function createKey($bits = 1024, $timeout = false, $partial = array())
 422    {
 423        if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL ) {
 424            $rsa = openssl_pkey_new(array('private_key_bits' => $bits));
 425            openssl_pkey_export($rsa, $privatekey);
 426            $publickey = openssl_pkey_get_details($rsa);
 427            $publickey = $publickey['key'];
 428
 429            if ($this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_PKCS1) {
 430                $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1)));
 431                $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
 432            }
 433
 434            return array(
 435                'privatekey' => $privatekey,
 436                'publickey' => $publickey,
 437                'partialkey' => false
 438            );
 439        }
 440
 441        static $e;
 442        if (!isset($e)) {
 443            if (!defined('CRYPT_RSA_EXPONENT')) {
 444                // http://en.wikipedia.org/wiki/65537_%28number%29
 445                define('CRYPT_RSA_EXPONENT', '65537');
 446            }
 447            if (!defined('CRYPT_RSA_COMMENT')) {
 448                define('CRYPT_RSA_COMMENT', 'phpseclib-generated-key');
 449            }
 450            // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
 451            // than 256 bits.
 452            if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
 453                define('CRYPT_RSA_SMALLEST_PRIME', 4096);
 454            }
 455
 456            $e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
 457        }
 458
 459        extract($this->_generateMinMax($bits));
 460        $absoluteMin = $min;
 461        $temp = $bits >> 1;
 462        if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
 463            $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
 464            $temp = CRYPT_RSA_SMALLEST_PRIME;
 465        } else {
 466            $num_primes = 2;
 467        }
 468        extract($this->_generateMinMax($temp + $bits % $temp));
 469        $finalMax = $max;
 470        extract($this->_generateMinMax($temp));
 471
 472        $generator = new Math_BigInteger();
 473        $generator->setRandomGenerator('crypt_random');
 474
 475        $n = $this->one->copy();
 476        if (!empty($partial)) {
 477            extract(unserialize($partial));
 478        } else {
 479            $exponents = $coefficients = $primes = array();
 480            $lcm = array(
 481                'top' => $this->one->copy(),
 482                'bottom' => false
 483            );
 484        }
 485
 486        $start = time();
 487        $i0 = count($primes) + 1;
 488
 489        do {
 490            for ($i = $i0; $i <= $num_primes; $i++) {
 491                if ($timeout !== false) {
 492                    $timeout-= time() - $start;
 493                    $start = time();
 494                    if ($timeout <= 0) {
 495                        return serialize(array(
 496                            'privatekey' => '',
 497                            'publickey'  => '',
 498                            'partialkey' => array(
 499                                'primes' => $primes,
 500                                'coefficients' => $coefficients,
 501                                'lcm' => $lcm,
 502                                'exponents' => $exponents
 503                            )
 504                        ));
 505                    }
 506                }
 507
 508                if ($i == $num_primes) {
 509                    list($min, $temp) = $absoluteMin->divide($n);
 510                    if (!$temp->equals($this->zero)) {
 511                        $min = $min->add($this->one); // ie. ceil()
 512                    }
 513                    $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
 514                } else {
 515                    $primes[$i] = $generator->randomPrime($min, $max, $timeout);
 516                }
 517
 518                if ($primes[$i] === false) { // if we've reached the timeout
 519                    return array(
 520                        'privatekey' => '',
 521                        'publickey'  => '',
 522                        'partialkey' => empty($primes) ? '' : serialize(array(
 523                            'primes' => array_slice($primes, 0, $i - 1),
 524                            'coefficients' => $coefficients,
 525                            'lcm' => $lcm,
 526                            'exponents' => $exponents
 527                        ))
 528                    );
 529                }
 530
 531                // the first coefficient is calculated differently from the rest
 532                // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
 533                if ($i > 2) {
 534                    $coefficients[$i] = $n->modInverse($primes[$i]);
 535                }
 536
 537                $n = $n->multiply($primes[$i]);
 538
 539                $temp = $primes[$i]->subtract($this->one);
 540
 541                // textbook RSA implementations use Euler's totient function instead of the least common multiple.
 542                // see http://en.wikipedia.org/wiki/Euler%27s_totient_function
 543                $lcm['top'] = $lcm['top']->multiply($temp);
 544                $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
 545
 546                $exponents[$i] = $e->modInverse($temp);
 547            }
 548
 549            list($lcm) = $lcm['top']->divide($lcm['bottom']);
 550            $gcd = $lcm->gcd($e);
 551            $i0 = 1;
 552        } while (!$gcd->equals($this->one));
 553
 554        $d = $e->modInverse($lcm);
 555
 556        $coefficients[2] = $primes[2]->modInverse($primes[1]);
 557
 558        // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
 559        // RSAPrivateKey ::= SEQUENCE {
 560        //     version           Version,
 561        //     modulus           INTEGER,  -- n
 562        //     publicExponent    INTEGER,  -- e
 563        //     privateExponent   INTEGER,  -- d
 564        //     prime1            INTEGER,  -- p
 565        //     prime2            INTEGER,  -- q
 566        //     exponent1         INTEGER,  -- d mod (p-1)
 567        //     exponent2         INTEGER,  -- d mod (q-1)
 568        //     coefficient       INTEGER,  -- (inverse of q) mod p
 569        //     otherPrimeInfos   OtherPrimeInfos OPTIONAL
 570        // }
 571
 572        return array(
 573            'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
 574            'publickey'  => $this->_convertPublicKey($n, $e),
 575            'partialkey' => false
 576        );
 577    }
 578
 579    /**
 580     * Convert a private key to the appropriate format.
 581     *
 582     * @access private
 583     * @see setPrivateKeyFormat()
 584     * @param String $RSAPrivateKey
 585     * @return String
 586     */
 587    function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
 588    {
 589        $num_primes = count($primes);
 590        $raw = array(
 591            'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
 592            'modulus' => $n->toBytes(true),
 593            'publicExponent' => $e->toBytes(true),
 594            'privateExponent' => $d->toBytes(true),
 595            'prime1' => $primes[1]->toBytes(true),
 596            'prime2' => $primes[2]->toBytes(true),
 597            'exponent1' => $exponents[1]->toBytes(true),
 598            'exponent2' => $exponents[2]->toBytes(true),
 599            'coefficient' => $coefficients[2]->toBytes(true)
 600        );
 601
 602        // if the format in question does not support multi-prime rsa and multi-prime rsa was used,
 603        // call _convertPublicKey() instead.
 604        switch ($this->privateKeyFormat) {
 605            default: // eg. CRYPT_RSA_PRIVATE_FORMAT_PKCS1
 606                $components = array();
 607                foreach ($raw as $name => $value) {
 608                    $components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
 609                }
 610
 611                $RSAPrivateKey = implode('', $components);
 612
 613                if ($num_primes > 2) {
 614                    $OtherPrimeInfos = '';
 615                    for ($i = 3; $i <= $num_primes; $i++) {
 616                        // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
 617                        //
 618                        // OtherPrimeInfo ::= SEQUENCE {
 619                        //     prime             INTEGER,  -- ri
 620                        //     exponent          INTEGER,  -- di
 621                        //     coefficient       INTEGER   -- ti
 622                        // }
 623                        $OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
 624                        $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
 625                        $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
 626                        $OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
 627                    }
 628                    $RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
 629                }
 630
 631                $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
 632
 633                if (!empty($this->password)) {
 634                    $iv = $this->_random(8);
 635                    $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
 636                    $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
 637                    if (!class_exists('Crypt_TripleDES')) {
 638                        require_once('Crypt/TripleDES.php');
 639                    }
 640                    $des = new Crypt_TripleDES();
 641                    $des->setKey($symkey);
 642                    $des->setIV($iv);
 643                    $iv = strtoupper(bin2hex($iv));
 644                    $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
 645                                     "Proc-Type: 4,ENCRYPTED\r\n" .
 646                                     "DEK-Info: DES-EDE3-CBC,$iv\r\n" .
 647                                     "\r\n" .
 648                                     chunk_split(base64_encode($des->encrypt($RSAPrivateKey))) .
 649                                     '-----END RSA PRIVATE KEY-----';
 650                } else {
 651                    $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
 652                                     chunk_split(base64_encode($RSAPrivateKey)) .
 653                                     '-----END RSA PRIVATE KEY-----';
 654                }
 655
 656                return $RSAPrivateKey;
 657        }
 658    }
 659
 660    /**
 661     * Convert a public key to the appropriate format
 662     *
 663     * @access private
 664     * @see setPublicKeyFormat()
 665     * @param String $RSAPrivateKey
 666     * @return String
 667     */
 668    function _convertPublicKey($n, $e)
 669    {
 670        $modulus = $n->toBytes(true);
 671        $publicExponent = $e->toBytes(true);
 672
 673        switch ($this->publicKeyFormat) {
 674            case CRYPT_RSA_PUBLIC_FORMAT_RAW:
 675                return array('e' => $e->copy(), 'n' => $n->copy());
 676            case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
 677                // from <http://tools.ietf.org/html/rfc4253#page-15>:
 678                // string    "ssh-rsa"
 679                // mpint     e
 680                // mpint     n
 681                $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
 682                $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . CRYPT_RSA_COMMENT;
 683
 684                return $RSAPublicKey;
 685            default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1
 686                // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
 687                // RSAPublicKey ::= SEQUENCE {
 688                //     modulus           INTEGER,  -- n
 689                //     publicExponent    INTEGER   -- e
 690                // }
 691                $components = array(
 692                    'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
 693                    'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
 694                );
 695
 696                $RSAPublicKey = pack('Ca*a*a*',
 697                    CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
 698                    $components['modulus'], $components['publicExponent']
 699                );
 700
 701                $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
 702                                 chunk_split(base64_encode($RSAPublicKey)) .
 703                                 '-----END PUBLIC KEY-----';
 704
 705                return $RSAPublicKey;
 706        }
 707    }
 708
 709    /**
 710     * Break a public or private key down into its constituant components
 711     *
 712     * @access private
 713     * @see _convertPublicKey()
 714     * @see _convertPrivateKey()
 715     * @param String $key
 716     * @param Integer $type
 717     * @return Array
 718     */
 719    function _parseKey($key, $type)
 720    {
 721        switch ($type) {
 722            case CRYPT_RSA_PUBLIC_FORMAT_RAW:
 723                if (!is_array($key)) {
 724                    return false;
 725                }
 726                $components = array();
 727                switch (true) {
 728                    case isset($key['e']):
 729                        $components['publicExponent'] = $key['e']->copy();
 730                        break;
 731                    case isset($key['exponent']):
 732                        $components['publicExponent'] = $key['exponent']->copy();
 733                        break;
 734                    case isset($key['publicExponent']):
 735                        $components['publicExponent'] = $key['publicExponent']->copy();
 736                        break;
 737                    case isset($key[0]):
 738                        $components['publicExponent'] = $key[0]->copy();
 739                }
 740                switch (true) {
 741                    case isset($key['n']):
 742                        $components['modulus'] = $key['n']->copy();
 743                        break;
 744                    case isset($key['modulo']):
 745                        $components['modulus'] = $key['modulo']->copy();
 746                        break;
 747                    case isset($key['modulus']):
 748                        $components['modulus'] = $key['modulus']->copy();
 749                        break;
 750                    case isset($key[1]):
 751                        $components['modulus'] = $key[1]->copy();
 752                }
 753                return $components;
 754            case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
 755            case CRYPT_RSA_PUBLIC_FORMAT_PKCS1:
 756                /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
 757                   "outside the scope" of PKCS#1.  PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
 758                   protect private keys, however, that's not what OpenSSL* does.  OpenSSL protects private keys by adding
 759                   two new "fields" to the key - DEK-Info and Proc-Type.  These fields are discussed here:
 760
 761                   http://tools.ietf.org/html/rfc1421#section-4.6.1.1
 762                   http://tools.ietf.org/html/rfc1421#section-4.6.1.3
 763
 764                   DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
 765                   DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
 766                   function.  As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
 767                   own implementation.  ie. the implementation *is* the standard and any bugs that may exist in that 
 768                   implementation are part of the standard, as well.
 769
 770                   * OpenSSL is the de facto standard.  It's utilized by OpenSSH and other projects */
 771                if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
 772                    $iv = pack('H*', trim($matches[2]));
 773                    $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
 774                    $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
 775                    $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-#s', '', $key);
 776                    $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false;
 777                    if ($ciphertext === false) {
 778                        $ciphertext = $key;
 779                    }
 780                    switch ($matches[1]) {
 781                        case 'DES-EDE3-CBC':
 782                            if (!class_exists('Crypt_TripleDES')) {
 783                                require_once('Crypt/TripleDES.php');
 784                            }
 785                            $crypto = new Crypt_TripleDES();
 786                            break;
 787                        case 'DES-CBC':
 788                            if (!class_exists('Crypt_DES')) {
 789                                require_once('Crypt/DES.php');
 790                            }
 791                            $crypto = new Crypt_DES();
 792                            break;
 793                        default:
 794                            return false;
 795                    }
 796                    $crypto->setKey($symkey);
 797                    $crypto->setIV($iv);
 798                    $decoded = $crypto->decrypt($ciphertext);
 799                } else {
 800                    $decoded = preg_replace('#-.+-|[\r\n]#', '', $key);
 801                    $decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false;
 802                }
 803
 804                if ($decoded !== false) {
 805                    $key = $decoded;
 806                }
 807
 808                $components = array();
 809
 810                if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
 811                    return false;
 812                }
 813                if ($this->_decodeLength($key) != strlen($key)) {
 814                    return false;
 815                }
 816
 817                $tag = ord($this->_string_shift($key));
 818                if ($tag == CRYPT_RSA_ASN1_SEQUENCE) {
 819                    /* intended for keys for which OpenSSL's asn1parse returns the following:
 820
 821                        0:d=0  hl=4 l= 290 cons: SEQUENCE
 822                        4:d=1  hl=2 l=  13 cons:  SEQUENCE
 823                        6:d=2  hl=2 l=   9 prim:   OBJECT            :rsaEncryption
 824                       17:d=2  hl=2 l=   0 prim:   NULL
 825                       19:d=1  hl=4 l= 271 prim:  BIT STRING */
 826                    $this->_string_shift($key, $this->_decodeLength($key));
 827                    $this->_string_shift($key); // skip over the BIT STRING tag
 828                    $this->_decodeLength($key); // skip over the BIT STRING length
 829                    // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
 830                    //  unused bits in teh final subsequent octet. The number shall be in the range zero to seven."
 831                    //  -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
 832                    $this->_string_shift($key);
 833                    if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
 834                        return false;
 835                    }
 836                    if ($this->_decodeLength($key) != strlen($key)) {
 837                        return false;
 838                    }
 839                    $tag = ord($this->_string_shift($key));
 840                }
 841                if ($tag != CRYPT_RSA_ASN1_INTEGER) {
 842                    return false;
 843                }
 844
 845                $length = $this->_decodeLength($key);
 846                $temp = $this->_string_shift($key, $length);
 847                if (strlen($temp) != 1 || ord($temp) > 2) {
 848                    $components['modulus'] = new Math_BigInteger($temp, -256);
 849                    $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
 850                    $length = $this->_decodeLength($key);
 851                    $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
 852
 853                    return $components;
 854                }
 855                if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) {
 856                    return false;
 857                }
 858                $length = $this->_decodeLength($key);
 859                $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
 860                $this->_string_shift($key);
 861                $length = $this->_decodeLength($key);
 862                $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
 863                $this->_string_shift($key);
 864                $length = $this->_decodeLength($key);
 865                $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
 866                $this->_string_shift($key);
 867                $length = $this->_decodeLength($key);
 868                $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), -256));
 869                $this->_string_shift($key);
 870                $length = $this->_decodeLength($key);
 871                $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
 872                $this->_string_shift($key);
 873                $length = $this->_decodeLength($key);
 874                $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), -256));
 875                $this->_string_shift($key);
 876                $length = $this->_decodeLength($key);
 877                $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
 878                $this->_string_shift($key);
 879                $length = $this->_decodeLength($key);
 880                $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), -256));
 881
 882                if (!empty($key)) {
 883                    if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
 884                        return false;
 885                    }
 886                    $this->_decodeLength($key);
 887                    while (!empty($key)) {
 888                        if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
 889                            return false;
 890                        }
 891                        $this->_decodeLength($key);
 892                        $key = substr($key, 1);
 893                        $length = $this->_decodeLength($key);
 894                        $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
 895                        $this->_string_shift($key);
 896                        $length = $this->_decodeLength($key);
 897                        $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
 898                        $this->_string_shift($key);
 899                        $length = $this->_decodeLength($key);
 900                        $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
 901                    }
 902                }
 903
 904                return $components;
 905            case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
 906                $key = base64_decode(preg_replace('#^ssh-rsa | .+$#', '', $key));
 907                if ($key === false) {
 908                    return false;
 909                }
 910
 911                $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
 912
 913                extract(unpack('Nlength', $this->_string_shift($key, 4)));
 914                $publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256);
 915                extract(unpack('Nlength', $this->_string_shift($key, 4)));
 916                $modulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
 917
 918                if ($cleanup && strlen($key)) {
 919                    extract(unpack('Nlength', $this->_string_shift($key, 4)));
 920                    return array(
 921                        'modulus' => new Math_BigInteger($this->_string_shift($key, $length), -256),
 922                        'publicExponent' => $modulus
 923                    );
 924                } else {
 925                    return array(
 926                        'modulus' => $modulus,
 927                        'publicExponent' => $publicExponent
 928                    );
 929                }
 930        }
 931    }
 932
 933    /**
 934     * Loads a public or private key
 935     *
 936     * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
 937     *
 938     * @access public
 939     * @param String $key
 940     * @param Integer $type optional
 941     */
 942    function loadKey($key, $type = CRYPT_RSA_PRIVATE_FORMAT_PKCS1)
 943    {
 944        $components = $this->_parseKey($key, $type);
 945        if ($components === false) {
 946            return false;
 947        }
 948
 949        $this->modulus = $components['modulus'];
 950        $this->k = strlen($this->modulus->toBytes());
 951        $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
 952        if (isset($components['primes'])) {
 953            $this->primes = $components['primes'];
 954            $this->exponents = $components['exponents'];
 955            $this->coefficients = $components['coefficients'];
 956            $this->publicExponent = $components['publicExponent'];
 957        } else {
 958            $this->primes = array();
 959            $this->exponents = array();
 960            $this->coefficients = array();
 961            $this->publicExponent = false;
 962        }
 963
 964        return true;
 965    }
 966
 967    /**
 968     * Sets the password
 969     *
 970     * Private keys can be encrypted with a password.  To unset the password, pass in the empty string or false.
 971     * Or rather, pass in $password such that empty($password) is true.
 972     *
 973     * @see createKey()
 974     * @see loadKey()
 975     * @access public
 976     * @param String $password
 977     */
 978    function setPassword($password)
 979    {
 980        $this->password = $password;
 981    }
 982
 983    /**
 984     * Defines the public key
 985     *
 986     * Some private key formats define the public exponent and some don't.  Those that don't define it are problematic when
 987     * used in certain contexts.  For example, in SSH-2, RSA authentication works by sending the public key along with a
 988     * message signed by the private key to the server.  The SSH-2 server looks the public key up in an index of public keys
 989     * and if it's present then proceeds to verify the signature.  Problem is, if your private key doesn't include the public
 990     * exponent this won't work unless you manually add the public exponent.
 991     *
 992     * Do note that when a new key is loaded the index will be cleared.
 993     *
 994     * Returns true on success, false on failure
 995     *
 996     * @see getPublicKey()
 997     * @access public
 998     * @param String $key
 999     * @param Integer $type optional
1000     * @return Boolean
1001     */
1002    function setPublicKey($key, $type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
1003    {
1004        $components = $this->_parseKey($key, $type);
1005        if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
1006            return false;
1007        }
1008        $this->publicExponent = $components['publicExponent'];
1009    }
1010
1011    /**
1012     * Returns the public key
1013     *
1014     * The public key is only returned under two circumstances - if the private key had the public key embedded within it
1015     * or if the public key was set via setPublicKey().  If the currently loaded key is supposed to be the public key this
1016     * function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
1017     *
1018     * @see getPublicKey()
1019     * @access public
1020     * @param String $key
1021     * @param Integer $type optional
1022     */
1023    function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
1024    {
1025        if (empty($this->modulus) || empty($this->publicExponent)) {
1026            return false;
1027        }
1028
1029        $oldFormat = $this->publicKeyFormat;
1030        $this->publicKeyFormat = $type;
1031        $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
1032        $this->publicKeyFormat = $oldFormat;
1033        return $temp;
1034    }
1035
1036    /**
1037     * Generates the smallest and largest numbers requiring $bits bits
1038     *
1039     * @access private
1040     * @param Integer $bits
1041     * @return Array
1042     */
1043    function _generateMinMax($bits)
1044    {
1045        $bytes = $bits >> 3;
1046        $min = str_repeat(chr(0), $bytes);
1047        $max = str_repeat(chr(0xFF), $bytes);
1048        $msb = $bits & 7;
1049        if ($msb) {
1050            $min = chr(1 << ($msb - 1)) . $min;
1051            $max = chr((1 << $msb) - 1) . $max;
1052        } else {
1053            $min[0] = chr(0x80);
1054        }
1055
1056        return array(
1057            'min' => new Math_BigInteger($min, 256),
1058            'max' => new Math_BigInteger($max, 256)
1059        );
1060    }
1061
1062    /**
1063     * DER-decode the length
1064     *
1065     * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4.  See
1066     * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 � 8.1.3} for more information.
1067     *
1068     * @access private
1069     * @param String $string
1070     * @return Integer
1071     */
1072    function _decodeLength(&$string)
1073    {
1074        $length = ord($this->_string_shift($string));
1075        if ( $length & 0x80 ) { // definite length, long form
1076            $length&= 0x7F;
1077            $temp = $this->_string_shift($string, $length);
1078            list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
1079        }
1080        return $length;
1081    }
1082
1083    /**
1084     * DER-encode the length
1085     *
1086     * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4.  See
1087     * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 � 8.1.3} for more information.
1088     *
1089     * @access private
1090     * @param Integer $length
1091     * @return String
1092     */
1093    function _encodeLength($length)
1094    {
1095        if ($length <= 0x7F) {
1096            return chr($length);
1097        }
1098
1099        $temp = ltrim(pack('N', $length), chr(0));
1100        return pack('Ca*', 0x80 | strlen($temp), $temp);
1101    }
1102
1103    /**
1104     * String Shift
1105     *
1106     * Inspired by array_shift
1107     *
1108     * @param String $string
1109     * @param optional Integer $index
1110     * @return String
1111     * @access private
1112     */
1113    function _string_shift(&$string, $index = 1)
1114    {
1115        $substr = substr($string, 0, $index);
1116        $string = substr($string, $index);
1117        return $substr;
1118    }
1119
1120    /**
1121     * Determines the private key format
1122     *
1123     * @see createKey()
1124     * @access public
1125     * @param Integer $format
1126     */
1127    function setPrivateKeyFormat($format)
1128    {
1129        $this->privateKeyFormat = $format;
1130    }
1131
1132    /**
1133     * Determines the public key format
1134     *
1135     * @see createKey()
1136     * @access public
1137     * @param Integer $format
1138     */
1139    function setPublicKeyFormat($format)
1140    {
1141        $this->publicKeyFormat = $format;
1142    }
1143
1144    /**
1145     * Determines which hashing function should be used
1146     *
1147     * Used with signature production / verification and (if the encryption mode is CRYPT_RSA_ENCRYPTION_OAEP) encryption and
1148     * decryption.  If $hash isn't supported, sha1 is used.
1149     *
1150     * @access public
1151     * @param String $hash
1152     */
1153    function setHash($hash)
1154    {
1155        // Crypt_Hash supports algorithms that PKCS#1 doesn't support.  md5-96 and sha1-96, for example.
1156        switch ($hash) {
1157            case 'md2':
1158            case 'md5':
1159            case 'sha1':
1160            case 'sha256':
1161            case 'sha384':
1162            case 'sha512':
1163                $this->hash = new Crypt_Hash($hash);
1164                $this->hashName = $hash;
1165                break;
1166            default:
1167                $this->hash = new Crypt_Hash('sha1');
1168                $this->hashName = 'sha1';
1169        }
1170        $this->hLen = $this->hash->getLength();
1171    }
1172
1173    /**
1174     * Determines which hashing function should be used for the mask generation function
1175     *
1176     * The mask generation function is used by CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_SIGNATURE_PSS and although it's
1177     * best if Hash and MGFHash are set to the same thing this is not a requirement.
1178     *
1179     * @access public
1180     * @param String $hash
1181     */
1182    function setMGFHash($hash)
1183    {
1184        // Crypt_Hash supports algorithms that PKCS#1 doesn't support.  md5-96 and sha1-96, for example.
1185        switch ($hash) {
1186            case 'md2':
1187            case 'md5':
1188            case 'sha1':
1189            case 'sha256':
1190            case 'sha384':
1191            case 'sha512':
1192                $this->mgfHash = new Crypt_Hash($hash);
1193                break;
1194            default:
1195                $this->mgfHash = new Crypt_Hash('sha1');
1196        }
1197        $this->mgfHLen = $this->mgfHash->getLength();
1198    }
1199
1200    /**
1201     * Determines the salt length
1202     *
1203     * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
1204     *
1205     *    Typical salt lengths in octets are hLen (the length of the output
1206     *    of the hash function Hash) and 0.
1207     *
1208     * @access public
1209     * @param Integer $format
1210     */
1211    function setSaltLength($sLen)
1212    {
1213        $this->sLen = $sLen;
1214    }
1215
1216    /**
1217     * Generates a random string x bytes long
1218     *
1219     * @access public
1220     * @param Integer $bytes
1221     * @param optional Integer $nonzero
1222     * @return String
1223     */
1224    function _random($bytes, $nonzero = false)
1225    {
1226        $temp = '';
1227        if ($nonzero) {
1228            for ($i = 0; $i < $bytes; $i++) {
1229                $temp.= chr(crypt_random(1, 255));
1230            }
1231        } else {
1232            $ints = ($bytes + 1) >> 2;
1233            for ($i = 0; $i < $ints; $i++) {
1234                $temp.= pack('N', crypt_random());
1235            }
1236            $temp = substr($temp, 0, $bytes);
1237        }
1238        return $temp;
1239    }
1240
1241    /**
1242     * Integer-to-Octet-String primitive
1243     *
1244     * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
1245     *
1246     * @access private
1247     * @param Math_BigInteger $x
1248     * @param Integer $xLen
1249     * @return String
1250     */
1251    function _i2osp($x, $xLen)
1252    {
1253        $x = $x->toBytes();
1254        if (strlen($x) > $xLen) {
1255            user_error('Integer too large', E_USER_NOTICE);
1256            return false;
1257        }
1258        return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
1259    }
1260
1261    /**
1262     * Octet-String-to-Integer primitive
1263     *
1264     * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
1265     *
1266     * @access private
1267     * @param String $x
1268     * @return Math_BigInteger
1269     */
1270    function _os2ip($x)
1271    {
1272        return new Math_BigInteger($x, 256);
1273    }
1274
1275    /**
1276     * Exponentiate with or without Chinese Remainder Theorem
1277     *
1278     * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
1279     *
1280     * @access private
1281     * @param Math_BigInteger $x
1282     * @return Math_BigInteger
1283     */
1284    function _exponentiate($x)
1285    {
1286        if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) {
1287            return $x->modPow($this->exponent, $this->modulus);
1288        }
1289
1290        $num_primes = count($this->primes);
1291
1292        if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
1293            $m_i = array(
1294                1 => $x->modPow($this->exponents[1], $this->primes[1]),
1295                2 => $x->modPow($this->exponents[2], $this->primes[2])
1296            );
1297            $h = $m_i[1]->subtract($m_i[2]);
1298            $h = $h->multiply($this->coefficients[2]);
1299            list(, $h) = $h->divide($this->primes[1]);
1300            $m = $m_i[2]->add($h->multiply($this->primes[2]));
1301
1302            $r = $this->primes[1];
1303            for ($i = 3; $i <= $num_primes; $i++) {
1304                $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
1305
1306                $r = $r->multiply($this->primes[$i - 1]);
1307
1308                $h = $m_i->subtract($m);
1309                $h = $h->multiply($this->coefficients[$i]);
1310                list(, $h) = $h->divide($this->primes[$i]);
1311
1312                $m = $m->add($r->multiply($h));
1313            }
1314        } else {
1315            $smallest = $this->primes[1];
1316            for ($i = 2; $i <= $num_primes; $i++) {
1317                if ($smallest->compare($this->primes[$i]) > 0) {
1318                    $smallest = $this->primes[$i];
1319                }
1320            }
1321
1322            $one = new Math_BigInteger(1);
1323            $one->setRandomGenerator('crypt_random');
1324
1325            $r = $one->random($one, $smallest->subtract($one));
1326
1327            $m_i = array(
1328                1 => $this->_blind($x, $r, 1),
1329                2 => $this->_blind($x, $r, 2)
1330            );
1331            $h = $m_i[1]->subtract($m_i[2]);
1332            $h = $h->multiply($this->coefficients[2]);
1333            list(, $h) = $h->divide($this->primes[1]);
1334            $m = $m_i[2]->add($h->multiply($this->primes[2]));
1335
1336            $r = $this->primes[1];
1337            for ($i = 3; $i <= $num_primes; $i++) {
1338                $m_i = $this->_blind($x, $r, $i);
1339
1340                $r = $r->multiply($this->primes[$i - 1]);
1341
1342                $h = $m_i->subtract($m);
1343                $h = $h->multiply($this->coefficients[$i]);
1344                list(, $h) = $h->divide($this->primes[$i]);
1345
1346                $m = $m->add($r->multiply($h));
1347            }
1348        }
1349
1350        return $m;
1351    }
1352
1353    /**
1354     * Performs RSA Blinding
1355     *
1356     * Protects against timing attacks by employing RSA Blinding.
1357     * Returns $x->modPow($this->exponents[$i], $this->primes[$i])
1358     *
1359     * @access private
1360     * @param Math_BigInteger $x
1361     * @param Math_BigInteger $r
1362     * @param Integer $i
1363     * @return Math_BigInteger
1364     */
1365    function _blind($x, $r, $i)
1366    {
1367        $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
1368
1369        $x = $x->modPow($this->exponents[$i], $this->primes[$i]);
1370
1371        $r = $r->modInverse($this->primes[$i]);
1372        $x = $x->multiply($r);
1373        list(, $x) = $x->divide($this->primes[$i]);
1374
1375        return $x;
1376    }
1377
1378    /**
1379     * RSAEP
1380     *
1381     * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
1382     *
1383     * @access private
1384     * @param Math_BigInteger $m
1385     * @return Math_BigInteger
1386     */
1387    function _rsaep($m)
1388    {
1389        if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1390            user_error('Message representative out of range', E_USER_NOTICE);
1391            return false;
1392        }
1393        return $this->_exponentiate($m);
1394    }
1395
1396    /**
1397     * RSADP
1398     *
1399     * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
1400     *
1401     * @access private
1402     * @param Math_BigInteger $c
1403     * @return Math_BigInteger
1404     */
1405    function _rsadp($c)
1406    {
1407        if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
1408            user_error('Ciphertext representative out of range', E_USER_NOTICE);
1409            return false;
1410        }
1411        return $this->_exponentiate($c);
1412    }
1413
1414    /**
1415     * RSASP1
1416     *
1417     * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
1418     *
1419     * @access private
1420     * @param Math_BigInteger $m
1421     * @return Math_BigInteger
1422     */
1423    function _rsasp1($m)
1424    {
1425        if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1426            user_error('Message representative out of range', E_USER_NOTICE);
1427            return false;
1428        }
1429        return $this->_exponentiate($m);
1430    }
1431
1432    /**
1433     * RSAVP1
1434     *
1435     * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
1436     *
1437     * @access private
1438     * @param Math_BigInteger $s
1439     * @return Math_BigInteger
1440     */
1441    function _rsavp1($s)
1442    {
1443        if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
1444            user_error('Signature representative out of range', E_USER_NOTICE);
1445            return false;
1446        }
1447        return $this->_exponentiate($s);
1448    }
1449
1450    /**
1451     * MGF1
1452     *
1453     * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
1454     *
1455     * @access private
1456     * @param String $mgfSeed
1457     * @param I…

Large files files are truncated, but you can click here to view the full file