[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/vendor/phpseclib/phpseclib/phpseclib/Crypt/ -> Base.php (source)

   1  <?php
   2  
   3  /**
   4   * Base Class for all \phpseclib\Crypt\* cipher classes
   5   *
   6   * PHP version 5
   7   *
   8   * Internally for phpseclib developers:
   9   *  If you plan to add a new cipher class, please note following rules:
  10   *
  11   *  - The new \phpseclib\Crypt\* cipher class should extend \phpseclib\Crypt\Base
  12   *
  13   *  - Following methods are then required to be overridden/overloaded:
  14   *
  15   *    - _encryptBlock()
  16   *
  17   *    - _decryptBlock()
  18   *
  19   *    - _setupKey()
  20   *
  21   *  - All other methods are optional to be overridden/overloaded
  22   *
  23   *  - Look at the source code of the current ciphers how they extend \phpseclib\Crypt\Base
  24   *    and take one of them as a start up for the new cipher class.
  25   *
  26   *  - Please read all the other comments/notes/hints here also for each class var/method
  27   *
  28   * @category  Crypt
  29   * @package   Base
  30   * @author    Jim Wigginton <terrafrost@php.net>
  31   * @author    Hans-Juergen Petrich <petrich@tronic-media.com>
  32   * @copyright 2007 Jim Wigginton
  33   * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
  34   * @link      http://phpseclib.sourceforge.net
  35   */
  36  
  37  namespace phpseclib\Crypt;
  38  
  39  /**
  40   * Base Class for all \phpseclib\Crypt\* cipher classes
  41   *
  42   * @package Base
  43   * @author  Jim Wigginton <terrafrost@php.net>
  44   * @author  Hans-Juergen Petrich <petrich@tronic-media.com>
  45   */
  46  abstract class Base
  47  {
  48      /**#@+
  49       * @access public
  50       * @see \phpseclib\Crypt\Base::encrypt()
  51       * @see \phpseclib\Crypt\Base::decrypt()
  52       */
  53      /**
  54       * Encrypt / decrypt using the Counter mode.
  55       *
  56       * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
  57       *
  58       * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
  59       */
  60      const MODE_CTR = -1;
  61      /**
  62       * Encrypt / decrypt using the Electronic Code Book mode.
  63       *
  64       * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
  65       */
  66      const MODE_ECB = 1;
  67      /**
  68       * Encrypt / decrypt using the Code Book Chaining mode.
  69       *
  70       * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
  71       */
  72      const MODE_CBC = 2;
  73      /**
  74       * Encrypt / decrypt using the Cipher Feedback mode.
  75       *
  76       * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
  77       */
  78      const MODE_CFB = 3;
  79      /**
  80       * Encrypt / decrypt using the Cipher Feedback mode (8bit)
  81       */
  82      const MODE_CFB8 = 38;
  83      /**
  84       * Encrypt / decrypt using the Output Feedback mode.
  85       *
  86       * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
  87       */
  88      const MODE_OFB = 4;
  89      /**
  90       * Encrypt / decrypt using streaming mode.
  91       */
  92      const MODE_STREAM = 5;
  93      /**#@-*/
  94  
  95      /**
  96       * Whirlpool available flag
  97       *
  98       * @see \phpseclib\Crypt\Base::_hashInlineCryptFunction()
  99       * @var bool
 100       * @access private
 101       */
 102      static $WHIRLPOOL_AVAILABLE;
 103  
 104      /**#@+
 105       * @access private
 106       * @see \phpseclib\Crypt\Base::__construct()
 107       */
 108      /**
 109       * Base value for the internal implementation $engine switch
 110       */
 111      const ENGINE_INTERNAL = 1;
 112      /**
 113       * Base value for the mcrypt implementation $engine switch
 114       */
 115      const ENGINE_MCRYPT = 2;
 116      /**
 117       * Base value for the mcrypt implementation $engine switch
 118       */
 119      const ENGINE_OPENSSL = 3;
 120      /**#@-*/
 121  
 122      /**
 123       * The Encryption Mode
 124       *
 125       * @see self::__construct()
 126       * @var int
 127       * @access private
 128       */
 129      var $mode;
 130  
 131      /**
 132       * The Block Length of the block cipher
 133       *
 134       * @var int
 135       * @access private
 136       */
 137      var $block_size = 16;
 138  
 139      /**
 140       * The Key
 141       *
 142       * @see self::setKey()
 143       * @var string
 144       * @access private
 145       */
 146      var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
 147  
 148      /**
 149       * The Initialization Vector
 150       *
 151       * @see self::setIV()
 152       * @var string
 153       * @access private
 154       */
 155      var $iv;
 156  
 157      /**
 158       * A "sliding" Initialization Vector
 159       *
 160       * @see self::enableContinuousBuffer()
 161       * @see self::_clearBuffers()
 162       * @var string
 163       * @access private
 164       */
 165      var $encryptIV;
 166  
 167      /**
 168       * A "sliding" Initialization Vector
 169       *
 170       * @see self::enableContinuousBuffer()
 171       * @see self::_clearBuffers()
 172       * @var string
 173       * @access private
 174       */
 175      var $decryptIV;
 176  
 177      /**
 178       * Continuous Buffer status
 179       *
 180       * @see self::enableContinuousBuffer()
 181       * @var bool
 182       * @access private
 183       */
 184      var $continuousBuffer = false;
 185  
 186      /**
 187       * Encryption buffer for CTR, OFB and CFB modes
 188       *
 189       * @see self::encrypt()
 190       * @see self::_clearBuffers()
 191       * @var array
 192       * @access private
 193       */
 194      var $enbuffer;
 195  
 196      /**
 197       * Decryption buffer for CTR, OFB and CFB modes
 198       *
 199       * @see self::decrypt()
 200       * @see self::_clearBuffers()
 201       * @var array
 202       * @access private
 203       */
 204      var $debuffer;
 205  
 206      /**
 207       * mcrypt resource for encryption
 208       *
 209       * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
 210       * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
 211       *
 212       * @see self::encrypt()
 213       * @var resource
 214       * @access private
 215       */
 216      var $enmcrypt;
 217  
 218      /**
 219       * mcrypt resource for decryption
 220       *
 221       * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
 222       * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
 223       *
 224       * @see self::decrypt()
 225       * @var resource
 226       * @access private
 227       */
 228      var $demcrypt;
 229  
 230      /**
 231       * Does the enmcrypt resource need to be (re)initialized?
 232       *
 233       * @see \phpseclib\Crypt\Twofish::setKey()
 234       * @see \phpseclib\Crypt\Twofish::setIV()
 235       * @var bool
 236       * @access private
 237       */
 238      var $enchanged = true;
 239  
 240      /**
 241       * Does the demcrypt resource need to be (re)initialized?
 242       *
 243       * @see \phpseclib\Crypt\Twofish::setKey()
 244       * @see \phpseclib\Crypt\Twofish::setIV()
 245       * @var bool
 246       * @access private
 247       */
 248      var $dechanged = true;
 249  
 250      /**
 251       * mcrypt resource for CFB mode
 252       *
 253       * mcrypt's CFB mode, in (and only in) buffered context,
 254       * is broken, so phpseclib implements the CFB mode by it self,
 255       * even when the mcrypt php extension is available.
 256       *
 257       * In order to do the CFB-mode work (fast) phpseclib
 258       * use a separate ECB-mode mcrypt resource.
 259       *
 260       * @link http://phpseclib.sourceforge.net/cfb-demo.phps
 261       * @see self::encrypt()
 262       * @see self::decrypt()
 263       * @see self::_setupMcrypt()
 264       * @var resource
 265       * @access private
 266       */
 267      var $ecb;
 268  
 269      /**
 270       * Optimizing value while CFB-encrypting
 271       *
 272       * Only relevant if $continuousBuffer enabled
 273       * and $engine == self::ENGINE_MCRYPT
 274       *
 275       * It's faster to re-init $enmcrypt if
 276       * $buffer bytes > $cfb_init_len than
 277       * using the $ecb resource furthermore.
 278       *
 279       * This value depends of the chosen cipher
 280       * and the time it would be needed for it's
 281       * initialization [by mcrypt_generic_init()]
 282       * which, typically, depends on the complexity
 283       * on its internaly Key-expanding algorithm.
 284       *
 285       * @see self::encrypt()
 286       * @var int
 287       * @access private
 288       */
 289      var $cfb_init_len = 600;
 290  
 291      /**
 292       * Does internal cipher state need to be (re)initialized?
 293       *
 294       * @see self::setKey()
 295       * @see self::setIV()
 296       * @see self::disableContinuousBuffer()
 297       * @var bool
 298       * @access private
 299       */
 300      var $changed = true;
 301  
 302      /**
 303       * Padding status
 304       *
 305       * @see self::enablePadding()
 306       * @var bool
 307       * @access private
 308       */
 309      var $padding = true;
 310  
 311      /**
 312       * Is the mode one that is paddable?
 313       *
 314       * @see self::__construct()
 315       * @var bool
 316       * @access private
 317       */
 318      var $paddable = false;
 319  
 320      /**
 321       * Holds which crypt engine internaly should be use,
 322       * which will be determined automatically on __construct()
 323       *
 324       * Currently available $engines are:
 325       * - self::ENGINE_OPENSSL  (very fast, php-extension: openssl, extension_loaded('openssl') required)
 326       * - self::ENGINE_MCRYPT   (fast, php-extension: mcrypt, extension_loaded('mcrypt') required)
 327       * - self::ENGINE_INTERNAL (slower, pure php-engine, no php-extension required)
 328       *
 329       * @see self::_setEngine()
 330       * @see self::encrypt()
 331       * @see self::decrypt()
 332       * @var int
 333       * @access private
 334       */
 335      var $engine;
 336  
 337      /**
 338       * Holds the preferred crypt engine
 339       *
 340       * @see self::_setEngine()
 341       * @see self::setPreferredEngine()
 342       * @var int
 343       * @access private
 344       */
 345      var $preferredEngine;
 346  
 347      /**
 348       * The mcrypt specific name of the cipher
 349       *
 350       * Only used if $engine == self::ENGINE_MCRYPT
 351       *
 352       * @link http://www.php.net/mcrypt_module_open
 353       * @link http://www.php.net/mcrypt_list_algorithms
 354       * @see self::_setupMcrypt()
 355       * @var string
 356       * @access private
 357       */
 358      var $cipher_name_mcrypt;
 359  
 360      /**
 361       * The openssl specific name of the cipher
 362       *
 363       * Only used if $engine == self::ENGINE_OPENSSL
 364       *
 365       * @link http://www.php.net/openssl-get-cipher-methods
 366       * @var string
 367       * @access private
 368       */
 369      var $cipher_name_openssl;
 370  
 371      /**
 372       * The openssl specific name of the cipher in ECB mode
 373       *
 374       * If OpenSSL does not support the mode we're trying to use (CTR)
 375       * it can still be emulated with ECB mode.
 376       *
 377       * @link http://www.php.net/openssl-get-cipher-methods
 378       * @var string
 379       * @access private
 380       */
 381      var $cipher_name_openssl_ecb;
 382  
 383      /**
 384       * The default salt used by setPassword()
 385       *
 386       * @see self::setPassword()
 387       * @var string
 388       * @access private
 389       */
 390      var $password_default_salt = 'phpseclib/salt';
 391  
 392      /**
 393       * The name of the performance-optimized callback function
 394       *
 395       * Used by encrypt() / decrypt()
 396       * only if $engine == self::ENGINE_INTERNAL
 397       *
 398       * @see self::encrypt()
 399       * @see self::decrypt()
 400       * @see self::_setupInlineCrypt()
 401       * @see self::$use_inline_crypt
 402       * @var Callback
 403       * @access private
 404       */
 405      var $inline_crypt;
 406  
 407      /**
 408       * Holds whether performance-optimized $inline_crypt() can/should be used.
 409       *
 410       * @see self::encrypt()
 411       * @see self::decrypt()
 412       * @see self::inline_crypt
 413       * @var mixed
 414       * @access private
 415       */
 416      var $use_inline_crypt;
 417  
 418      /**
 419       * If OpenSSL can be used in ECB but not in CTR we can emulate CTR
 420       *
 421       * @see self::_openssl_ctr_process()
 422       * @var bool
 423       * @access private
 424       */
 425      var $openssl_emulate_ctr = false;
 426  
 427      /**
 428       * Determines what options are passed to openssl_encrypt/decrypt
 429       *
 430       * @see self::isValidEngine()
 431       * @var mixed
 432       * @access private
 433       */
 434      var $openssl_options;
 435  
 436      /**
 437       * Has the key length explicitly been set or should it be derived from the key, itself?
 438       *
 439       * @see self::setKeyLength()
 440       * @var bool
 441       * @access private
 442       */
 443      var $explicit_key_length = false;
 444  
 445      /**
 446       * Don't truncate / null pad key
 447       *
 448       * @see self::_clearBuffers()
 449       * @var bool
 450       * @access private
 451       */
 452      var $skip_key_adjustment = false;
 453  
 454      /**
 455       * Default Constructor.
 456       *
 457       * Determines whether or not the mcrypt extension should be used.
 458       *
 459       * $mode could be:
 460       *
 461       * - self::MODE_ECB
 462       *
 463       * - self::MODE_CBC
 464       *
 465       * - self::MODE_CTR
 466       *
 467       * - self::MODE_CFB
 468       *
 469       * - self::MODE_OFB
 470       *
 471       * If not explicitly set, self::MODE_CBC will be used.
 472       *
 473       * @param int $mode
 474       * @access public
 475       */
 476      function __construct($mode = self::MODE_CBC)
 477      {
 478          // $mode dependent settings
 479          switch ($mode) {
 480              case self::MODE_ECB:
 481                  $this->paddable = true;
 482                  $this->mode = self::MODE_ECB;
 483                  break;
 484              case self::MODE_CTR:
 485              case self::MODE_CFB:
 486              case self::MODE_CFB8:
 487              case self::MODE_OFB:
 488              case self::MODE_STREAM:
 489                  $this->mode = $mode;
 490                  break;
 491              case self::MODE_CBC:
 492              default:
 493                  $this->paddable = true;
 494                  $this->mode = self::MODE_CBC;
 495          }
 496  
 497          $this->_setEngine();
 498  
 499          // Determining whether inline crypting can be used by the cipher
 500          if ($this->use_inline_crypt !== false) {
 501              $this->use_inline_crypt = version_compare(PHP_VERSION, '5.3.0') >= 0 || function_exists('create_function');
 502          }
 503      }
 504  
 505      /**
 506       * Sets the initialization vector. (optional)
 507       *
 508       * SetIV is not required when self::MODE_ECB (or ie for AES: \phpseclib\Crypt\AES::MODE_ECB) is being used.  If not explicitly set, it'll be assumed
 509       * to be all zero's.
 510       *
 511       * @access public
 512       * @param string $iv
 513       * @internal Can be overwritten by a sub class, but does not have to be
 514       */
 515      function setIV($iv)
 516      {
 517          if ($this->mode == self::MODE_ECB) {
 518              return;
 519          }
 520  
 521          $this->iv = $iv;
 522          $this->changed = true;
 523      }
 524  
 525      /**
 526       * Sets the key length.
 527       *
 528       * Keys with explicitly set lengths need to be treated accordingly
 529       *
 530       * @access public
 531       * @param int $length
 532       */
 533      function setKeyLength($length)
 534      {
 535          $this->explicit_key_length = true;
 536          $this->changed = true;
 537          $this->_setEngine();
 538      }
 539  
 540      /**
 541       * Returns the current key length in bits
 542       *
 543       * @access public
 544       * @return int
 545       */
 546      function getKeyLength()
 547      {
 548          return $this->key_length << 3;
 549      }
 550  
 551      /**
 552       * Returns the current block length in bits
 553       *
 554       * @access public
 555       * @return int
 556       */
 557      function getBlockLength()
 558      {
 559          return $this->block_size << 3;
 560      }
 561  
 562      /**
 563       * Sets the key.
 564       *
 565       * The min/max length(s) of the key depends on the cipher which is used.
 566       * If the key not fits the length(s) of the cipher it will paded with null bytes
 567       * up to the closest valid key length.  If the key is more than max length,
 568       * we trim the excess bits.
 569       *
 570       * If the key is not explicitly set, it'll be assumed to be all null bytes.
 571       *
 572       * @access public
 573       * @param string $key
 574       * @internal Could, but not must, extend by the child Crypt_* class
 575       */
 576      function setKey($key)
 577      {
 578          if (!$this->explicit_key_length) {
 579              $this->setKeyLength(strlen($key) << 3);
 580              $this->explicit_key_length = false;
 581          }
 582  
 583          $this->key = $key;
 584          $this->changed = true;
 585          $this->_setEngine();
 586      }
 587  
 588      /**
 589       * Sets the password.
 590       *
 591       * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
 592       *     {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
 593       *         $hash, $salt, $count, $dkLen
 594       *
 595       *         Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
 596       *
 597       * @see Crypt/Hash.php
 598       * @param string $password
 599       * @param string $method
 600       * @return bool
 601       * @access public
 602       * @internal Could, but not must, extend by the child Crypt_* class
 603       */
 604      function setPassword($password, $method = 'pbkdf2')
 605      {
 606          $key = '';
 607  
 608          switch ($method) {
 609              default: // 'pbkdf2' or 'pbkdf1'
 610                  $func_args = func_get_args();
 611  
 612                  // Hash function
 613                  $hash = isset($func_args[2]) ? $func_args[2] : 'sha1';
 614  
 615                  // WPA and WPA2 use the SSID as the salt
 616                  $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;
 617  
 618                  // RFC2898#section-4.2 uses 1,000 iterations by default
 619                  // WPA and WPA2 use 4,096.
 620                  $count = isset($func_args[4]) ? $func_args[4] : 1000;
 621  
 622                  // Keylength
 623                  if (isset($func_args[5])) {
 624                      $dkLen = $func_args[5];
 625                  } else {
 626                      $dkLen = $method == 'pbkdf1' ? 2 * $this->key_length : $this->key_length;
 627                  }
 628  
 629                  switch (true) {
 630                      case $method == 'pbkdf1':
 631                          $hashObj = new Hash();
 632                          $hashObj->setHash($hash);
 633                          if ($dkLen > $hashObj->getLength()) {
 634                              user_error('Derived key too long');
 635                              return false;
 636                          }
 637                          $t = $password . $salt;
 638                          for ($i = 0; $i < $count; ++$i) {
 639                              $t = $hashObj->hash($t);
 640                          }
 641                          $key = substr($t, 0, $dkLen);
 642  
 643                          $this->setKey(substr($key, 0, $dkLen >> 1));
 644                          $this->setIV(substr($key, $dkLen >> 1));
 645  
 646                          return true;
 647                      // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
 648                      case !function_exists('hash_pbkdf2'):
 649                      case !function_exists('hash_algos'):
 650                      case !in_array($hash, hash_algos()):
 651                          $i = 1;
 652                          $hmac = new Hash();
 653                          $hmac->setHash($hash);
 654                          $hmac->setKey($password);
 655                          while (strlen($key) < $dkLen) {
 656                              $f = $u = $hmac->hash($salt . pack('N', $i++));
 657                              for ($j = 2; $j <= $count; ++$j) {
 658                                  $u = $hmac->hash($u);
 659                                  $f^= $u;
 660                              }
 661                              $key.= $f;
 662                          }
 663                          $key = substr($key, 0, $dkLen);
 664                          break;
 665                      default:
 666                          $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
 667                  }
 668          }
 669  
 670          $this->setKey($key);
 671  
 672          return true;
 673      }
 674  
 675      /**
 676       * Encrypts a message.
 677       *
 678       * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher
 679       * implementations may or may not pad in the same manner.  Other common approaches to padding and the reasons why it's
 680       * necessary are discussed in the following
 681       * URL:
 682       *
 683       * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
 684       *
 685       * An alternative to padding is to, separately, send the length of the file.  This is what SSH, in fact, does.
 686       * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that
 687       * length.
 688       *
 689       * @see self::decrypt()
 690       * @access public
 691       * @param string $plaintext
 692       * @return string $ciphertext
 693       * @internal Could, but not must, extend by the child Crypt_* class
 694       */
 695      function encrypt($plaintext)
 696      {
 697          if ($this->paddable) {
 698              $plaintext = $this->_pad($plaintext);
 699          }
 700  
 701          if ($this->engine === self::ENGINE_OPENSSL) {
 702              if ($this->changed) {
 703                  $this->_clearBuffers();
 704                  $this->changed = false;
 705              }
 706              switch ($this->mode) {
 707                  case self::MODE_STREAM:
 708                      return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
 709                  case self::MODE_ECB:
 710                      $result = @openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
 711                      return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
 712                  case self::MODE_CBC:
 713                      $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
 714                      if (!defined('OPENSSL_RAW_DATA')) {
 715                          $result = substr($result, 0, -$this->block_size);
 716                      }
 717                      if ($this->continuousBuffer) {
 718                          $this->encryptIV = substr($result, -$this->block_size);
 719                      }
 720                      return $result;
 721                  case self::MODE_CTR:
 722                      return $this->_openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer);
 723                  case self::MODE_CFB:
 724                      // cfb loosely routines inspired by openssl's:
 725                      // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
 726                      $ciphertext = '';
 727                      if ($this->continuousBuffer) {
 728                          $iv = &$this->encryptIV;
 729                          $pos = &$this->enbuffer['pos'];
 730                      } else {
 731                          $iv = $this->encryptIV;
 732                          $pos = 0;
 733                      }
 734                      $len = strlen($plaintext);
 735                      $i = 0;
 736                      if ($pos) {
 737                          $orig_pos = $pos;
 738                          $max = $this->block_size - $pos;
 739                          if ($len >= $max) {
 740                              $i = $max;
 741                              $len-= $max;
 742                              $pos = 0;
 743                          } else {
 744                              $i = $len;
 745                              $pos+= $len;
 746                              $len = 0;
 747                          }
 748                          // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
 749                          $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
 750                          $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
 751                          $plaintext = substr($plaintext, $i);
 752                      }
 753  
 754                      $overflow = $len % $this->block_size;
 755  
 756                      if ($overflow) {
 757                          $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
 758                          $iv = $this->_string_pop($ciphertext, $this->block_size);
 759  
 760                          $size = $len - $overflow;
 761                          $block = $iv ^ substr($plaintext, -$overflow);
 762                          $iv = substr_replace($iv, $block, 0, $overflow);
 763                          $ciphertext.= $block;
 764                          $pos = $overflow;
 765                      } elseif ($len) {
 766                          $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
 767                          $iv = substr($ciphertext, -$this->block_size);
 768                      }
 769  
 770                      return $ciphertext;
 771                  case self::MODE_CFB8:
 772                      $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
 773                      if ($this->continuousBuffer) {
 774                          if (($len = strlen($ciphertext)) >= $this->block_size) {
 775                              $this->encryptIV = substr($ciphertext, -$this->block_size);
 776                          } else {
 777                              $this->encryptIV = substr($this->encryptIV, $len - $this->block_size) . substr($ciphertext, -$len);
 778                          }
 779                      }
 780                      return $ciphertext;
 781                  case self::MODE_OFB:
 782                      return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
 783              }
 784          }
 785  
 786          if ($this->engine === self::ENGINE_MCRYPT) {
 787              if ($this->changed) {
 788                  $this->_setupMcrypt();
 789                  $this->changed = false;
 790              }
 791              if ($this->enchanged) {
 792                  @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
 793                  $this->enchanged = false;
 794              }
 795  
 796              // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
 797              // using mcrypt's default handing of CFB the above would output two different things.  using phpseclib's
 798              // rewritten CFB implementation the above outputs the same thing twice.
 799              if ($this->mode == self::MODE_CFB && $this->continuousBuffer) {
 800                  $block_size = $this->block_size;
 801                  $iv = &$this->encryptIV;
 802                  $pos = &$this->enbuffer['pos'];
 803                  $len = strlen($plaintext);
 804                  $ciphertext = '';
 805                  $i = 0;
 806                  if ($pos) {
 807                      $orig_pos = $pos;
 808                      $max = $block_size - $pos;
 809                      if ($len >= $max) {
 810                          $i = $max;
 811                          $len-= $max;
 812                          $pos = 0;
 813                      } else {
 814                          $i = $len;
 815                          $pos+= $len;
 816                          $len = 0;
 817                      }
 818                      $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
 819                      $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
 820                      $this->enbuffer['enmcrypt_init'] = true;
 821                  }
 822                  if ($len >= $block_size) {
 823                      if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) {
 824                          if ($this->enbuffer['enmcrypt_init'] === true) {
 825                              @mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
 826                              $this->enbuffer['enmcrypt_init'] = false;
 827                          }
 828                          $ciphertext.= @mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
 829                          $iv = substr($ciphertext, -$block_size);
 830                          $len%= $block_size;
 831                      } else {
 832                          while ($len >= $block_size) {
 833                              $iv = @mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
 834                              $ciphertext.= $iv;
 835                              $len-= $block_size;
 836                              $i+= $block_size;
 837                          }
 838                      }
 839                  }
 840  
 841                  if ($len) {
 842                      $iv = @mcrypt_generic($this->ecb, $iv);
 843                      $block = $iv ^ substr($plaintext, -$len);
 844                      $iv = substr_replace($iv, $block, 0, $len);
 845                      $ciphertext.= $block;
 846                      $pos = $len;
 847                  }
 848  
 849                  return $ciphertext;
 850              }
 851  
 852              $ciphertext = @mcrypt_generic($this->enmcrypt, $plaintext);
 853  
 854              if (!$this->continuousBuffer) {
 855                  @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
 856              }
 857  
 858              return $ciphertext;
 859          }
 860  
 861          if ($this->changed) {
 862              $this->_setup();
 863              $this->changed = false;
 864          }
 865          if ($this->use_inline_crypt) {
 866              $inline = $this->inline_crypt;
 867              return $inline('encrypt', $this, $plaintext);
 868          }
 869  
 870          $buffer = &$this->enbuffer;
 871          $block_size = $this->block_size;
 872          $ciphertext = '';
 873          switch ($this->mode) {
 874              case self::MODE_ECB:
 875                  for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 876                      $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
 877                  }
 878                  break;
 879              case self::MODE_CBC:
 880                  $xor = $this->encryptIV;
 881                  for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 882                      $block = substr($plaintext, $i, $block_size);
 883                      $block = $this->_encryptBlock($block ^ $xor);
 884                      $xor = $block;
 885                      $ciphertext.= $block;
 886                  }
 887                  if ($this->continuousBuffer) {
 888                      $this->encryptIV = $xor;
 889                  }
 890                  break;
 891              case self::MODE_CTR:
 892                  $xor = $this->encryptIV;
 893                  if (strlen($buffer['ciphertext'])) {
 894                      for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 895                          $block = substr($plaintext, $i, $block_size);
 896                          if (strlen($block) > strlen($buffer['ciphertext'])) {
 897                              $buffer['ciphertext'].= $this->_encryptBlock($xor);
 898                          }
 899                          $this->_increment_str($xor);
 900                          $key = $this->_string_shift($buffer['ciphertext'], $block_size);
 901                          $ciphertext.= $block ^ $key;
 902                      }
 903                  } else {
 904                      for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 905                          $block = substr($plaintext, $i, $block_size);
 906                          $key = $this->_encryptBlock($xor);
 907                          $this->_increment_str($xor);
 908                          $ciphertext.= $block ^ $key;
 909                      }
 910                  }
 911                  if ($this->continuousBuffer) {
 912                      $this->encryptIV = $xor;
 913                      if ($start = strlen($plaintext) % $block_size) {
 914                          $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
 915                      }
 916                  }
 917                  break;
 918              case self::MODE_CFB:
 919                  // cfb loosely routines inspired by openssl's:
 920                  // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
 921                  if ($this->continuousBuffer) {
 922                      $iv = &$this->encryptIV;
 923                      $pos = &$buffer['pos'];
 924                  } else {
 925                      $iv = $this->encryptIV;
 926                      $pos = 0;
 927                  }
 928                  $len = strlen($plaintext);
 929                  $i = 0;
 930                  if ($pos) {
 931                      $orig_pos = $pos;
 932                      $max = $block_size - $pos;
 933                      if ($len >= $max) {
 934                          $i = $max;
 935                          $len-= $max;
 936                          $pos = 0;
 937                      } else {
 938                          $i = $len;
 939                          $pos+= $len;
 940                          $len = 0;
 941                      }
 942                      // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
 943                      $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
 944                      $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
 945                  }
 946                  while ($len >= $block_size) {
 947                      $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
 948                      $ciphertext.= $iv;
 949                      $len-= $block_size;
 950                      $i+= $block_size;
 951                  }
 952                  if ($len) {
 953                      $iv = $this->_encryptBlock($iv);
 954                      $block = $iv ^ substr($plaintext, $i);
 955                      $iv = substr_replace($iv, $block, 0, $len);
 956                      $ciphertext.= $block;
 957                      $pos = $len;
 958                  }
 959                  break;
 960              case self::MODE_CFB8:
 961                  $ciphertext = '';
 962                  $len = strlen($plaintext);
 963                  $iv = $this->encryptIV;
 964  
 965                  for ($i = 0; $i < $len; ++$i) {
 966                      $ciphertext .= ($c = $plaintext[$i] ^ $this->_encryptBlock($iv));
 967                      $iv = substr($iv, 1) . $c;
 968                  }
 969  
 970                  if ($this->continuousBuffer) {
 971                      if ($len >= $block_size) {
 972                          $this->encryptIV = substr($ciphertext, -$block_size);
 973                      } else {
 974                          $this->encryptIV = substr($this->encryptIV, $len - $block_size) . substr($ciphertext, -$len);
 975                      }
 976                  }
 977                  break;
 978              case self::MODE_OFB:
 979                  $xor = $this->encryptIV;
 980                  if (strlen($buffer['xor'])) {
 981                      for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 982                          $block = substr($plaintext, $i, $block_size);
 983                          if (strlen($block) > strlen($buffer['xor'])) {
 984                              $xor = $this->_encryptBlock($xor);
 985                              $buffer['xor'].= $xor;
 986                          }
 987                          $key = $this->_string_shift($buffer['xor'], $block_size);
 988                          $ciphertext.= $block ^ $key;
 989                      }
 990                  } else {
 991                      for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 992                          $xor = $this->_encryptBlock($xor);
 993                          $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
 994                      }
 995                      $key = $xor;
 996                  }
 997                  if ($this->continuousBuffer) {
 998                      $this->encryptIV = $xor;
 999                      if ($start = strlen($plaintext) % $block_size) {
1000                          $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1001                      }
1002                  }
1003                  break;
1004              case self::MODE_STREAM:
1005                  $ciphertext = $this->_encryptBlock($plaintext);
1006                  break;
1007          }
1008  
1009          return $ciphertext;
1010      }
1011  
1012      /**
1013       * Decrypts a message.
1014       *
1015       * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
1016       * it is.
1017       *
1018       * @see self::encrypt()
1019       * @access public
1020       * @param string $ciphertext
1021       * @return string $plaintext
1022       * @internal Could, but not must, extend by the child Crypt_* class
1023       */
1024      function decrypt($ciphertext)
1025      {
1026          if ($this->paddable) {
1027              // we pad with chr(0) since that's what mcrypt_generic does.  to quote from {@link http://www.php.net/function.mcrypt-generic}:
1028              // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
1029              $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
1030          }
1031  
1032          if ($this->engine === self::ENGINE_OPENSSL) {
1033              if ($this->changed) {
1034                  $this->_clearBuffers();
1035                  $this->changed = false;
1036              }
1037              switch ($this->mode) {
1038                  case self::MODE_STREAM:
1039                      $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1040                      break;
1041                  case self::MODE_ECB:
1042                      if (!defined('OPENSSL_RAW_DATA')) {
1043                          $ciphertext.= @openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true);
1044                      }
1045                      $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1046                      break;
1047                  case self::MODE_CBC:
1048                      if (!defined('OPENSSL_RAW_DATA')) {
1049                          $padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size);
1050                          $ciphertext.= substr(@openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size);
1051                          $offset = 2 * $this->block_size;
1052                      } else {
1053                          $offset = $this->block_size;
1054                      }
1055                      $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV);
1056                      if ($this->continuousBuffer) {
1057                          $this->decryptIV = substr($ciphertext, -$offset, $this->block_size);
1058                      }
1059                      break;
1060                  case self::MODE_CTR:
1061                      $plaintext = $this->_openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer);
1062                      break;
1063                  case self::MODE_CFB:
1064                      // cfb loosely routines inspired by openssl's:
1065                      // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
1066                      $plaintext = '';
1067                      if ($this->continuousBuffer) {
1068                          $iv = &$this->decryptIV;
1069                          $pos = &$this->buffer['pos'];
1070                      } else {
1071                          $iv = $this->decryptIV;
1072                          $pos = 0;
1073                      }
1074                      $len = strlen($ciphertext);
1075                      $i = 0;
1076                      if ($pos) {
1077                          $orig_pos = $pos;
1078                          $max = $this->block_size - $pos;
1079                          if ($len >= $max) {
1080                              $i = $max;
1081                              $len-= $max;
1082                              $pos = 0;
1083                          } else {
1084                              $i = $len;
1085                              $pos+= $len;
1086                              $len = 0;
1087                          }
1088                          // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $this->blocksize
1089                          $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1090                          $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1091                          $ciphertext = substr($ciphertext, $i);
1092                      }
1093                      $overflow = $len % $this->block_size;
1094                      if ($overflow) {
1095                          $plaintext.= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1096                          if ($len - $overflow) {
1097                              $iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow);
1098                          }
1099                          $iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1100                          $plaintext.= $iv ^ substr($ciphertext, -$overflow);
1101                          $iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow);
1102                          $pos = $overflow;
1103                      } elseif ($len) {
1104                          $plaintext.= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1105                          $iv = substr($ciphertext, -$this->block_size);
1106                      }
1107                      break;
1108                  case self::MODE_CFB8:
1109                      $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV);
1110                      if ($this->continuousBuffer) {
1111                          if (($len = strlen($ciphertext)) >= $this->block_size) {
1112                              $this->decryptIV = substr($ciphertext, -$this->block_size);
1113                          } else {
1114                              $this->decryptIV = substr($this->decryptIV, $len - $this->block_size) . substr($ciphertext, -$len);
1115                          }
1116                      }
1117                      break;
1118                  case self::MODE_OFB:
1119                      $plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
1120              }
1121  
1122              return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1123          }
1124  
1125          if ($this->engine === self::ENGINE_MCRYPT) {
1126              $block_size = $this->block_size;
1127              if ($this->changed) {
1128                  $this->_setupMcrypt();
1129                  $this->changed = false;
1130              }
1131              if ($this->dechanged) {
1132                  @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
1133                  $this->dechanged = false;
1134              }
1135  
1136              if ($this->mode == self::MODE_CFB && $this->continuousBuffer) {
1137                  $iv = &$this->decryptIV;
1138                  $pos = &$this->debuffer['pos'];
1139                  $len = strlen($ciphertext);
1140                  $plaintext = '';
1141                  $i = 0;
1142                  if ($pos) {
1143                      $orig_pos = $pos;
1144                      $max = $block_size - $pos;
1145                      if ($len >= $max) {
1146                          $i = $max;
1147                          $len-= $max;
1148                          $pos = 0;
1149                      } else {
1150                          $i = $len;
1151                          $pos+= $len;
1152                          $len = 0;
1153                      }
1154                      // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1155                      $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1156                      $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1157                  }
1158                  if ($len >= $block_size) {
1159                      $cb = substr($ciphertext, $i, $len - $len % $block_size);
1160                      $plaintext.= @mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
1161                      $iv = substr($cb, -$block_size);
1162                      $len%= $block_size;
1163                  }
1164                  if ($len) {
1165                      $iv = @mcrypt_generic($this->ecb, $iv);
1166                      $plaintext.= $iv ^ substr($ciphertext, -$len);
1167                      $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
1168                      $pos = $len;
1169                  }
1170  
1171                  return $plaintext;
1172              }
1173  
1174              $plaintext = @mdecrypt_generic($this->demcrypt, $ciphertext);
1175  
1176              if (!$this->continuousBuffer) {
1177                  @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
1178              }
1179  
1180              return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1181          }
1182  
1183          if ($this->changed) {
1184              $this->_setup();
1185              $this->changed = false;
1186          }
1187          if ($this->use_inline_crypt) {
1188              $inline = $this->inline_crypt;
1189              return $inline('decrypt', $this, $ciphertext);
1190          }
1191  
1192          $block_size = $this->block_size;
1193  
1194          $buffer = &$this->debuffer;
1195          $plaintext = '';
1196          switch ($this->mode) {
1197              case self::MODE_ECB:
1198                  for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1199                      $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
1200                  }
1201                  break;
1202              case self::MODE_CBC:
1203                  $xor = $this->decryptIV;
1204                  for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1205                      $block = substr($ciphertext, $i, $block_size);
1206                      $plaintext.= $this->_decryptBlock($block) ^ $xor;
1207                      $xor = $block;
1208                  }
1209                  if ($this->continuousBuffer) {
1210                      $this->decryptIV = $xor;
1211                  }
1212                  break;
1213              case self::MODE_CTR:
1214                  $xor = $this->decryptIV;
1215                  if (strlen($buffer['ciphertext'])) {
1216                      for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1217                          $block = substr($ciphertext, $i, $block_size);
1218                          if (strlen($block) > strlen($buffer['ciphertext'])) {
1219                              $buffer['ciphertext'].= $this->_encryptBlock($xor);
1220                              $this->_increment_str($xor);
1221                          }
1222                          $key = $this->_string_shift($buffer['ciphertext'], $block_size);
1223                          $plaintext.= $block ^ $key;
1224                      }
1225                  } else {
1226                      for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1227                          $block = substr($ciphertext, $i, $block_size);
1228                          $key = $this->_encryptBlock($xor);
1229                          $this->_increment_str($xor);
1230                          $plaintext.= $block ^ $key;
1231                      }
1232                  }
1233                  if ($this->continuousBuffer) {
1234                      $this->decryptIV = $xor;
1235                      if ($start = strlen($ciphertext) % $block_size) {
1236                          $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1237                      }
1238                  }
1239                  break;
1240              case self::MODE_CFB:
1241                  if ($this->continuousBuffer) {
1242                      $iv = &$this->decryptIV;
1243                      $pos = &$buffer['pos'];
1244                  } else {
1245                      $iv = $this->decryptIV;
1246                      $pos = 0;
1247                  }
1248                  $len = strlen($ciphertext);
1249                  $i = 0;
1250                  if ($pos) {
1251                      $orig_pos = $pos;
1252                      $max = $block_size - $pos;
1253                      if ($len >= $max) {
1254                          $i = $max;
1255                          $len-= $max;
1256                          $pos = 0;
1257                      } else {
1258                          $i = $len;
1259                          $pos+= $len;
1260                          $len = 0;
1261                      }
1262                      // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1263                      $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1264                      $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1265                  }
1266                  while ($len >= $block_size) {
1267                      $iv = $this->_encryptBlock($iv);
1268                      $cb = substr($ciphertext, $i, $block_size);
1269                      $plaintext.= $iv ^ $cb;
1270                      $iv = $cb;
1271                      $len-= $block_size;
1272                      $i+= $block_size;
1273                  }
1274                  if ($len) {
1275                      $iv = $this->_encryptBlock($iv);
1276                      $plaintext.= $iv ^ substr($ciphertext, $i);
1277                      $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
1278                      $pos = $len;
1279                  }
1280                  break;
1281              case self::MODE_CFB8:
1282                  $plaintext = '';
1283                  $len = strlen($ciphertext);
1284                  $iv = $this->decryptIV;
1285  
1286                  for ($i = 0; $i < $len; ++$i) {
1287                      $plaintext .= $ciphertext[$i] ^ $this->_encryptBlock($iv);
1288                      $iv = substr($iv, 1) . $ciphertext[$i];
1289                  }
1290  
1291                  if ($this->continuousBuffer) {
1292                      if ($len >= $block_size) {
1293                          $this->decryptIV = substr($ciphertext, -$block_size);
1294                      } else {
1295                          $this->decryptIV = substr($this->decryptIV, $len - $block_size) . substr($ciphertext, -$len);
1296                      }
1297                  }
1298                  break;
1299              case self::MODE_OFB:
1300                  $xor = $this->decryptIV;
1301                  if (strlen($buffer['xor'])) {
1302                      for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1303                          $block = substr($ciphertext, $i, $block_size);
1304                          if (strlen($block) > strlen($buffer['xor'])) {
1305                              $xor = $this->_encryptBlock($xor);
1306                              $buffer['xor'].= $xor;
1307                          }
1308                          $key = $this->_string_shift($buffer['xor'], $block_size);
1309                          $plaintext.= $block ^ $key;
1310                      }
1311                  } else {
1312                      for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1313                          $xor = $this->_encryptBlock($xor);
1314                          $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
1315                      }
1316                      $key = $xor;
1317                  }
1318                  if ($this->continuousBuffer) {
1319                      $this->decryptIV = $xor;
1320                      if ($start = strlen($ciphertext) % $block_size) {
1321                          $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1322                      }
1323                  }
1324                  break;
1325              case self::MODE_STREAM:
1326                  $plaintext = $this->_decryptBlock($ciphertext);
1327                  break;
1328          }
1329          return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1330      }
1331  
1332      /**
1333       * OpenSSL CTR Processor
1334       *
1335       * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1336       * for CTR is the same for both encrypting and decrypting this function is re-used by both Base::encrypt()
1337       * and Base::decrypt(). Also, OpenSSL doesn't implement CTR for all of it's symmetric ciphers so this
1338       * function will emulate CTR with ECB when necessary.
1339       *
1340       * @see self::encrypt()
1341       * @see self::decrypt()
1342       * @param string $plaintext
1343       * @param string $encryptIV
1344       * @param array $buffer
1345       * @return string
1346       * @access private
1347       */
1348      function _openssl_ctr_process($plaintext, &$encryptIV, &$buffer)
1349      {
1350          $ciphertext = '';
1351  
1352          $block_size = $this->block_size;
1353          $key = $this->key;
1354  
1355          if ($this->openssl_emulate_ctr) {
1356              $xor = $encryptIV;
1357              if (strlen($buffer['ciphertext'])) {
1358                  for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1359                      $block = substr($plaintext, $i, $block_size);
1360                      if (strlen($block) > strlen($buffer['ciphertext'])) {
1361                          $result = @openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1362                          $result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
1363                          $buffer['ciphertext'].= $result;
1364                      }
1365                      $this->_increment_str($xor);
1366                      $otp = $this->_string_shift($buffer['ciphertext'], $block_size);
1367                      $ciphertext.= $block ^ $otp;
1368                  }
1369              } else {
1370                  for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1371                      $block = substr($plaintext, $i, $block_size);
1372                      $otp = @openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1373                      $otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp;
1374                      $this->_increment_str($xor);
1375                      $ciphertext.= $block ^ $otp;
1376                  }
1377              }
1378              if ($this->continuousBuffer) {
1379                  $encryptIV = $xor;
1380                  if ($start = strlen($plaintext) % $block_size) {
1381                      $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1382                  }
1383              }
1384  
1385              return $ciphertext;
1386          }
1387  
1388          if (strlen($buffer['ciphertext'])) {
1389              $ciphertext = $plaintext ^ $this->_string_shift($buffer['ciphertext'], strlen($plaintext));
1390              $plaintext = substr($plaintext, strlen($ciphertext));
1391  
1392              if (!strlen($plaintext)) {
1393                  return $ciphertext;
1394              }
1395          }
1396  
1397          $overflow = strlen($plaintext) % $block_size;
1398          if ($overflow) {
1399              $plaintext2 = $this->_string_pop($plaintext, $overflow); // ie. trim $plaintext to a multiple of $block_size and put rest of $plaintext in $plaintext2
1400              $encrypted = openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1401              $temp = $this->_string_pop($encrypted, $block_size);
1402              $ciphertext.= $encrypted . ($plaintext2 ^ $temp);
1403              if ($this->continuousBuffer) {
1404                  $buffer['ciphertext'] = substr($temp, $overflow);
1405                  $encryptIV = $temp;
1406              }
1407          } elseif (!strlen($buffer['ciphertext'])) {
1408              $ciphertext.= openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1409              $temp = $this->_string_pop($ciphertext, $block_size);
1410              if ($this->continuousBuffer) {
1411                  $encryptIV = $temp;
1412              }
1413          }
1414          if ($this->continuousBuffer) {
1415              if (!defined('OPENSSL_RAW_DATA')) {
1416                  $encryptIV.= @openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1417              }
1418              $encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1419              if ($overflow) {
1420                  $this->_increment_str($encryptIV);
1421              }
1422          }
1423  
1424          return $ciphertext;
1425      }
1426  
1427      /**
1428       * OpenSSL OFB Processor
1429       *
1430       * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1431       * for OFB is the same for both encrypting and decrypting this function is re-used by both Base::encrypt()
1432       * and Base::decrypt().
1433       *
1434       * @see self::encrypt()
1435       * @see self::decrypt()
1436       * @param string $plaintext
1437       * @param string $encryptIV
1438       * @param array $buffer
1439       * @return string
1440       * @access private
1441       */
1442      function _openssl_ofb_process($plaintext, &$encryptIV, &$buffer)
1443      {
1444          if (strlen($buffer['xor'])) {
1445              $ciphertext = $plaintext ^ $buffer['xor'];
1446              $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
1447              $plaintext = substr($plaintext, strlen($ciphertext));
1448          } else {
1449              $ciphertext = '';
1450          }
1451  
1452          $block_size = $this->block_size;
1453  
1454          $len = strlen($plaintext);
1455          $key = $this->key;
1456          $overflow = $len % $block_size;
1457  
1458          if (strlen($plaintext)) {
1459              if ($overflow) {
1460                  $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1461                  $xor = $this->_string_pop($ciphertext, $block_size);
1462                  if ($this->continuousBuffer) {
1463                      $encryptIV = $xor;
1464                  }
1465                  $ciphertext.= $this->_string_shift($xor, $overflow) ^ substr($plaintext, -$overflow);
1466                  if ($this->continuousBuffer) {
1467                      $buffer['xor'] = $xor;
1468                  }
1469              } else {
1470                  $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1471                  if ($this->continuousBuffer) {
1472                      $encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size);
1473                  }
1474              }
1475          }
1476  
1477          return $ciphertext;
1478      }
1479  
1480      /**
1481       * phpseclib <-> OpenSSL Mode Mapper
1482       *
1483       * May need to be overwritten by classes extending this one in some cases
1484       *
1485       * @return int
1486       * @access private
1487       */
1488      function _openssl_translate_mode()
1489      {
1490          switch ($this->mode) {
1491              case self::MODE_ECB:
1492                  return 'ecb';
1493              case self::MODE_CBC:
1494                  return 'cbc';
1495              case self::MODE_CTR:
1496                  return 'ctr';
1497              case self::MODE_CFB:
1498                  return 'cfb';
1499              case self::MODE_CFB8:
1500                  return 'cfb8';
1501              case self::MODE_OFB:
1502                  return 'ofb';
1503          }
1504      }
1505  
1506      /**
1507       * Pad "packets".
1508       *
1509       * Block ciphers working by encrypting between their specified [$this->]block_size at a time
1510       * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
1511       * pad the input so that it is of the proper length.
1512       *
1513       * Padding is enabled by default.  Sometimes, however, it is undesirable to pad strings.  Such is the case in SSH,
1514       * where "packets" are padded with random bytes before being encrypted.  Unpad these packets and you risk stripping
1515       * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1516       * transmitted separately)
1517       *
1518       * @see self::disablePadding()
1519       * @access public
1520       */
1521      function enablePadding()
1522      {
1523          $this->padding = true;
1524      }
1525  
1526      /**
1527       * Do not pad packets.
1528       *
1529       * @see self::enablePadding()
1530       * @access public
1531       */
1532      function disablePadding()
1533      {
1534          $this->padding = false;
1535      }
1536  
1537      /**
1538       * Treat consecutive "packets" as if they are a continuous buffer.
1539       *
1540       * Say you have a 32-byte plaintext $plaintext.  Using the default behavior, the two following code snippets
1541       * will yield different outputs:
1542       *
1543       * <code>
1544       *    echo $rijndael->encrypt(substr($plaintext,  0, 16));
1545       *    echo $rijndael->encrypt(substr($plaintext, 16, 16));
1546       * </code>
1547       * <code>
1548       *    echo $rijndael->encrypt($plaintext);
1549       * </code>
1550       *
1551       * The solution is to enable the continuous buffer.  Although this will resolve the above discrepancy, it creates
1552       * another, as demonstrated with the following:
1553       *
1554       * <code>
1555       *    $rijndael->encrypt(substr($plaintext, 0, 16));
1556       *    echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1557       * </code>
1558       * <code>
1559       *    echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1560       * </code>
1561       *
1562       * With the continuous buffer disabled, these would yield the same output.  With it enabled, they yield different
1563       * outputs.  The reason is due to the fact that the initialization vector's change after every encryption /
1564       * decryption round when the continuous buffer is enabled.  When it's disabled, they remain constant.
1565       *
1566       * Put another way, when the continuous buffer is enabled, the state of the \phpseclib\Crypt\*() object changes after each
1567       * encryption / decryption round, whereas otherwise, it'd remain constant.  For this reason, it's recommended that
1568       * continuous buffers not be used.  They do offer better security and are, in fact, sometimes required (SSH uses them),
1569       * however, they are also less intuitive and more likely to cause you problems.
1570       *
1571       * @see self::disableContinuousBuffer()
1572       * @access public
1573       * @internal Could, but not must, extend by the child Crypt_* class
1574       */
1575      function enableContinuousBuffer()
1576      {
1577          if ($this->mode == self::MODE_ECB) {
1578              return;
1579          }
1580  
1581          $this->continuousBuffer = true;
1582  
1583          $this->_setEngine();
1584      }
1585  
1586      /**
1587       * Treat consecutive packets as if they are a discontinuous buffer.
1588       *
1589       * The default behavior.
1590       *
1591       * @see self::enableContinuousBuffer()
1592       * @access public
1593       * @internal Could, but not must, extend by the child Crypt_* class
1594       */
1595      function disableContinuousBuffer()
1596      {
1597          if ($this->mode == self::MODE_ECB) {
1598              return;
1599          }
1600          if (!$this->continuousBuffer) {
1601              return;
1602          }
1603  
1604          $this->continuousBuffer = false;
1605          $this->changed = true;
1606  
1607          $this->_setEngine();
1608      }
1609  
1610      /**
1611       * Test for engine validity
1612       *
1613       * @see self::__construct()
1614       * @param int $engine
1615       * @access public
1616       * @return bool
1617       */
1618      function isValidEngine($engine)
1619      {
1620          switch ($engine) {
1621              case self::ENGINE_OPENSSL:
1622                  if ($this->mode == self::MODE_STREAM && $this->continuousBuffer) {
1623                      return false;
1624                  }
1625                  $this->openssl_emulate_ctr = false;
1626                  $result = $this->cipher_name_openssl &&
1627                            extension_loaded('openssl') &&
1628                            // PHP 5.3.0 - 5.3.2 did not let you set IV's
1629                            version_compare(PHP_VERSION, '5.3.3', '>=');
1630                  if (!$result) {
1631                      return false;
1632                  }
1633  
1634                  // prior to PHP 5.4.0 OPENSSL_RAW_DATA and OPENSSL_ZERO_PADDING were not defined. instead of expecting an integer
1635                  // $options openssl_encrypt expected a boolean $raw_data.
1636                  if (!defined('OPENSSL_RAW_DATA')) {
1637                      $this->openssl_options = true;
1638                  } else {
1639                      $this->openssl_options = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;
1640                  }
1641  
1642                  $methods = openssl_get_cipher_methods();
1643                  if (in_array($this->cipher_name_openssl, $methods)) {
1644                      return true;
1645                  }
1646                  // not all of openssl's symmetric cipher's support ctr. for those
1647                  // that don't we'll emulate it
1648                  switch ($this->mode) {
1649                      case self::MODE_CTR:
1650                          if (in_array($this->cipher_name_openssl_ecb, $methods)) {
1651                              $this->openssl_emulate_ctr = true;
1652                              return true;
1653                          }
1654                  }
1655                  return false;
1656              case self::ENGINE_MCRYPT:
1657                  return $this->cipher_name_mcrypt &&
1658                         extension_loaded('mcrypt') &&
1659                         in_array($this->cipher_name_mcrypt, @mcrypt_list_algorithms());
1660              case self::ENGINE_INTERNAL:
1661                  return true;
1662          }
1663  
1664          return false;
1665      }
1666  
1667      /**
1668       * Sets the preferred crypt engine
1669       *
1670       * Currently, $engine could be:
1671       *
1672       * - \phpseclib\Crypt\Base::ENGINE_OPENSSL  [very fast]
1673       *
1674       * - \phpseclib\Crypt\Base::ENGINE_MCRYPT   [fast]
1675       *
1676       * - \phpseclib\Crypt\Base::ENGINE_INTERNAL [slow]
1677       *
1678       * If the preferred crypt engine is not available the fastest available one will be used
1679       *
1680       * @see self::__construct()
1681       * @param int $engine
1682       * @access public
1683       */
1684      function setPreferredEngine($engine)
1685      {
1686          switch ($engine) {
1687              //case self::ENGINE_OPENSSL;
1688              case self::ENGINE_MCRYPT:
1689              case self::ENGINE_INTERNAL:
1690                  $this->preferredEngine = $engine;
1691                  break;
1692              default:
1693                  $this->preferredEngine = self::ENGINE_OPENSSL;
1694          }
1695  
1696          $this->_setEngine();
1697      }
1698  
1699      /**
1700       * Returns the engine currently being utilized
1701       *
1702       * @see self::_setEngine()
1703       * @access public
1704       */
1705      function getEngine()
1706      {
1707          return $this->engine;
1708      }
1709  
1710      /**
1711       * Sets the engine as appropriate
1712       *
1713       * @see self::__construct()
1714       * @access private
1715       */
1716      function _setEngine()
1717      {
1718          $this->engine = null;
1719  
1720          $candidateEngines = array(
1721              $this->preferredEngine,
1722              self::ENGINE_OPENSSL,
1723              self::ENGINE_MCRYPT
1724          );
1725          foreach ($candidateEngines as $engine) {
1726              if ($this->isValidEngine($engine)) {
1727                  $this->engine = $engine;
1728                  break;
1729              }
1730          }
1731          if (!$this->engine) {
1732              $this->engine = self::ENGINE_INTERNAL;
1733          }
1734  
1735          if ($this->engine != self::ENGINE_MCRYPT && $this->enmcrypt) {
1736              // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed,
1737              // (re)open them with the module named in $this->cipher_name_mcrypt
1738              @mcrypt_module_close($this->enmcrypt);
1739              @mcrypt_module_close($this->demcrypt);
1740              $this->enmcrypt = null;
1741              $this->demcrypt = null;
1742  
1743              if ($this->ecb) {
1744                  @mcrypt_module_close($this->ecb);
1745                  $this->ecb = null;
1746              }
1747          }
1748  
1749          $this->changed = true;
1750      }
1751  
1752      /**
1753       * Encrypts a block
1754       *
1755       * Note: Must be extended by the child \phpseclib\Crypt\* class
1756       *
1757       * @access private
1758       * @param string $in
1759       * @return string
1760       */
1761      abstract function _encryptBlock($in);
1762  
1763      /**
1764       * Decrypts a block
1765       *
1766       * Note: Must be extended by the child \phpseclib\Crypt\* class
1767       *
1768       * @access private
1769       * @param string $in
1770       * @return string
1771       */
1772      abstract function _decryptBlock($in);
1773  
1774      /**
1775       * Setup the key (expansion)
1776       *
1777       * Only used if $engine == self::ENGINE_INTERNAL
1778       *
1779       * Note: Must extend by the child \phpseclib\Crypt\* class
1780       *
1781       * @see self::_setup()
1782       * @access private
1783       */
1784      abstract function _setupKey();
1785  
1786      /**
1787       * Setup the self::ENGINE_INTERNAL $engine
1788       *
1789       * (re)init, if necessary, the internal cipher $engine and flush all $buffers
1790       * Used (only) if $engine == self::ENGINE_INTERNAL
1791       *
1792       * _setup() will be called each time if $changed === true
1793       * typically this happens when using one or more of following public methods:
1794       *
1795       * - setKey()
1796       *
1797       * - setIV()
1798       *
1799       * - disableContinuousBuffer()
1800       *
1801       * - First run of encrypt() / decrypt() with no init-settings
1802       *
1803       * @see self::setKey()
1804       * @see self::setIV()
1805       * @see self::disableContinuousBuffer()
1806       * @access private
1807       * @internal _setup() is always called before en/decryption.
1808       * @internal Could, but not must, extend by the child Crypt_* class
1809       */
1810      function _setup()
1811      {
1812          $this->_clearBuffers();
1813          $this->_setupKey();
1814  
1815          if ($this->use_inline_crypt) {
1816              $this->_setupInlineCrypt();
1817          }
1818      }
1819  
1820      /**
1821       * Setup the self::ENGINE_MCRYPT $engine
1822       *
1823       * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers
1824       * Used (only) if $engine = self::ENGINE_MCRYPT
1825       *
1826       * _setupMcrypt() will be called each time if $changed === true
1827       * typically this happens when using one or more of following public methods:
1828       *
1829       * - setKey()
1830       *
1831       * - setIV()
1832       *
1833       * - disableContinuousBuffer()
1834       *
1835       * - First run of encrypt() / decrypt()
1836       *
1837       * @see self::setKey()
1838       * @see self::setIV()
1839       * @see self::disableContinuousBuffer()
1840       * @access private
1841       * @internal Could, but not must, extend by the child Crypt_* class
1842       */
1843      function _setupMcrypt()
1844      {
1845          $this->_clearBuffers();
1846          $this->enchanged = $this->dechanged = true;
1847  
1848          if (!isset($this->enmcrypt)) {
1849              static $mcrypt_modes = array(
1850                  self::MODE_CTR    => 'ctr',
1851                  self::MODE_ECB    => MCRYPT_MODE_ECB,
1852                  self::MODE_CBC    => MCRYPT_MODE_CBC,
1853                  self::MODE_CFB    => 'ncfb',
1854                  self::MODE_CFB8   => MCRYPT_MODE_CFB,
1855                  self::MODE_OFB    => MCRYPT_MODE_NOFB,
1856                  self::MODE_STREAM => MCRYPT_MODE_STREAM,
1857              );
1858  
1859              $this->demcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
1860              $this->enmcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
1861  
1862              // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer()
1863              // to workaround mcrypt's broken ncfb implementation in buffered mode
1864              // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
1865              if ($this->mode == self::MODE_CFB) {
1866                  $this->ecb = @mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
1867              }
1868          } // else should mcrypt_generic_deinit be called?
1869  
1870          if ($this->mode == self::MODE_CFB) {
1871              @mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
1872          }
1873      }
1874  
1875      /**
1876       * Pads a string
1877       *
1878       * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
1879       * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to
1880       * chr($this->block_size - (strlen($text) % $this->block_size)
1881       *
1882       * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1883       * and padding will, hence forth, be enabled.
1884       *
1885       * @see self::_unpad()
1886       * @param string $text
1887       * @access private
1888       * @return string
1889       */
1890      function _pad($text)
1891      {
1892          $length = strlen($text);
1893  
1894          if (!$this->padding) {
1895              if ($length % $this->block_size == 0) {
1896                  return $text;
1897              } else {
1898                  user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
1899                  $this->padding = true;
1900              }
1901          }
1902  
1903          $pad = $this->block_size - ($length % $this->block_size);
1904  
1905          return str_pad($text, $length + $pad, chr($pad));
1906      }
1907  
1908      /**
1909       * Unpads a string.
1910       *
1911       * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1912       * and false will be returned.
1913       *
1914       * @see self::_pad()
1915       * @param string $text
1916       * @access private
1917       * @return string
1918       */
1919      function _unpad($text)
1920      {
1921          if (!$this->padding) {
1922              return $text;
1923          }
1924  
1925          $length = ord($text[strlen($text) - 1]);
1926  
1927          if (!$length || $length > $this->block_size) {
1928              return false;
1929          }
1930  
1931          return substr($text, 0, -$length);
1932      }
1933  
1934      /**
1935       * Clears internal buffers
1936       *
1937       * Clearing/resetting the internal buffers is done everytime
1938       * after disableContinuousBuffer() or on cipher $engine (re)init
1939       * ie after setKey() or setIV()
1940       *
1941       * @access public
1942       * @internal Could, but not must, extend by the child Crypt_* class
1943       */
1944      function _clearBuffers()
1945      {
1946          $this->enbuffer = $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
1947  
1948          // mcrypt's handling of invalid's $iv:
1949          // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size);
1950          $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");
1951  
1952          if (!$this->skip_key_adjustment) {
1953              $this->key = str_pad(substr($this->key, 0, $this->key_length), $this->key_length, "\0");
1954          }
1955      }
1956  
1957      /**
1958       * String Shift
1959       *
1960       * Inspired by array_shift
1961       *
1962       * @param string $string
1963       * @param int $index
1964       * @access private
1965       * @return string
1966       */
1967      function _string_shift(&$string, $index = 1)
1968      {
1969          $substr = substr($string, 0, $index);
1970          $string = substr($string, $index);
1971          return $substr;
1972      }
1973  
1974      /**
1975       * String Pop
1976       *
1977       * Inspired by array_pop
1978       *
1979       * @param string $string
1980       * @param int $index
1981       * @access private
1982       * @return string
1983       */
1984      function _string_pop(&$string, $index = 1)
1985      {
1986          $substr = substr($string, -$index);
1987          $string = substr($string, 0, -$index);
1988          return $substr;
1989      }
1990  
1991      /**
1992       * Increment the current string
1993       *
1994       * @see self::decrypt()
1995       * @see self::encrypt()
1996       * @param string $var
1997       * @access private
1998       */
1999      function _increment_str(&$var)
2000      {
2001          for ($i = 4; $i <= strlen($var); $i+= 4) {
2002              $temp = substr($var, -$i, 4);
2003              switch ($temp) {
2004                  case "\xFF\xFF\xFF\xFF":
2005                      $var = substr_replace($var, "\x00\x00\x00\x00", -$i, 4);
2006                      break;
2007                  case "\x7F\xFF\xFF\xFF":
2008                      $var = substr_replace($var, "\x80\x00\x00\x00", -$i, 4);
2009                      return;
2010                  default:
2011                      $temp = unpack('Nnum', $temp);
2012                      $var = substr_replace($var, pack('N', $temp['num'] + 1), -$i, 4);
2013                      return;
2014              }
2015          }
2016  
2017          $remainder = strlen($var) % 4;
2018  
2019          if ($remainder == 0) {
2020              return;
2021          }
2022  
2023          $temp = unpack('Nnum', str_pad(substr($var, 0, $remainder), 4, "\0", STR_PAD_LEFT));
2024          $temp = substr(pack('N', $temp['num'] + 1), -$remainder);
2025          $var = substr_replace($var, $temp, 0, $remainder);
2026      }
2027  
2028      /**
2029       * Setup the performance-optimized function for de/encrypt()
2030       *
2031       * Stores the created (or existing) callback function-name
2032       * in $this->inline_crypt
2033       *
2034       * Internally for phpseclib developers:
2035       *
2036       *     _setupInlineCrypt() would be called only if:
2037       *
2038       *     - $engine == self::ENGINE_INTERNAL and
2039       *
2040       *     - $use_inline_crypt === true
2041       *
2042       *     - each time on _setup(), after(!) _setupKey()
2043       *
2044       *
2045       *     This ensures that _setupInlineCrypt() has always a
2046       *     full ready2go initializated internal cipher $engine state
2047       *     where, for example, the keys allready expanded,
2048       *     keys/block_size calculated and such.
2049       *
2050       *     It is, each time if called, the responsibility of _setupInlineCrypt():
2051       *
2052       *     - to set $this->inline_crypt to a valid and fully working callback function
2053       *       as a (faster) replacement for encrypt() / decrypt()
2054       *
2055       *     - NOT to create unlimited callback functions (for memory reasons!)
2056       *       no matter how often _setupInlineCrypt() would be called. At some
2057       *       point of amount they must be generic re-useable.
2058       *
2059       *     - the code of _setupInlineCrypt() it self,
2060       *       and the generated callback code,
2061       *       must be, in following order:
2062       *       - 100% safe
2063       *       - 100% compatible to encrypt()/decrypt()
2064       *       - using only php5+ features/lang-constructs/php-extensions if
2065       *         compatibility (down to php4) or fallback is provided
2066       *       - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-)
2067       *       - >= 10% faster than encrypt()/decrypt() [which is, by the way,
2068       *         the reason for the existence of _setupInlineCrypt() :-)]
2069       *       - memory-nice
2070       *       - short (as good as possible)
2071       *
2072       * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code.
2073       *       - In case of using inline crypting, _setupInlineCrypt() must extend by the child \phpseclib\Crypt\* class.
2074       *       - The following variable names are reserved:
2075       *         - $_*  (all variable names prefixed with an underscore)
2076       *         - $self (object reference to it self. Do not use $this, but $self instead)
2077       *         - $in (the content of $in has to en/decrypt by the generated code)
2078       *       - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only
2079       *
2080       *
2081       * @see self::_setup()
2082       * @see self::_createInlineCryptFunction()
2083       * @see self::encrypt()
2084       * @see self::decrypt()
2085       * @access private
2086       * @internal If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt()
2087       */
2088      function _setupInlineCrypt()
2089      {
2090          // If, for any reason, an extending \phpseclib\Crypt\Base() \phpseclib\Crypt\* class
2091          // not using inline crypting then it must be ensured that: $this->use_inline_crypt = false
2092          // ie in the class var declaration of $use_inline_crypt in general for the \phpseclib\Crypt\* class,
2093          // in the constructor at object instance-time
2094          // or, if it's runtime-specific, at runtime
2095  
2096          $this->use_inline_crypt = false;
2097      }
2098  
2099      /**
2100       * Creates the performance-optimized function for en/decrypt()
2101       *
2102       * Internally for phpseclib developers:
2103       *
2104       *    _createInlineCryptFunction():
2105       *
2106       *    - merge the $cipher_code [setup'ed by _setupInlineCrypt()]
2107       *      with the current [$this->]mode of operation code
2108       *
2109       *    - create the $inline function, which called by encrypt() / decrypt()
2110       *      as its replacement to speed up the en/decryption operations.
2111       *
2112       *    - return the name of the created $inline callback function
2113       *
2114       *    - used to speed up en/decryption
2115       *
2116       *
2117       *
2118       *    The main reason why can speed up things [up to 50%] this way are:
2119       *
2120       *    - using variables more effective then regular.
2121       *      (ie no use of expensive arrays but integers $k_0, $k_1 ...
2122       *      or even, for example, the pure $key[] values hardcoded)
2123       *
2124       *    - avoiding 1000's of function calls of ie _encryptBlock()
2125       *      but inlining the crypt operations.
2126       *      in the mode of operation for() loop.
2127       *
2128       *    - full loop unroll the (sometimes key-dependent) rounds
2129       *      avoiding this way ++$i counters and runtime-if's etc...
2130       *
2131       *    The basic code architectur of the generated $inline en/decrypt()
2132       *    lambda function, in pseudo php, is:
2133       *
2134       *    <code>
2135       *    +----------------------------------------------------------------------------------------------+
2136       *    | callback $inline = create_function:                                                          |
2137       *    | lambda_function_0001_crypt_ECB($action, $text)                                               |
2138       *    | {                                                                                            |
2139       *    |     INSERT PHP CODE OF:                                                                      |
2140       *    |     $cipher_code['init_crypt'];                  // general init code.                       |
2141       *    |                                                  // ie: $sbox'es declarations used for       |
2142       *    |                                                  //     encrypt and decrypt'ing.             |
2143       *    |                                                                                              |
2144       *    |     switch ($action) {                                                                       |
2145       *    |         case 'encrypt':                                                                      |
2146       *    |             INSERT PHP CODE OF:                                                              |
2147       *    |             $cipher_code['init_encrypt'];       // encrypt sepcific init code.               |
2148       *    |                                                    ie: specified $key or $box                |
2149       *    |                                                        declarations for encrypt'ing.         |
2150       *    |                                                                                              |
2151       *    |             foreach ($ciphertext) {                                                          |
2152       *    |                 $in = $block_size of $ciphertext;                                            |
2153       *    |                                                                                              |
2154       *    |                 INSERT PHP CODE OF:                                                          |
2155       *    |                 $cipher_code['encrypt_block'];  // encrypt's (string) $in, which is always:  |
2156       *    |                                                 // strlen($in) == $this->block_size          |
2157       *    |                                                 // here comes the cipher algorithm in action |
2158       *    |                                                 // for encryption.                           |
2159       *    |                                                 // $cipher_code['encrypt_block'] has to      |
2160       *    |                                                 // encrypt the content of the $in variable   |
2161       *    |                                                                                              |
2162       *    |                 $plaintext .= $in;                                                           |
2163       *    |             }                                                                                |
2164       *    |             return $plaintext;                                                               |
2165       *    |                                                                                              |
2166       *    |         case 'decrypt':                                                                      |
2167       *    |             INSERT PHP CODE OF:                                                              |
2168       *    |             $cipher_code['init_decrypt'];       // decrypt sepcific init code                |
2169       *    |                                                    ie: specified $key or $box                |
2170       *    |                                                        declarations for decrypt'ing.         |
2171       *    |             foreach ($plaintext) {                                                           |
2172       *    |                 $in = $block_size of $plaintext;                                             |
2173       *    |                                                                                              |
2174       *    |                 INSERT PHP CODE OF:                                                          |
2175       *    |                 $cipher_code['decrypt_block'];  // decrypt's (string) $in, which is always   |
2176       *    |                                                 // strlen($in) == $this->block_size          |
2177       *    |                                                 // here comes the cipher algorithm in action |
2178       *    |                                                 // for decryption.                           |
2179       *    |                                                 // $cipher_code['decrypt_block'] has to      |
2180       *    |                                                 // decrypt the content of the $in variable   |
2181       *    |                 $ciphertext .= $in;                                                          |
2182       *    |             }                                                                                |
2183       *    |             return $ciphertext;                                                              |
2184       *    |     }                                                                                        |
2185       *    | }                                                                                            |
2186       *    +----------------------------------------------------------------------------------------------+
2187       *    </code>
2188       *
2189       *    See also the \phpseclib\Crypt\*::_setupInlineCrypt()'s for
2190       *    productive inline $cipher_code's how they works.
2191       *
2192       *    Structure of:
2193       *    <code>
2194       *    $cipher_code = array(
2195       *        'init_crypt'    => (string) '', // optional
2196       *        'init_encrypt'  => (string) '', // optional
2197       *        'init_decrypt'  => (string) '', // optional
2198       *        'encrypt_block' => (string) '', // required
2199       *        'decrypt_block' => (string) ''  // required
2200       *    );
2201       *    </code>
2202       *
2203       * @see self::_setupInlineCrypt()
2204       * @see self::encrypt()
2205       * @see self::decrypt()
2206       * @param array $cipher_code
2207       * @access private
2208       * @return string (the name of the created callback function)
2209       */
2210      function _createInlineCryptFunction($cipher_code)
2211      {
2212          $block_size = $this->block_size;
2213  
2214          // optional
2215          $init_crypt    = isset($cipher_code['init_crypt'])    ? $cipher_code['init_crypt']    : '';
2216          $init_encrypt  = isset($cipher_code['init_encrypt'])  ? $cipher_code['init_encrypt']  : '';
2217          $init_decrypt  = isset($cipher_code['init_decrypt'])  ? $cipher_code['init_decrypt']  : '';
2218          // required
2219          $encrypt_block = $cipher_code['encrypt_block'];
2220          $decrypt_block = $cipher_code['decrypt_block'];
2221  
2222          // Generating mode of operation inline code,
2223          // merged with the $cipher_code algorithm
2224          // for encrypt- and decryption.
2225          switch ($this->mode) {
2226              case self::MODE_ECB:
2227                  $encrypt = $init_encrypt . '
2228                      $_ciphertext = "";
2229                      $_plaintext_len = strlen($_text);
2230  
2231                      for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2232                          $in = substr($_text, $_i, '.$block_size.');
2233                          '.$encrypt_block.'
2234                          $_ciphertext.= $in;
2235                      }
2236  
2237                      return $_ciphertext;
2238                      ';
2239  
2240                  $decrypt = $init_decrypt . '
2241                      $_plaintext = "";
2242                      $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
2243                      $_ciphertext_len = strlen($_text);
2244  
2245                      for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2246                          $in = substr($_text, $_i, '.$block_size.');
2247                          '.$decrypt_block.'
2248                          $_plaintext.= $in;
2249                      }
2250  
2251                      return $self->_unpad($_plaintext);
2252                      ';
2253                  break;
2254              case self::MODE_CTR:
2255                  $encrypt = $init_encrypt . '
2256                      $_ciphertext = "";
2257                      $_plaintext_len = strlen($_text);
2258                      $_xor = $self->encryptIV;
2259                      $_buffer = &$self->enbuffer;
2260                      if (strlen($_buffer["ciphertext"])) {
2261                          for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2262                              $_block = substr($_text, $_i, '.$block_size.');
2263                              if (strlen($_block) > strlen($_buffer["ciphertext"])) {
2264                                  $in = $_xor;
2265                                  '.$encrypt_block.'
2266                                  $self->_increment_str($_xor);
2267                                  $_buffer["ciphertext"].= $in;
2268                              }
2269                              $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
2270                              $_ciphertext.= $_block ^ $_key;
2271                          }
2272                      } else {
2273                          for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2274                              $_block = substr($_text, $_i, '.$block_size.');
2275                              $in = $_xor;
2276                              '.$encrypt_block.'
2277                              $self->_increment_str($_xor);
2278                              $_key = $in;
2279                              $_ciphertext.= $_block ^ $_key;
2280                          }
2281                      }
2282                      if ($self->continuousBuffer) {
2283                          $self->encryptIV = $_xor;
2284                          if ($_start = $_plaintext_len % '.$block_size.') {
2285                              $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
2286                          }
2287                      }
2288  
2289                      return $_ciphertext;
2290                  ';
2291  
2292                  $decrypt = $init_encrypt . '
2293                      $_plaintext = "";
2294                      $_ciphertext_len = strlen($_text);
2295                      $_xor = $self->decryptIV;
2296                      $_buffer = &$self->debuffer;
2297  
2298                      if (strlen($_buffer["ciphertext"])) {
2299                          for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2300                              $_block = substr($_text, $_i, '.$block_size.');
2301                              if (strlen($_block) > strlen($_buffer["ciphertext"])) {
2302                                  $in = $_xor;
2303                                  '.$encrypt_block.'
2304                                  $self->_increment_str($_xor);
2305                                  $_buffer["ciphertext"].= $in;
2306                              }
2307                              $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
2308                              $_plaintext.= $_block ^ $_key;
2309                          }
2310                      } else {
2311                          for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2312                              $_block = substr($_text, $_i, '.$block_size.');
2313                              $in = $_xor;
2314                              '.$encrypt_block.'
2315                              $self->_increment_str($_xor);
2316                              $_key = $in;
2317                              $_plaintext.= $_block ^ $_key;
2318                          }
2319                      }
2320                      if ($self->continuousBuffer) {
2321                          $self->decryptIV = $_xor;
2322                          if ($_start = $_ciphertext_len % '.$block_size.') {
2323                              $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
2324                          }
2325                      }
2326  
2327                      return $_plaintext;
2328                      ';
2329                  break;
2330              case self::MODE_CFB:
2331                  $encrypt = $init_encrypt . '
2332                      $_ciphertext = "";
2333                      $_buffer = &$self->enbuffer;
2334  
2335                      if ($self->continuousBuffer) {
2336                          $_iv = &$self->encryptIV;
2337                          $_pos = &$_buffer["pos"];
2338                      } else {
2339                          $_iv = $self->encryptIV;
2340                          $_pos = 0;
2341                      }
2342                      $_len = strlen($_text);
2343                      $_i = 0;
2344                      if ($_pos) {
2345                          $_orig_pos = $_pos;
2346                          $_max = '.$block_size.' - $_pos;
2347                          if ($_len >= $_max) {
2348                              $_i = $_max;
2349                              $_len-= $_max;
2350                              $_pos = 0;
2351                          } else {
2352                              $_i = $_len;
2353                              $_pos+= $_len;
2354                              $_len = 0;
2355                          }
2356                          $_ciphertext = substr($_iv, $_orig_pos) ^ $_text;
2357                          $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i);
2358                      }
2359                      while ($_len >= '.$block_size.') {
2360                          $in = $_iv;
2361                          '.$encrypt_block.';
2362                          $_iv = $in ^ substr($_text, $_i, '.$block_size.');
2363                          $_ciphertext.= $_iv;
2364                          $_len-= '.$block_size.';
2365                          $_i+= '.$block_size.';
2366                      }
2367                      if ($_len) {
2368                          $in = $_iv;
2369                          '.$encrypt_block.'
2370                          $_iv = $in;
2371                          $_block = $_iv ^ substr($_text, $_i);
2372                          $_iv = substr_replace($_iv, $_block, 0, $_len);
2373                          $_ciphertext.= $_block;
2374                          $_pos = $_len;
2375                      }
2376                      return $_ciphertext;
2377                  ';
2378  
2379                  $decrypt = $init_encrypt . '
2380                      $_plaintext = "";
2381                      $_buffer = &$self->debuffer;
2382  
2383                      if ($self->continuousBuffer) {
2384                          $_iv = &$self->decryptIV;
2385                          $_pos = &$_buffer["pos"];
2386                      } else {
2387                          $_iv = $self->decryptIV;
2388                          $_pos = 0;
2389                      }
2390                      $_len = strlen($_text);
2391                      $_i = 0;
2392                      if ($_pos) {
2393                          $_orig_pos = $_pos;
2394                          $_max = '.$block_size.' - $_pos;
2395                          if ($_len >= $_max) {
2396                              $_i = $_max;
2397                              $_len-= $_max;
2398                              $_pos = 0;
2399                          } else {
2400                              $_i = $_len;
2401                              $_pos+= $_len;
2402                              $_len = 0;
2403                          }
2404                          $_plaintext = substr($_iv, $_orig_pos) ^ $_text;
2405                          $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i);
2406                      }
2407                      while ($_len >= '.$block_size.') {
2408                          $in = $_iv;
2409                          '.$encrypt_block.'
2410                          $_iv = $in;
2411                          $cb = substr($_text, $_i, '.$block_size.');
2412                          $_plaintext.= $_iv ^ $cb;
2413                          $_iv = $cb;
2414                          $_len-= '.$block_size.';
2415                          $_i+= '.$block_size.';
2416                      }
2417                      if ($_len) {
2418                          $in = $_iv;
2419                          '.$encrypt_block.'
2420                          $_iv = $in;
2421                          $_plaintext.= $_iv ^ substr($_text, $_i);
2422                          $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len);
2423                          $_pos = $_len;
2424                      }
2425  
2426                      return $_plaintext;
2427                      ';
2428                  break;
2429              case self::MODE_CFB8:
2430                  $encrypt = $init_encrypt . '
2431                      $_ciphertext = "";
2432                      $_len = strlen($_text);
2433                      $_iv = $self->encryptIV;
2434  
2435                      for ($_i = 0; $_i < $_len; ++$_i) {
2436                          $in = $_iv;
2437                          '.$encrypt_block.'
2438                          $_ciphertext .= ($_c = $_text[$_i] ^ $in);
2439                          $_iv = substr($_iv, 1) . $_c;
2440                      }
2441  
2442                      if ($self->continuousBuffer) {
2443                          if ($_len >= '.$block_size.') {
2444                              $self->encryptIV = substr($_ciphertext, -'.$block_size.');
2445                          } else {
2446                              $self->encryptIV = substr($self->encryptIV, $_len - '.$block_size.') . substr($_ciphertext, -$_len);
2447                          }
2448                      }
2449  
2450                      return $_ciphertext;
2451                      ';
2452                  $decrypt = $init_encrypt . '
2453                      $_plaintext = "";
2454                      $_len = strlen($_text);
2455                      $_iv = $self->decryptIV;
2456  
2457                      for ($_i = 0; $_i < $_len; ++$_i) {
2458                          $in = $_iv;
2459                          '.$encrypt_block.'
2460                          $_plaintext .= $_text[$_i] ^ $in;
2461                          $_iv = substr($_iv, 1) . $_text[$_i];
2462                      }
2463  
2464                      if ($self->continuousBuffer) {
2465                          if ($_len >= '.$block_size.') {
2466                              $self->decryptIV = substr($_text, -'.$block_size.');
2467                          } else {
2468                              $self->decryptIV = substr($self->decryptIV, $_len - '.$block_size.') . substr($_text, -$_len);
2469                          }
2470                      }
2471  
2472                      return $_plaintext;
2473                      ';
2474                  break;
2475              case self::MODE_OFB:
2476                  $encrypt = $init_encrypt . '
2477                      $_ciphertext = "";
2478                      $_plaintext_len = strlen($_text);
2479                      $_xor = $self->encryptIV;
2480                      $_buffer = &$self->enbuffer;
2481  
2482                      if (strlen($_buffer["xor"])) {
2483                          for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2484                              $_block = substr($_text, $_i, '.$block_size.');
2485                              if (strlen($_block) > strlen($_buffer["xor"])) {
2486                                  $in = $_xor;
2487                                  '.$encrypt_block.'
2488                                  $_xor = $in;
2489                                  $_buffer["xor"].= $_xor;
2490                              }
2491                              $_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
2492                              $_ciphertext.= $_block ^ $_key;
2493                          }
2494                      } else {
2495                          for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2496                              $in = $_xor;
2497                              '.$encrypt_block.'
2498                              $_xor = $in;
2499                              $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
2500                          }
2501                          $_key = $_xor;
2502                      }
2503                      if ($self->continuousBuffer) {
2504                          $self->encryptIV = $_xor;
2505                          if ($_start = $_plaintext_len % '.$block_size.') {
2506                               $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
2507                          }
2508                      }
2509                      return $_ciphertext;
2510                      ';
2511  
2512                  $decrypt = $init_encrypt . '
2513                      $_plaintext = "";
2514                      $_ciphertext_len = strlen($_text);
2515                      $_xor = $self->decryptIV;
2516                      $_buffer = &$self->debuffer;
2517  
2518                      if (strlen($_buffer["xor"])) {
2519                          for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2520                              $_block = substr($_text, $_i, '.$block_size.');
2521                              if (strlen($_block) > strlen($_buffer["xor"])) {
2522                                  $in = $_xor;
2523                                  '.$encrypt_block.'
2524                                  $_xor = $in;
2525                                  $_buffer["xor"].= $_xor;
2526                              }
2527                              $_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
2528                              $_plaintext.= $_block ^ $_key;
2529                          }
2530                      } else {
2531                          for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2532                              $in = $_xor;
2533                              '.$encrypt_block.'
2534                              $_xor = $in;
2535                              $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
2536                          }
2537                          $_key = $_xor;
2538                      }
2539                      if ($self->continuousBuffer) {
2540                          $self->decryptIV = $_xor;
2541                          if ($_start = $_ciphertext_len % '.$block_size.') {
2542                               $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
2543                          }
2544                      }
2545                      return $_plaintext;
2546                      ';
2547                  break;
2548              case self::MODE_STREAM:
2549                  $encrypt = $init_encrypt . '
2550                      $_ciphertext = "";
2551                      '.$encrypt_block.'
2552                      return $_ciphertext;
2553                      ';
2554                  $decrypt = $init_decrypt . '
2555                      $_plaintext = "";
2556                      '.$decrypt_block.'
2557                      return $_plaintext;
2558                      ';
2559                  break;
2560              // case self::MODE_CBC:
2561              default:
2562                  $encrypt = $init_encrypt . '
2563                      $_ciphertext = "";
2564                      $_plaintext_len = strlen($_text);
2565  
2566                      $in = $self->encryptIV;
2567  
2568                      for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2569                          $in = substr($_text, $_i, '.$block_size.') ^ $in;
2570                          '.$encrypt_block.'
2571                          $_ciphertext.= $in;
2572                      }
2573  
2574                      if ($self->continuousBuffer) {
2575                          $self->encryptIV = $in;
2576                      }
2577  
2578                      return $_ciphertext;
2579                      ';
2580  
2581                  $decrypt = $init_decrypt . '
2582                      $_plaintext = "";
2583                      $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
2584                      $_ciphertext_len = strlen($_text);
2585  
2586                      $_iv = $self->decryptIV;
2587  
2588                      for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2589                          $in = $_block = substr($_text, $_i, '.$block_size.');
2590                          '.$decrypt_block.'
2591                          $_plaintext.= $in ^ $_iv;
2592                          $_iv = $_block;
2593                      }
2594  
2595                      if ($self->continuousBuffer) {
2596                          $self->decryptIV = $_iv;
2597                      }
2598  
2599                      return $self->_unpad($_plaintext);
2600                      ';
2601                  break;
2602          }
2603  
2604          // Create the $inline function and return its name as string. Ready to run!
2605          if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
2606              eval('$func = function ($_action, &$self, $_text) { ' . $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' } };');
2607              return $func;
2608          }
2609  
2610          return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }');
2611      }
2612  
2613      /**
2614       * Holds the lambda_functions table (classwide)
2615       *
2616       * Each name of the lambda function, created from
2617       * _setupInlineCrypt() && _createInlineCryptFunction()
2618       * is stored, classwide (!), here for reusing.
2619       *
2620       * The string-based index of $function is a classwide
2621       * unique value representing, at least, the $mode of
2622       * operation (or more... depends of the optimizing level)
2623       * for which $mode the lambda function was created.
2624       *
2625       * @access private
2626       * @return array &$functions
2627       */
2628      function &_getLambdaFunctions()
2629      {
2630          static $functions = array();
2631          return $functions;
2632      }
2633  
2634      /**
2635       * Generates a digest from $bytes
2636       *
2637       * @see self::_setupInlineCrypt()
2638       * @access private
2639       * @param $bytes
2640       * @return string
2641       */
2642      function _hashInlineCryptFunction($bytes)
2643      {
2644          if (!isset(self::$WHIRLPOOL_AVAILABLE)) {
2645              self::$WHIRLPOOL_AVAILABLE = extension_loaded('hash') && in_array('whirlpool', hash_algos());
2646          }
2647  
2648          $result = '';
2649          $hash = $bytes;
2650  
2651          switch (true) {
2652              case self::$WHIRLPOOL_AVAILABLE:
2653                  foreach (str_split($bytes, 64) as $t) {
2654                      $hash = hash('whirlpool', $hash, true);
2655                      $result .= $t ^ $hash;
2656                  }
2657                  return $result . hash('whirlpool', $hash, true);
2658              default:
2659                  $len = strlen($bytes);
2660                  for ($i = 0; $i < $len; $i+=20) {
2661                      $t = substr($bytes, $i, 20);
2662                      $hash = pack('H*', sha1($hash));
2663                      $result .= $t ^ $hash;
2664                  }
2665                  return $result . pack('H*', sha1($hash));
2666          }
2667      }
2668  
2669      /**
2670       * Convert float to int
2671       *
2672       * On ARM CPUs converting floats to ints doesn't always work
2673       *
2674       * @access private
2675       * @param string $x
2676       * @return int
2677       */
2678      function safe_intval($x)
2679      {
2680          switch (true) {
2681              case is_int($x):
2682              // PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding"
2683              case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
2684                  return $x;
2685          }
2686          return (fmod($x, 0x80000000) & 0x7FFFFFFF) |
2687              ((fmod(floor($x / 0x80000000), 2) & 1) << 31);
2688      }
2689  
2690      /**
2691       * eval()'able string for in-line float to int
2692       *
2693       * @access private
2694       * @return string
2695       */
2696      function safe_intval_inline()
2697      {
2698          switch (true) {
2699              case defined('PHP_INT_SIZE') && PHP_INT_SIZE == 8:
2700              case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
2701                  return '%s';
2702                  break;
2703              default:
2704                  $safeint = '(is_int($temp = %s) ? $temp : (fmod($temp, 0x80000000) & 0x7FFFFFFF) | ';
2705                  return $safeint . '((fmod(floor($temp / 0x80000000), 2) & 1) << 31))';
2706          }
2707      }
2708  }