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