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