[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/phpseclib/ -> Crypt_Base.php (source)

   1  <?php
   2  /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
   3  
   4  /**
   5   * Base Class for all Crypt_* cipher classes
   6   *
   7   * PHP versions 4 and 5
   8   *
   9   * Internally for phpseclib developers:
  10   *  If you plan to add a new cipher class, please note following rules:
  11   *
  12   *  - The new Crypt_* cipher class should extend Crypt_Base
  13   *
  14   *  - Following methods are then required to be overridden/overloaded:
  15   *
  16   *    - _encryptBlock()
  17   *
  18   *    - _decryptBlock()
  19   *
  20   *    - _setupKey()
  21   *
  22   *  - All other methods are optional to be overridden/overloaded
  23   *
  24   *  - Look at the source code of the current ciphers how they extend Crypt_Base
  25   *    and take one of them as a start up for the new cipher class.
  26   *
  27   *  - Please read all the other comments/notes/hints here also for each class var/method
  28   *
  29   * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
  30   * of this software and associated documentation files (the "Software"), to deal
  31   * in the Software without restriction, including without limitation the rights
  32   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  33   * copies of the Software, and to permit persons to whom the Software is
  34   * furnished to do so, subject to the following conditions:
  35   *
  36   * The above copyright notice and this permission notice shall be included in
  37   * all copies or substantial portions of the Software.
  38   *
  39   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  40   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  41   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  42   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  43   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  44   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  45   * THE SOFTWARE.
  46   *
  47   * @category   Crypt
  48   * @package    Crypt_Base
  49   * @author     Jim Wigginton <terrafrost@php.net>
  50   * @author     Hans-Juergen Petrich <petrich@tronic-media.com>
  51   * @copyright  MMVII Jim Wigginton
  52   * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
  53   * @version    1.0.1
  54   * @link       http://phpseclib.sourceforge.net
  55   */
  56  
  57  /**#@+
  58   * @access public
  59   * @see Crypt_Base::encrypt()
  60   * @see Crypt_Base::decrypt()
  61   */
  62  /**
  63   * Encrypt / decrypt using the Counter mode.
  64   *
  65   * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
  66   *
  67   * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
  68   */
  69  define('CRYPT_MODE_CTR', -1);
  70  /**
  71   * Encrypt / decrypt using the Electronic Code Book mode.
  72   *
  73   * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
  74   */
  75  define('CRYPT_MODE_ECB', 1);
  76  /**
  77   * Encrypt / decrypt using the Code Book Chaining mode.
  78   *
  79   * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
  80   */
  81  define('CRYPT_MODE_CBC', 2);
  82  /**
  83   * Encrypt / decrypt using the Cipher Feedback mode.
  84   *
  85   * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
  86   */
  87  define('CRYPT_MODE_CFB', 3);
  88  /**
  89   * Encrypt / decrypt using the Output Feedback mode.
  90   *
  91   * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
  92   */
  93  define('CRYPT_MODE_OFB', 4);
  94  /**
  95   * Encrypt / decrypt using streaming mode.
  96   *
  97   */
  98  define('CRYPT_MODE_STREAM', 5);
  99  /**#@-*/
 100  
 101  /**#@+
 102   * @access private
 103   * @see Crypt_Base::Crypt_Base()
 104   */
 105  /**
 106   * Base value for the internal implementation $engine switch
 107   */
 108  define('CRYPT_MODE_INTERNAL', 1);
 109  /**
 110   * Base value for the mcrypt implementation $engine switch
 111   */
 112  define('CRYPT_MODE_MCRYPT', 2);
 113  /**#@-*/
 114  
 115  /**
 116   * Base Class for all Crypt_* cipher classes
 117   *
 118   * @author  Jim Wigginton <terrafrost@php.net>
 119   * @author  Hans-Juergen Petrich <petrich@tronic-media.com>
 120   * @version 1.0.0
 121   * @access  public
 122   * @package Crypt_Base
 123   */
 124  class Crypt_Base {
 125      /**
 126       * The Encryption Mode
 127       *
 128       * @see Crypt_Base::Crypt_Base()
 129       * @var Integer
 130       * @access private
 131       */
 132      var $mode;
 133  
 134      /**
 135       * The Block Length of the block cipher
 136       *
 137       * @var Integer
 138       * @access private
 139       */
 140      var $block_size = 16;
 141  
 142      /**
 143       * The Key
 144       *
 145       * @see Crypt_Base::setKey()
 146       * @var String
 147       * @access private
 148       */
 149      var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
 150  
 151      /**
 152       * The Initialization Vector
 153       *
 154       * @see Crypt_Base::setIV()
 155       * @var String
 156       * @access private
 157       */
 158      var $iv;
 159  
 160      /**
 161       * A "sliding" Initialization Vector
 162       *
 163       * @see Crypt_Base::enableContinuousBuffer()
 164       * @see Crypt_Base::_clearBuffers()
 165       * @var String
 166       * @access private
 167       */
 168      var $encryptIV;
 169  
 170      /**
 171       * A "sliding" Initialization Vector
 172       *
 173       * @see Crypt_Base::enableContinuousBuffer()
 174       * @see Crypt_Base::_clearBuffers()
 175       * @var String
 176       * @access private
 177       */
 178      var $decryptIV;
 179  
 180      /**
 181       * Continuous Buffer status
 182       *
 183       * @see Crypt_Base::enableContinuousBuffer()
 184       * @var Boolean
 185       * @access private
 186       */
 187      var $continuousBuffer = false;
 188  
 189      /**
 190       * Encryption buffer for CTR, OFB and CFB modes
 191       *
 192       * @see Crypt_Base::encrypt()
 193       * @see Crypt_Base::_clearBuffers()
 194       * @var Array
 195       * @access private
 196       */
 197      var $enbuffer;
 198  
 199      /**
 200       * Decryption buffer for CTR, OFB and CFB modes
 201       *
 202       * @see Crypt_Base::decrypt()
 203       * @see Crypt_Base::_clearBuffers()
 204       * @var Array
 205       * @access private
 206       */
 207      var $debuffer;
 208  
 209      /**
 210       * mcrypt resource for encryption
 211       *
 212       * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
 213       * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
 214       *
 215       * @see Crypt_Base::encrypt()
 216       * @var Resource
 217       * @access private
 218       */
 219      var $enmcrypt;
 220  
 221      /**
 222       * mcrypt resource for decryption
 223       *
 224       * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
 225       * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
 226       *
 227       * @see Crypt_Base::decrypt()
 228       * @var Resource
 229       * @access private
 230       */
 231      var $demcrypt;
 232  
 233      /**
 234       * Does the enmcrypt resource need to be (re)initialized?
 235       *
 236       * @see Crypt_Twofish::setKey()
 237       * @see Crypt_Twofish::setIV()
 238       * @var Boolean
 239       * @access private
 240       */
 241      var $enchanged = true;
 242  
 243      /**
 244       * Does the demcrypt resource need to be (re)initialized?
 245       *
 246       * @see Crypt_Twofish::setKey()
 247       * @see Crypt_Twofish::setIV()
 248       * @var Boolean
 249       * @access private
 250       */
 251      var $dechanged = true;
 252  
 253      /**
 254       * mcrypt resource for CFB mode
 255       *
 256       * mcrypt's CFB mode, in (and only in) buffered context,
 257       * is broken, so phpseclib implements the CFB mode by it self,
 258       * even when the mcrypt php extension is available.
 259       *
 260       * In order to do the CFB-mode work (fast) phpseclib
 261       * use a separate ECB-mode mcrypt resource.
 262       *
 263       * @link http://phpseclib.sourceforge.net/cfb-demo.phps
 264       * @see Crypt_Base::encrypt()
 265       * @see Crypt_Base::decrypt()
 266       * @see Crypt_Base::_setupMcrypt()
 267       * @var Resource
 268       * @access private
 269       */
 270      var $ecb;
 271  
 272      /**
 273       * Optimizing value while CFB-encrypting
 274       *
 275       * Only relevant if $continuousBuffer enabled
 276       * and $engine == CRYPT_MODE_MCRYPT
 277       *
 278       * It's faster to re-init $enmcrypt if
 279       * $buffer bytes > $cfb_init_len than
 280       * using the $ecb resource furthermore.
 281       *
 282       * This value depends of the choosen cipher
 283       * and the time it would be needed for it's
 284       * initialization [by mcrypt_generic_init()]
 285       * which, typically, depends on the complexity
 286       * on its internaly Key-expanding algorithm.
 287       *
 288       * @see Crypt_Base::encrypt()
 289       * @var Integer
 290       * @access private
 291       */
 292      var $cfb_init_len = 600;
 293  
 294      /**
 295       * Does internal cipher state need to be (re)initialized?
 296       *
 297       * @see setKey()
 298       * @see setIV()
 299       * @see disableContinuousBuffer()
 300       * @var Boolean
 301       * @access private
 302       */
 303      var $changed = true;
 304  
 305      /**
 306       * Padding status
 307       *
 308       * @see Crypt_Base::enablePadding()
 309       * @var Boolean
 310       * @access private
 311       */
 312      var $padding = true;
 313  
 314      /**
 315       * Is the mode one that is paddable?
 316       *
 317       * @see Crypt_Base::Crypt_Base()
 318       * @var Boolean
 319       * @access private
 320       */
 321      var $paddable = false;
 322  
 323      /**
 324       * Holds which crypt engine internaly should be use,
 325       * which will be determined automatically on __construct()
 326       *
 327       * Currently available $engines are:
 328       * - CRYPT_MODE_MCRYPT   (fast, php-extension: mcrypt, extension_loaded('mcrypt') required)
 329       * - CRYPT_MODE_INTERNAL (slower, pure php-engine, no php-extension required)
 330       *
 331       * In the pipeline... maybe. But currently not available:
 332       * - CRYPT_MODE_OPENSSL  (very fast, php-extension: openssl, extension_loaded('openssl') required)
 333       *
 334       * If possible, CRYPT_MODE_MCRYPT will be used for each cipher.
 335       * Otherwise CRYPT_MODE_INTERNAL
 336       *
 337       * @see Crypt_Base::encrypt()
 338       * @see Crypt_Base::decrypt()
 339       * @var Integer
 340       * @access private
 341       */
 342      var $engine;
 343  
 344      /**
 345       * The mcrypt specific name of the cipher
 346       *
 347       * Only used if $engine == CRYPT_MODE_MCRYPT
 348       *
 349       * @link http://php.net/mcrypt_module_open
 350       * @link http://php.net/mcrypt_list_algorithms
 351       * @see Crypt_Base::_setupMcrypt()
 352       * @var String
 353       * @access private
 354       */
 355      var $cipher_name_mcrypt;
 356  
 357      /**
 358       * The default password key_size used by setPassword()
 359       *
 360       * @see Crypt_Base::setPassword()
 361       * @var Integer
 362       * @access private
 363       */
 364      var $password_key_size = 32;
 365  
 366      /**
 367       * The default salt used by setPassword()
 368       *
 369       * @see Crypt_Base::setPassword()
 370       * @var String
 371       * @access private
 372       */
 373      var $password_default_salt = 'phpseclib/salt';
 374  
 375      /**
 376       * The namespace used by the cipher for its constants.
 377       *
 378       * ie: AES.php is using CRYPT_AES_MODE_* for its constants
 379       *     so $const_namespace is AES
 380       *
 381       *     DES.php is using CRYPT_DES_MODE_* for its constants
 382       *     so $const_namespace is DES... and so on
 383       *
 384       * All CRYPT_<$const_namespace>_MODE_* are aliases of
 385       * the generic CRYPT_MODE_* constants, so both could be used
 386       * for each cipher.
 387       *
 388       * Example:
 389       * $aes = new Crypt_AES(CRYPT_AES_MODE_CFB); // $aes will operate in cfb mode
 390       * $aes = new Crypt_AES(CRYPT_MODE_CFB);     // identical
 391       *
 392       * @see Crypt_Base::Crypt_Base()
 393       * @var String
 394       * @access private
 395       */
 396      var $const_namespace;
 397  
 398      /**
 399       * The name of the performance-optimized callback function
 400       *
 401       * Used by encrypt() / decrypt()
 402       * only if $engine == CRYPT_MODE_INTERNAL
 403       *
 404       * @see Crypt_Base::encrypt()
 405       * @see Crypt_Base::decrypt()
 406       * @see Crypt_Base::_setupInlineCrypt()
 407       * @see Crypt_Base::$use_inline_crypt
 408       * @var Callback
 409       * @access private
 410       */
 411      var $inline_crypt;
 412  
 413      /**
 414       * Holds whether performance-optimized $inline_crypt() can/should be used.
 415       *
 416       * @see Crypt_Base::encrypt()
 417       * @see Crypt_Base::decrypt()
 418       * @see Crypt_Base::inline_crypt
 419       * @var mixed
 420       * @access private
 421       */
 422      var $use_inline_crypt;
 423  
 424      /**
 425       * Default Constructor.
 426       *
 427       * Determines whether or not the mcrypt extension should be used.
 428       *
 429       * $mode could be:
 430       *
 431       * - CRYPT_MODE_ECB
 432       *
 433       * - CRYPT_MODE_CBC
 434       *
 435       * - CRYPT_MODE_CTR
 436       *
 437       * - CRYPT_MODE_CFB
 438       *
 439       * - CRYPT_MODE_OFB
 440       *
 441       * (or the alias constants of the choosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...)
 442       *
 443       * If not explictly set, CRYPT_MODE_CBC will be used.
 444       *
 445       * @param optional Integer $mode
 446       * @access public
 447       */
 448      function __construct($mode = CRYPT_MODE_CBC)
 449      {
 450          $const_crypt_mode = 'CRYPT_' . $this->const_namespace . '_MODE';
 451  
 452          // Determining the availibility of mcrypt support for the cipher
 453          if (!defined($const_crypt_mode)) {
 454              switch (true) {
 455                  case extension_loaded('mcrypt') && in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms()):
 456                      define($const_crypt_mode, CRYPT_MODE_MCRYPT);
 457                      break;
 458                  default:
 459                      define($const_crypt_mode, CRYPT_MODE_INTERNAL);
 460              }
 461          }
 462  
 463          // Determining which internal $engine should be used.
 464          // The fastes possible first.
 465          switch (true) {
 466              case empty($this->cipher_name_mcrypt): // The cipher module has no mcrypt-engine support at all so we force CRYPT_MODE_INTERNAL
 467                  $this->engine = CRYPT_MODE_INTERNAL;
 468                  break;
 469              case constant($const_crypt_mode) == CRYPT_MODE_MCRYPT:
 470                  $this->engine = CRYPT_MODE_MCRYPT;
 471                  break;
 472              default:
 473                  $this->engine = CRYPT_MODE_INTERNAL;
 474          }
 475  
 476          // $mode dependent settings
 477          switch ($mode) {
 478              case CRYPT_MODE_ECB:
 479                  $this->paddable = true;
 480                  $this->mode = $mode;
 481                  break;
 482              case CRYPT_MODE_CTR:
 483              case CRYPT_MODE_CFB:
 484              case CRYPT_MODE_OFB:
 485              case CRYPT_MODE_STREAM:
 486                  $this->mode = $mode;
 487                  break;
 488              case CRYPT_MODE_CBC:
 489              default:
 490                  $this->paddable = true;
 491                  $this->mode = CRYPT_MODE_CBC;
 492          }
 493  
 494          // Determining whether inline crypting can be used by the cipher
 495          if ($this->use_inline_crypt !== false && function_exists('create_function')) {
 496              $this->use_inline_crypt = true;
 497          }
 498      }
 499  
 500      /**
 501       * Sets the initialization vector. (optional)
 502       *
 503       * SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used.  If not explictly set, it'll be assumed
 504       * to be all zero's.
 505       *
 506       * Note: Could, but not must, extend by the child Crypt_* class
 507       *
 508       * @access public
 509       * @param String $iv
 510       */
 511      function setIV($iv)
 512      {
 513          if ($this->mode == CRYPT_MODE_ECB) {
 514              return;
 515          }
 516  
 517          $this->iv = $iv;
 518          $this->changed = true;
 519      }
 520  
 521      /**
 522       * Sets the key.
 523       *
 524       * The min/max length(s) of the key depends on the cipher which is used.
 525       * If the key not fits the length(s) of the cipher it will paded with null bytes
 526       * up to the closest valid key length.  If the key is more than max length,
 527       * we trim the excess bits.
 528       *
 529       * If the key is not explicitly set, it'll be assumed to be all null bytes.
 530       *
 531       * Note: Could, but not must, extend by the child Crypt_* class
 532       *
 533       * @access public
 534       * @param String $key
 535       */
 536      function setKey($key)
 537      {
 538          $this->key = $key;
 539          $this->changed = true;
 540      }
 541  
 542      /**
 543       * Sets the password.
 544       *
 545       * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
 546       *     {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
 547       *         $hash, $salt, $count, $dkLen
 548       *
 549       *         Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
 550       *
 551       * Note: Could, but not must, extend by the child Crypt_* class
 552       *
 553       * @see Crypt/Hash.php
 554       * @param String $password
 555       * @param optional String $method
 556       * @access public
 557       */
 558      function setPassword($password, $method = 'pbkdf2')
 559      {
 560          $key = '';
 561  
 562          switch ($method) {
 563              default: // 'pbkdf2'
 564                  $func_args = func_get_args();
 565  
 566                  // Hash function
 567                  $hash = isset($func_args[2]) ? $func_args[2] : 'sha1';
 568  
 569                  // WPA and WPA2 use the SSID as the salt
 570                  $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;
 571  
 572                  // RFC2898#section-4.2 uses 1,000 iterations by default
 573                  // WPA and WPA2 use 4,096.
 574                  $count = isset($func_args[4]) ? $func_args[4] : 1000;
 575  
 576                  // Keylength
 577                  $dkLen = isset($func_args[5]) ? $func_args[5] : $this->password_key_size;
 578  
 579                  // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
 580                  switch (true) {
 581                      case !function_exists('hash_pbkdf2'):
 582                      case !function_exists('hash_algos'):
 583                      case !in_array($hash, hash_algos()):
 584                          if (!class_exists('Crypt_Hash')) {
 585                              require_once('Crypt/Hash.php');
 586                          }
 587                          $i = 1;
 588                          while (strlen($key) < $dkLen) {
 589                              $hmac = new Crypt_Hash();
 590                              $hmac->setHash($hash);
 591                              $hmac->setKey($password);
 592                              $f = $u = $hmac->hash($salt . pack('N', $i++));
 593                              for ($j = 2; $j <= $count; ++$j) {
 594                                  $u = $hmac->hash($u);
 595                                  $f^= $u;
 596                              }
 597                              $key.= $f;
 598                          }
 599                          $key = substr($key, 0, $dkLen);
 600                          break;
 601                      default:
 602                          $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
 603                  }
 604          }
 605  
 606          $this->setKey($key);
 607      }
 608  
 609      /**
 610       * Encrypts a message.
 611       *
 612       * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher
 613       * implementations may or may not pad in the same manner.  Other common approaches to padding and the reasons why it's
 614       * necessary are discussed in the following
 615       * URL:
 616       *
 617       * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
 618       *
 619       * An alternative to padding is to, separately, send the length of the file.  This is what SSH, in fact, does.
 620       * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that
 621       * length.
 622       *
 623       * Note: Could, but not must, extend by the child Crypt_* class
 624       *
 625       * @see Crypt_Base::decrypt()
 626       * @access public
 627       * @param String $plaintext
 628       * @return String $cipertext
 629       */
 630      function encrypt($plaintext)
 631      {
 632          if ($this->engine == CRYPT_MODE_MCRYPT) {
 633              if ($this->changed) {
 634                  $this->_setupMcrypt();
 635                  $this->changed = false;
 636              }
 637              if ($this->enchanged) {
 638                  mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
 639                  $this->enchanged = false;
 640              }
 641  
 642              // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
 643              // using mcrypt's default handing of CFB the above would output two different things.  using phpseclib's
 644              // rewritten CFB implementation the above outputs the same thing twice.
 645              if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) {
 646                  $block_size = $this->block_size;
 647                  $iv = &$this->encryptIV;
 648                  $pos = &$this->enbuffer['pos'];
 649                  $len = strlen($plaintext);
 650                  $ciphertext = '';
 651                  $i = 0;
 652                  if ($pos) {
 653                      $orig_pos = $pos;
 654                      $max = $block_size - $pos;
 655                      if ($len >= $max) {
 656                          $i = $max;
 657                          $len-= $max;
 658                          $pos = 0;
 659                      } else {
 660                          $i = $len;
 661                          $pos+= $len;
 662                          $len = 0;
 663                      }
 664                      $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
 665                      $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
 666                      $this->enbuffer['enmcrypt_init'] = true;
 667                  }
 668                  if ($len >= $block_size) {
 669                      if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) {
 670                          if ($this->enbuffer['enmcrypt_init'] === true) {
 671                              mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
 672                              $this->enbuffer['enmcrypt_init'] = false;
 673                          }
 674                          $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
 675                          $iv = substr($ciphertext, -$block_size);
 676                          $len%= $block_size;
 677                      } else {
 678                          while ($len >= $block_size) {
 679                              $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
 680                              $ciphertext.= $iv;
 681                              $len-= $block_size;
 682                              $i+= $block_size;
 683                          }
 684                      }
 685                  }
 686  
 687                  if ($len) {
 688                      $iv = mcrypt_generic($this->ecb, $iv);
 689                      $block = $iv ^ substr($plaintext, -$len);
 690                      $iv = substr_replace($iv, $block, 0, $len);
 691                      $ciphertext.= $block;
 692                      $pos = $len;
 693                  }
 694  
 695                  return $ciphertext;
 696              }
 697  
 698              if ($this->paddable) {
 699                  $plaintext = $this->_pad($plaintext);
 700              }
 701  
 702              $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
 703  
 704              if (!$this->continuousBuffer) {
 705                  mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
 706              }
 707  
 708              return $ciphertext;
 709          }
 710  
 711          if ($this->changed) {
 712              $this->_setup();
 713              $this->changed = false;
 714          }
 715          if ($this->use_inline_crypt) {
 716              $inline = $this->inline_crypt;
 717              return $inline('encrypt', $this, $plaintext);
 718          }
 719          if ($this->paddable) {
 720              $plaintext = $this->_pad($plaintext);
 721          }
 722  
 723          $buffer = &$this->enbuffer;
 724          $block_size = $this->block_size;
 725          $ciphertext = '';
 726          switch ($this->mode) {
 727              case CRYPT_MODE_ECB:
 728                  for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 729                      $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
 730                  }
 731                  break;
 732              case CRYPT_MODE_CBC:
 733                  $xor = $this->encryptIV;
 734                  for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 735                      $block = substr($plaintext, $i, $block_size);
 736                      $block = $this->_encryptBlock($block ^ $xor);
 737                      $xor = $block;
 738                      $ciphertext.= $block;
 739                  }
 740                  if ($this->continuousBuffer) {
 741                      $this->encryptIV = $xor;
 742                  }
 743                  break;
 744              case CRYPT_MODE_CTR:
 745                  $xor = $this->encryptIV;
 746                  if (strlen($buffer['encrypted'])) {
 747                      for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 748                          $block = substr($plaintext, $i, $block_size);
 749                          if (strlen($block) > strlen($buffer['encrypted'])) {
 750                              $buffer['encrypted'].= $this->_encryptBlock($this->_generateXor($xor, $block_size));
 751                          }
 752                          $key = $this->_stringShift($buffer['encrypted'], $block_size);
 753                          $ciphertext.= $block ^ $key;
 754                      }
 755                  } else {
 756                      for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 757                          $block = substr($plaintext, $i, $block_size);
 758                          $key = $this->_encryptBlock($this->_generateXor($xor, $block_size));
 759                          $ciphertext.= $block ^ $key;
 760                      }
 761                  }
 762                  if ($this->continuousBuffer) {
 763                      $this->encryptIV = $xor;
 764                      if ($start = strlen($plaintext) % $block_size) {
 765                          $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
 766                      }
 767                  }
 768                  break;
 769              case CRYPT_MODE_CFB:
 770                  // cfb loosely routines inspired by openssl's:
 771                  // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
 772                  if ($this->continuousBuffer) {
 773                      $iv = &$this->encryptIV;
 774                      $pos = &$buffer['pos'];
 775                  } else {
 776                      $iv = $this->encryptIV;
 777                      $pos = 0;
 778                  }
 779                  $len = strlen($plaintext);
 780                  $i = 0;
 781                  if ($pos) {
 782                      $orig_pos = $pos;
 783                      $max = $block_size - $pos;
 784                      if ($len >= $max) {
 785                          $i = $max;
 786                          $len-= $max;
 787                          $pos = 0;
 788                      } else {
 789                          $i = $len;
 790                          $pos+= $len;
 791                          $len = 0;
 792                      }
 793                      // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
 794                      $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
 795                      $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
 796                  }
 797                  while ($len >= $block_size) {
 798                      $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
 799                      $ciphertext.= $iv;
 800                      $len-= $block_size;
 801                      $i+= $block_size;
 802                  }
 803                  if ($len) {
 804                      $iv = $this->_encryptBlock($iv);
 805                      $block = $iv ^ substr($plaintext, $i);
 806                      $iv = substr_replace($iv, $block, 0, $len);
 807                      $ciphertext.= $block;
 808                      $pos = $len;
 809                  }
 810                  break;
 811              case CRYPT_MODE_OFB:
 812                  $xor = $this->encryptIV;
 813                  if (strlen($buffer['xor'])) {
 814                      for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 815                          $block = substr($plaintext, $i, $block_size);
 816                          if (strlen($block) > strlen($buffer['xor'])) {
 817                              $xor = $this->_encryptBlock($xor);
 818                              $buffer['xor'].= $xor;
 819                          }
 820                          $key = $this->_stringShift($buffer['xor'], $block_size);
 821                          $ciphertext.= $block ^ $key;
 822                      }
 823                  } else {
 824                      for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 825                          $xor = $this->_encryptBlock($xor);
 826                          $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
 827                      }
 828                      $key = $xor;
 829                  }
 830                  if ($this->continuousBuffer) {
 831                      $this->encryptIV = $xor;
 832                      if ($start = strlen($plaintext) % $block_size) {
 833                           $buffer['xor'] = substr($key, $start) . $buffer['xor'];
 834                      }
 835                  }
 836                  break;
 837              case CRYPT_MODE_STREAM:
 838                  $ciphertext = $this->_encryptBlock($plaintext);
 839                  break;
 840          }
 841  
 842          return $ciphertext;
 843      }
 844  
 845      /**
 846       * Decrypts a message.
 847       *
 848       * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
 849       * it is.
 850       *
 851       * Note: Could, but not must, extend by the child Crypt_* class
 852       *
 853       * @see Crypt_Base::encrypt()
 854       * @access public
 855       * @param String $ciphertext
 856       * @return String $plaintext
 857       */
 858      function decrypt($ciphertext)
 859      {
 860          if ($this->engine == CRYPT_MODE_MCRYPT) {
 861              $block_size = $this->block_size;
 862              if ($this->changed) {
 863                  $this->_setupMcrypt();
 864                  $this->changed = false;
 865              }
 866              if ($this->dechanged) {
 867                  mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
 868                  $this->dechanged = false;
 869              }
 870  
 871              if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) {
 872                  $iv = &$this->decryptIV;
 873                  $pos = &$this->debuffer['pos'];
 874                  $len = strlen($ciphertext);
 875                  $plaintext = '';
 876                  $i = 0;
 877                  if ($pos) {
 878                      $orig_pos = $pos;
 879                      $max = $block_size - $pos;
 880                      if ($len >= $max) {
 881                          $i = $max;
 882                          $len-= $max;
 883                          $pos = 0;
 884                      } else {
 885                          $i = $len;
 886                          $pos+= $len;
 887                          $len = 0;
 888                      }
 889                      // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
 890                      $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
 891                      $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
 892                  }
 893                  if ($len >= $block_size) {
 894                      $cb = substr($ciphertext, $i, $len - $len % $block_size);
 895                      $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
 896                      $iv = substr($cb, -$block_size);
 897                      $len%= $block_size;
 898                  }
 899                  if ($len) {
 900                      $iv = mcrypt_generic($this->ecb, $iv);
 901                      $plaintext.= $iv ^ substr($ciphertext, -$len);
 902                      $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
 903                      $pos = $len;
 904                  }
 905  
 906                  return $plaintext;
 907              }
 908  
 909              if ($this->paddable) {
 910                  // we pad with chr(0) since that's what mcrypt_generic does.  to quote from {@link http://php.net/function.mcrypt-generic}:
 911                  // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
 912                  $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0));
 913              }
 914  
 915              $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
 916  
 917              if (!$this->continuousBuffer) {
 918                  mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
 919              }
 920  
 921              return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
 922          }
 923  
 924          if ($this->changed) {
 925              $this->_setup();
 926              $this->changed = false;
 927          }
 928          if ($this->use_inline_crypt) {
 929              $inline = $this->inline_crypt;
 930              return $inline('decrypt', $this, $ciphertext);
 931          }
 932  
 933          $block_size = $this->block_size;
 934          if ($this->paddable) {
 935              // we pad with chr(0) since that's what mcrypt_generic does [...]
 936              $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0));
 937          }
 938  
 939          $buffer = &$this->debuffer;
 940          $plaintext = '';
 941          switch ($this->mode) {
 942              case CRYPT_MODE_ECB:
 943                  for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
 944                      $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
 945                  }
 946                  break;
 947              case CRYPT_MODE_CBC:
 948                  $xor = $this->decryptIV;
 949                  for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
 950                      $block = substr($ciphertext, $i, $block_size);
 951                      $plaintext.= $this->_decryptBlock($block) ^ $xor;
 952                      $xor = $block;
 953                  }
 954                  if ($this->continuousBuffer) {
 955                      $this->decryptIV = $xor;
 956                  }
 957                  break;
 958              case CRYPT_MODE_CTR:
 959                  $xor = $this->decryptIV;
 960                  if (strlen($buffer['ciphertext'])) {
 961                      for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
 962                          $block = substr($ciphertext, $i, $block_size);
 963                          if (strlen($block) > strlen($buffer['ciphertext'])) {
 964                              $buffer['ciphertext'].= $this->_encryptBlock($this->_generateXor($xor, $block_size));
 965                          }
 966                          $key = $this->_stringShift($buffer['ciphertext'], $block_size);
 967                          $plaintext.= $block ^ $key;
 968                      }
 969                  } else {
 970                      for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
 971                          $block = substr($ciphertext, $i, $block_size);
 972                          $key = $this->_encryptBlock($this->_generateXor($xor, $block_size));
 973                          $plaintext.= $block ^ $key;
 974                      }
 975                  }
 976                  if ($this->continuousBuffer) {
 977                      $this->decryptIV = $xor;
 978                      if ($start = strlen($ciphertext) % $block_size) {
 979                          $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
 980                      }
 981                  }
 982                  break;
 983              case CRYPT_MODE_CFB:
 984                  if ($this->continuousBuffer) {
 985                      $iv = &$this->decryptIV;
 986                      $pos = &$buffer['pos'];
 987                  } else {
 988                      $iv = $this->decryptIV;
 989                      $pos = 0;
 990                  }
 991                  $len = strlen($ciphertext);
 992                  $i = 0;
 993                  if ($pos) {
 994                      $orig_pos = $pos;
 995                      $max = $block_size - $pos;
 996                      if ($len >= $max) {
 997                          $i = $max;
 998                          $len-= $max;
 999                          $pos = 0;
1000                      } else {
1001                          $i = $len;
1002                          $pos+= $len;
1003                          $len = 0;
1004                      }
1005                      // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1006                      $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1007                      $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1008                  }
1009                  while ($len >= $block_size) {
1010                      $iv = $this->_encryptBlock($iv);
1011                      $cb = substr($ciphertext, $i, $block_size);
1012                      $plaintext.= $iv ^ $cb;
1013                      $iv = $cb;
1014                      $len-= $block_size;
1015                      $i+= $block_size;
1016                  }
1017                  if ($len) {
1018                      $iv = $this->_encryptBlock($iv);
1019                      $plaintext.= $iv ^ substr($ciphertext, $i);
1020                      $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
1021                      $pos = $len;
1022                  }
1023                  break;
1024              case CRYPT_MODE_OFB:
1025                  $xor = $this->decryptIV;
1026                  if (strlen($buffer['xor'])) {
1027                      for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1028                          $block = substr($ciphertext, $i, $block_size);
1029                          if (strlen($block) > strlen($buffer['xor'])) {
1030                              $xor = $this->_encryptBlock($xor);
1031                              $buffer['xor'].= $xor;
1032                          }
1033                          $key = $this->_stringShift($buffer['xor'], $block_size);
1034                          $plaintext.= $block ^ $key;
1035                      }
1036                  } else {
1037                      for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1038                          $xor = $this->_encryptBlock($xor);
1039                          $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
1040                      }
1041                      $key = $xor;
1042                  }
1043                  if ($this->continuousBuffer) {
1044                      $this->decryptIV = $xor;
1045                      if ($start = strlen($ciphertext) % $block_size) {
1046                           $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1047                      }
1048                  }
1049                  break;
1050              case CRYPT_MODE_STREAM:
1051                  $plaintext = $this->_decryptBlock($ciphertext);
1052                  break;
1053          }
1054          return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1055      }
1056  
1057      /**
1058       * Pad "packets".
1059       *
1060       * Block ciphers working by encrypting between their specified [$this->]block_size at a time
1061       * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
1062       * pad the input so that it is of the proper length.
1063       *
1064       * Padding is enabled by default.  Sometimes, however, it is undesirable to pad strings.  Such is the case in SSH,
1065       * where "packets" are padded with random bytes before being encrypted.  Unpad these packets and you risk stripping
1066       * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1067       * transmitted separately)
1068       *
1069       * @see Crypt_Base::disablePadding()
1070       * @access public
1071       */
1072      function enablePadding()
1073      {
1074          $this->padding = true;
1075      }
1076  
1077      /**
1078       * Do not pad packets.
1079       *
1080       * @see Crypt_Base::enablePadding()
1081       * @access public
1082       */
1083      function disablePadding()
1084      {
1085          $this->padding = false;
1086      }
1087  
1088      /**
1089       * Treat consecutive "packets" as if they are a continuous buffer.
1090       *
1091       * Say you have a 32-byte plaintext $plaintext.  Using the default behavior, the two following code snippets
1092       * will yield different outputs:
1093       *
1094       * <code>
1095       *    echo $rijndael->encrypt(substr($plaintext,  0, 16));
1096       *    echo $rijndael->encrypt(substr($plaintext, 16, 16));
1097       * </code>
1098       * <code>
1099       *    echo $rijndael->encrypt($plaintext);
1100       * </code>
1101       *
1102       * The solution is to enable the continuous buffer.  Although this will resolve the above discrepancy, it creates
1103       * another, as demonstrated with the following:
1104       *
1105       * <code>
1106       *    $rijndael->encrypt(substr($plaintext, 0, 16));
1107       *    echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1108       * </code>
1109       * <code>
1110       *    echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1111       * </code>
1112       *
1113       * With the continuous buffer disabled, these would yield the same output.  With it enabled, they yield different
1114       * outputs.  The reason is due to the fact that the initialization vector's change after every encryption /
1115       * decryption round when the continuous buffer is enabled.  When it's disabled, they remain constant.
1116       *
1117       * Put another way, when the continuous buffer is enabled, the state of the Crypt_*() object changes after each
1118       * encryption / decryption round, whereas otherwise, it'd remain constant.  For this reason, it's recommended that
1119       * continuous buffers not be used.  They do offer better security and are, in fact, sometimes required (SSH uses them),
1120       * however, they are also less intuitive and more likely to cause you problems.
1121       *
1122       * Note: Could, but not must, extend by the child Crypt_* class
1123       *
1124       * @see Crypt_Base::disableContinuousBuffer()
1125       * @access public
1126       */
1127      function enableContinuousBuffer()
1128      {
1129          if ($this->mode == CRYPT_MODE_ECB) {
1130              return;
1131          }
1132  
1133          $this->continuousBuffer = true;
1134      }
1135  
1136      /**
1137       * Treat consecutive packets as if they are a discontinuous buffer.
1138       *
1139       * The default behavior.
1140       *
1141       * Note: Could, but not must, extend by the child Crypt_* class
1142       *
1143       * @see Crypt_Base::enableContinuousBuffer()
1144       * @access public
1145       */
1146      function disableContinuousBuffer()
1147      {
1148          if ($this->mode == CRYPT_MODE_ECB) {
1149              return;
1150          }
1151          if (!$this->continuousBuffer) {
1152              return;
1153          }
1154  
1155          $this->continuousBuffer = false;
1156          $this->changed = true;
1157      }
1158  
1159      /**
1160       * Encrypts a block
1161       *
1162       * Note: Must extend by the child Crypt_* class
1163       *
1164       * @access private
1165       * @param String $in
1166       * @return String
1167       */
1168      function _encryptBlock($in)
1169      {
1170          user_error((version_compare(PHP_VERSION, '5.0.0', '>=')  ? __METHOD__ : __FUNCTION__)  . '() must extend by class ' . get_class($this), E_USER_ERROR);
1171      }
1172  
1173      /**
1174       * Decrypts a block
1175       *
1176       * Note: Must extend by the child Crypt_* class
1177       *
1178       * @access private
1179       * @param String $in
1180       * @return String
1181       */
1182      function _decryptBlock($in)
1183      {
1184          user_error((version_compare(PHP_VERSION, '5.0.0', '>=')  ? __METHOD__ : __FUNCTION__)  . '() must extend by class ' . get_class($this), E_USER_ERROR);
1185      }
1186  
1187      /**
1188       * Setup the key (expansion)
1189       *
1190       * Only used if $engine == CRYPT_MODE_INTERNAL
1191       *
1192       * Note: Must extend by the child Crypt_* class
1193       *
1194       * @see Crypt_Base::_setup()
1195       * @access private
1196       */
1197      function _setupKey()
1198      {
1199          user_error((version_compare(PHP_VERSION, '5.0.0', '>=')  ? __METHOD__ : __FUNCTION__)  . '() must extend by class ' . get_class($this), E_USER_ERROR);
1200      }
1201  
1202      /**
1203       * Setup the CRYPT_MODE_INTERNAL $engine
1204       *
1205       * (re)init, if necessary, the internal cipher $engine and flush all $buffers
1206       * Used (only) if $engine == CRYPT_MODE_INTERNAL
1207       *
1208       * _setup() will be called each time if $changed === true
1209       * typically this happens when using one or more of following public methods:
1210       *
1211       * - setKey()
1212       *
1213       * - setIV()
1214       *
1215       * - disableContinuousBuffer()
1216       *
1217       * - First run of encrypt() / decrypt() with no init-settings
1218       *
1219       * Internally: _setup() is called always before(!) en/decryption.
1220       *
1221       * Note: Could, but not must, extend by the child Crypt_* class
1222       *
1223       * @see setKey()
1224       * @see setIV()
1225       * @see disableContinuousBuffer()
1226       * @access private
1227       */
1228      function _setup()
1229      {
1230          $this->_clearBuffers();
1231          $this->_setupKey();
1232  
1233          if ($this->use_inline_crypt) {
1234              $this->_setupInlineCrypt();
1235          }
1236      }
1237  
1238      /**
1239       * Setup the CRYPT_MODE_MCRYPT $engine
1240       *
1241       * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers
1242       * Used (only) if $engine = CRYPT_MODE_MCRYPT
1243       *
1244       * _setupMcrypt() will be called each time if $changed === true
1245       * typically this happens when using one or more of following public methods:
1246       *
1247       * - setKey()
1248       *
1249       * - setIV()
1250       *
1251       * - disableContinuousBuffer()
1252       *
1253       * - First run of encrypt() / decrypt()
1254       *
1255       *
1256       * Note: Could, but not must, extend by the child Crypt_* class
1257       *
1258       * @see setKey()
1259       * @see setIV()
1260       * @see disableContinuousBuffer()
1261       * @access private
1262       */
1263      function _setupMcrypt()
1264      {
1265          $this->_clearBuffers();
1266          $this->enchanged = $this->dechanged = true;
1267  
1268          if (!isset($this->enmcrypt)) {
1269              static $mcrypt_modes = array(
1270                  CRYPT_MODE_CTR    => 'ctr',
1271                  CRYPT_MODE_ECB    => MCRYPT_MODE_ECB,
1272                  CRYPT_MODE_CBC    => MCRYPT_MODE_CBC,
1273                  CRYPT_MODE_CFB    => 'ncfb',
1274                  CRYPT_MODE_OFB    => MCRYPT_MODE_NOFB,
1275                  CRYPT_MODE_STREAM => MCRYPT_MODE_STREAM,
1276              );
1277  
1278              $this->demcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
1279              $this->enmcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
1280  
1281              // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer()
1282              // to workaround mcrypt's broken ncfb implementation in buffered mode
1283              // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
1284              if ($this->mode == CRYPT_MODE_CFB) {
1285                  $this->ecb = mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
1286              }
1287  
1288          } // else should mcrypt_generic_deinit be called?
1289  
1290          if ($this->mode == CRYPT_MODE_CFB) {
1291              mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
1292          }
1293      }
1294  
1295      /**
1296       * Pads a string
1297       *
1298       * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
1299       * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to
1300       * chr($this->block_size - (strlen($text) % $this->block_size)
1301       *
1302       * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1303       * and padding will, hence forth, be enabled.
1304       *
1305       * @see Crypt_Base::_unpad()
1306       * @param String $text
1307       * @access private
1308       * @return String
1309       */
1310      function _pad($text)
1311      {
1312          $length = strlen($text);
1313  
1314          if (!$this->padding) {
1315              if ($length % $this->block_size == 0) {
1316                  return $text;
1317              } else {
1318                  user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
1319                  $this->padding = true;
1320              }
1321          }
1322  
1323          $pad = $this->block_size - ($length % $this->block_size);
1324  
1325          return str_pad($text, $length + $pad, chr($pad));
1326      }
1327  
1328      /**
1329       * Unpads a string.
1330       *
1331       * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1332       * and false will be returned.
1333       *
1334       * @see Crypt_Base::_pad()
1335       * @param String $text
1336       * @access private
1337       * @return String
1338       */
1339      function _unpad($text)
1340      {
1341          if (!$this->padding) {
1342              return $text;
1343          }
1344  
1345          $length = ord($text[strlen($text) - 1]);
1346  
1347          if (!$length || $length > $this->block_size) {
1348              return false;
1349          }
1350  
1351          return substr($text, 0, -$length);
1352      }
1353  
1354      /**
1355       * Clears internal buffers
1356       *
1357       * Clearing/resetting the internal buffers is done everytime
1358       * after disableContinuousBuffer() or on cipher $engine (re)init
1359       * ie after setKey() or setIV()
1360       *
1361       * Note: Could, but not must, extend by the child Crypt_* class
1362       *
1363       * @access public
1364       */
1365      function _clearBuffers()
1366      {
1367          $this->enbuffer = array('encrypted'  => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
1368          $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
1369  
1370          // mcrypt's handling of invalid's $iv:
1371          // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size);
1372          $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");
1373      }
1374  
1375      /**
1376       * String Shift
1377       *
1378       * Inspired by array_shift
1379       *
1380       * @param String $string
1381       * @param optional Integer $index
1382       * @access private
1383       * @return String
1384       */
1385      function _stringShift(&$string, $index = 1)
1386      {
1387          $substr = substr($string, 0, $index);
1388          $string = substr($string, $index);
1389          return $substr;
1390      }
1391  
1392      /**
1393       * Generate CTR XOR encryption key
1394       *
1395       * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
1396       * plaintext / ciphertext in CTR mode.
1397       *
1398       * @see Crypt_Base::decrypt()
1399       * @see Crypt_Base::encrypt()
1400       * @param String $iv
1401       * @param Integer $length
1402       * @access private
1403       * @return String $xor
1404       */
1405      function _generateXor(&$iv, $length)
1406      {
1407          $xor = '';
1408          $block_size = $this->block_size;
1409          $num_blocks = floor(($length + ($block_size - 1)) / $block_size);
1410          for ($i = 0; $i < $num_blocks; $i++) {
1411              $xor.= $iv;
1412              for ($j = 4; $j <= $block_size; $j+= 4) {
1413                  $temp = substr($iv, -$j, 4);
1414                  switch ($temp) {
1415                      case "\xFF\xFF\xFF\xFF":
1416                          $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
1417                          break;
1418                      case "\x7F\xFF\xFF\xFF":
1419                          $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
1420                          break 2;
1421                      default:
1422                          extract(unpack('Ncount', $temp));
1423                          $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
1424                          break 2;
1425                  }
1426              }
1427          }
1428  
1429          return $xor;
1430      }
1431  
1432      /**
1433       * Setup the performance-optimized function for de/encrypt()
1434       *
1435       * Stores the created (or existing) callback function-name
1436       * in $this->inline_crypt
1437       *
1438       * Internally for phpseclib developers:
1439       *
1440       *     _setupInlineCrypt() would be called only if:
1441       *
1442       *     - $engine == CRYPT_MODE_INTERNAL and
1443       *
1444       *     - $use_inline_crypt === true
1445       *
1446       *     - each time on _setup(), after(!) _setupKey()
1447       *
1448       *
1449       *     This ensures that _setupInlineCrypt() has allways a
1450       *     full ready2go initializated internal cipher $engine state
1451       *     where, for example, the keys allready expanded,
1452       *     keys/block_size calculated and such.
1453       *
1454       *     It is, each time if called, the responsibility of _setupInlineCrypt():
1455       *
1456       *     - to set $this->inline_crypt to a valid and fully working callback function
1457       *       as a (faster) replacement for encrypt() / decrypt()
1458       *
1459       *     - NOT to create unlimited callback functions (for memory reasons!)
1460       *       no matter how often _setupInlineCrypt() would be called. At some
1461       *       point of amount they must be generic re-useable.
1462       *
1463       *     - the code of _setupInlineCrypt() it self,
1464       *       and the generated callback code,
1465       *       must be, in following order:
1466       *       - 100% safe
1467       *       - 100% compatible to encrypt()/decrypt()
1468       *       - using only php5+ features/lang-constructs/php-extensions if
1469       *         compatibility (down to php4) or fallback is provided
1470       *       - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-)
1471       *       - >= 10% faster than encrypt()/decrypt() [which is, by the way,
1472       *         the reason for the existence of _setupInlineCrypt() :-)]
1473       *       - memory-nice
1474       *       - short (as good as possible)
1475       *
1476       * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code.
1477       *       - In case of using inline crypting, _setupInlineCrypt() must extend by the child Crypt_* class.
1478       *       - The following variable names are reserved:
1479       *         - $_*  (all variable names prefixed with an underscore)
1480       *         - $self (object reference to it self. Do not use $this, but $self instead)
1481       *         - $in (the content of $in has to en/decrypt by the generated code)
1482       *       - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only
1483       *
1484       *
1485       * @see Crypt_Base::_setup()
1486       * @see Crypt_Base::_createInlineCryptFunction()
1487       * @see Crypt_Base::encrypt()
1488       * @see Crypt_Base::decrypt()
1489       * @access private
1490       */
1491      function _setupInlineCrypt()
1492      {
1493          // If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt()
1494  
1495          // If, for any reason, an extending Crypt_Base() Crypt_* class
1496          // not using inline crypting then it must be ensured that: $this->use_inline_crypt = false
1497          // ie in the class var declaration of $use_inline_crypt in general for the Crypt_* class,
1498          // in the constructor at object instance-time
1499          // or, if it's runtime-specific, at runtime
1500  
1501          $this->use_inline_crypt = false;
1502      }
1503  
1504      /**
1505       * Creates the performance-optimized function for en/decrypt()
1506       *
1507       * Internally for phpseclib developers:
1508       *
1509       *    _createInlineCryptFunction():
1510       *
1511       *    - merge the $cipher_code [setup'ed by _setupInlineCrypt()]
1512       *      with the current [$this->]mode of operation code
1513       *
1514       *    - create the $inline function, which called by encrypt() / decrypt()
1515       *      as its replacement to speed up the en/decryption operations.
1516       *
1517       *    - return the name of the created $inline callback function
1518       *
1519       *    - used to speed up en/decryption
1520       *
1521       *
1522       *
1523       *    The main reason why can speed up things [up to 50%] this way are:
1524       *
1525       *    - using variables more effective then regular.
1526       *      (ie no use of expensive arrays but integers $k_0, $k_1 ...
1527       *      or even, for example, the pure $key[] values hardcoded)
1528       *
1529       *    - avoiding 1000's of function calls of ie _encryptBlock()
1530       *      but inlining the crypt operations.
1531       *      in the mode of operation for() loop.
1532       *
1533       *    - full loop unroll the (sometimes key-dependent) rounds
1534       *      avoiding this way ++$i counters and runtime-if's etc...
1535       *
1536       *    The basic code architectur of the generated $inline en/decrypt()
1537       *    lambda function, in pseudo php, is:
1538       *
1539       *    <code>
1540       *    +----------------------------------------------------------------------------------------------+
1541       *    | callback $inline = create_function:                                                          |
1542       *    | lambda_function_0001_crypt_ECB($action, $text)                                               |
1543       *    | {                                                                                            |
1544       *    |     INSERT PHP CODE OF:                                                                      |
1545       *    |     $cipher_code['init_crypt'];                  // general init code.                       |
1546       *    |                                                  // ie: $sbox'es declarations used for       |
1547       *    |                                                  //     encrypt and decrypt'ing.             |
1548       *    |                                                                                              |
1549       *    |     switch ($action) {                                                                       |
1550       *    |         case 'encrypt':                                                                      |
1551       *    |             INSERT PHP CODE OF:                                                              |
1552       *    |             $cipher_code['init_encrypt'];       // encrypt sepcific init code.               |
1553       *    |                                                    ie: specified $key or $box                |
1554       *    |                                                        declarations for encrypt'ing.         |
1555       *    |                                                                                              |
1556       *    |             foreach ($ciphertext) {                                                          |
1557       *    |                 $in = $block_size of $ciphertext;                                            |
1558       *    |                                                                                              |
1559       *    |                 INSERT PHP CODE OF:                                                          |
1560       *    |                 $cipher_code['encrypt_block'];  // encrypt's (string) $in, which is always:  |
1561       *    |                                                 // strlen($in) == $this->block_size          |
1562       *    |                                                 // here comes the cipher algorithm in action |
1563       *    |                                                 // for encryption.                           |
1564       *    |                                                 // $cipher_code['encrypt_block'] has to      |
1565       *    |                                                 // encrypt the content of the $in variable   |
1566       *    |                                                                                              |
1567       *    |                 $plaintext .= $in;                                                           |
1568       *    |             }                                                                                |
1569       *    |             return $plaintext;                                                               |
1570       *    |                                                                                              |
1571       *    |         case 'decrypt':                                                                      |
1572       *    |             INSERT PHP CODE OF:                                                              |
1573       *    |             $cipher_code['init_decrypt'];       // decrypt sepcific init code                |
1574       *    |                                                    ie: specified $key or $box                |
1575       *    |                                                        declarations for decrypt'ing.         |
1576       *    |             foreach ($plaintext) {                                                           |
1577       *    |                 $in = $block_size of $plaintext;                                             |
1578       *    |                                                                                              |
1579       *    |                 INSERT PHP CODE OF:                                                          |
1580       *    |                 $cipher_code['decrypt_block'];  // decrypt's (string) $in, which is always   |
1581       *    |                                                 // strlen($in) == $this->block_size          |
1582       *    |                                                 // here comes the cipher algorithm in action |
1583       *    |                                                 // for decryption.                           |
1584       *    |                                                 // $cipher_code['decrypt_block'] has to      |
1585       *    |                                                 // decrypt the content of the $in variable   |
1586       *    |                 $ciphertext .= $in;                                                          |
1587       *    |             }                                                                                |
1588       *    |             return $ciphertext;                                                              |
1589       *    |     }                                                                                        |
1590       *    | }                                                                                            |
1591       *    +----------------------------------------------------------------------------------------------+
1592       *    </code>
1593       *
1594       *    See also the Crypt_*::_setupInlineCrypt()'s for
1595       *    productive inline $cipher_code's how they works.
1596       *
1597       *    Structure of:
1598       *    <code>
1599       *    $cipher_code = array(
1600       *        'init_crypt'    => (string) '', // optional
1601       *        'init_encrypt'  => (string) '', // optional
1602       *        'init_decrypt'  => (string) '', // optional
1603       *        'encrypt_block' => (string) '', // required
1604       *        'decrypt_block' => (string) ''  // required
1605       *    );
1606       *    </code>
1607       *
1608       * @see Crypt_Base::_setupInlineCrypt()
1609       * @see Crypt_Base::encrypt()
1610       * @see Crypt_Base::decrypt()
1611       * @param Array $cipher_code
1612       * @access private
1613       * @return String (the name of the created callback function)
1614       */
1615      function _createInlineCryptFunction($cipher_code)
1616      {
1617          $block_size = $this->block_size;
1618  
1619          // optional
1620          $init_crypt    = isset($cipher_code['init_crypt'])    ? $cipher_code['init_crypt']    : '';
1621          $init_encrypt  = isset($cipher_code['init_encrypt'])  ? $cipher_code['init_encrypt']  : '';
1622          $init_decrypt  = isset($cipher_code['init_decrypt'])  ? $cipher_code['init_decrypt']  : '';
1623          // required
1624          $encrypt_block = $cipher_code['encrypt_block'];
1625          $decrypt_block = $cipher_code['decrypt_block'];
1626  
1627          // Generating mode of operation inline code,
1628          // merged with the $cipher_code algorithm
1629          // for encrypt- and decryption.
1630          switch ($this->mode) {
1631              case CRYPT_MODE_ECB:
1632                  $encrypt = $init_encrypt . '
1633                      $_ciphertext = "";
1634                      $_text = $self->_pad($_text);
1635                      $_plaintext_len = strlen($_text);
1636  
1637                      for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
1638                          $in = substr($_text, $_i, '.$block_size.');
1639                          '.$encrypt_block.'
1640                          $_ciphertext.= $in;
1641                      }
1642  
1643                      return $_ciphertext;
1644                      ';
1645  
1646                  $decrypt = $init_decrypt . '
1647                      $_plaintext = "";
1648                      $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
1649                      $_ciphertext_len = strlen($_text);
1650  
1651                      for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
1652                          $in = substr($_text, $_i, '.$block_size.');
1653                          '.$decrypt_block.'
1654                          $_plaintext.= $in;
1655                      }
1656  
1657                      return $self->_unpad($_plaintext);
1658                      ';
1659                  break;
1660              case CRYPT_MODE_CTR:
1661                  $encrypt = $init_encrypt . '
1662                      $_ciphertext = "";
1663                      $_plaintext_len = strlen($_text);
1664                      $_xor = $self->encryptIV;
1665                      $_buffer = &$self->enbuffer;
1666  
1667                      if (strlen($_buffer["encrypted"])) {
1668                          for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
1669                              $_block = substr($_text, $_i, '.$block_size.');
1670                              if (strlen($_block) > strlen($_buffer["encrypted"])) {
1671                                  $in = $self->_generateXor($_xor, '.$block_size.');
1672                                  '.$encrypt_block.'
1673                                  $_buffer["encrypted"].= $in;
1674                              }
1675                              $_key = $self->_stringShift($_buffer["encrypted"], '.$block_size.');
1676                              $_ciphertext.= $_block ^ $_key;
1677                          }
1678                      } else {
1679                          for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
1680                              $_block = substr($_text, $_i, '.$block_size.');
1681                              $in = $self->_generateXor($_xor, '.$block_size.');
1682                              '.$encrypt_block.'
1683                              $_key = $in;
1684                              $_ciphertext.= $_block ^ $_key;
1685                          }
1686                      }
1687                      if ($self->continuousBuffer) {
1688                          $self->encryptIV = $_xor;
1689                          if ($_start = $_plaintext_len % '.$block_size.') {
1690                              $_buffer["encrypted"] = substr($_key, $_start) . $_buffer["encrypted"];
1691                          }
1692                      }
1693  
1694                      return $_ciphertext;
1695                  ';
1696  
1697                  $decrypt = $init_encrypt . '
1698                      $_plaintext = "";
1699                      $_ciphertext_len = strlen($_text);
1700                      $_xor = $self->decryptIV;
1701                      $_buffer = &$self->debuffer;
1702  
1703                      if (strlen($_buffer["ciphertext"])) {
1704                          for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
1705                              $_block = substr($_text, $_i, '.$block_size.');
1706                              if (strlen($_block) > strlen($_buffer["ciphertext"])) {
1707                                  $in = $self->_generateXor($_xor, '.$block_size.');
1708                                  '.$encrypt_block.'
1709                                  $_buffer["ciphertext"].= $in;
1710                              }
1711                              $_key = $self->_stringShift($_buffer["ciphertext"], '.$block_size.');
1712                              $_plaintext.= $_block ^ $_key;
1713                          }
1714                      } else {
1715                          for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
1716                              $_block = substr($_text, $_i, '.$block_size.');
1717                              $in = $self->_generateXor($_xor, '.$block_size.');
1718                              '.$encrypt_block.'
1719                              $_key = $in;
1720                              $_plaintext.= $_block ^ $_key;
1721                          }
1722                      }
1723                      if ($self->continuousBuffer) {
1724                          $self->decryptIV = $_xor;
1725                          if ($_start = $_ciphertext_len % '.$block_size.') {
1726                              $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
1727                          }
1728                      }
1729  
1730                      return $_plaintext;
1731                      ';
1732                  break;
1733              case CRYPT_MODE_CFB:
1734                  $encrypt = $init_encrypt . '
1735                      $_ciphertext = "";
1736                      $_buffer = &$self->enbuffer;
1737  
1738                      if ($self->continuousBuffer) {
1739                          $_iv = &$self->encryptIV;
1740                          $_pos = &$_buffer["pos"];
1741                      } else {
1742                          $_iv = $self->encryptIV;
1743                          $_pos = 0;
1744                      }
1745                      $_len = strlen($_text);
1746                      $_i = 0;
1747                      if ($_pos) {
1748                          $_orig_pos = $_pos;
1749                          $_max = '.$block_size.' - $_pos;
1750                          if ($_len >= $_max) {
1751                              $_i = $_max;
1752                              $_len-= $_max;
1753                              $_pos = 0;
1754                          } else {
1755                              $_i = $_len;
1756                              $_pos+= $_len;
1757                              $_len = 0;
1758                          }
1759                          $_ciphertext = substr($_iv, $_orig_pos) ^ $_text;
1760                          $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i);
1761                      }
1762                      while ($_len >= '.$block_size.') {
1763                          $in = $_iv;
1764                          '.$encrypt_block.';
1765                          $_iv = $in ^ substr($_text, $_i, '.$block_size.');
1766                          $_ciphertext.= $_iv;
1767                          $_len-= '.$block_size.';
1768                          $_i+= '.$block_size.';
1769                      }
1770                      if ($_len) {
1771                          $in = $_iv;
1772                          '.$encrypt_block.'
1773                          $_iv = $in;
1774                          $_block = $_iv ^ substr($_text, $_i);
1775                          $_iv = substr_replace($_iv, $_block, 0, $_len);
1776                          $_ciphertext.= $_block;
1777                          $_pos = $_len;
1778                      }
1779                      return $_ciphertext;
1780                  ';
1781  
1782                  $decrypt = $init_encrypt . '
1783                      $_plaintext = "";
1784                      $_buffer = &$self->debuffer;
1785  
1786                      if ($self->continuousBuffer) {
1787                          $_iv = &$self->decryptIV;
1788                          $_pos = &$_buffer["pos"];
1789                      } else {
1790                          $_iv = $self->decryptIV;
1791                          $_pos = 0;
1792                      }
1793                      $_len = strlen($_text);
1794                      $_i = 0;
1795                      if ($_pos) {
1796                          $_orig_pos = $_pos;
1797                          $_max = '.$block_size.' - $_pos;
1798                          if ($_len >= $_max) {
1799                              $_i = $_max;
1800                              $_len-= $_max;
1801                              $_pos = 0;
1802                          } else {
1803                              $_i = $_len;
1804                              $_pos+= $_len;
1805                              $_len = 0;
1806                          }
1807                          $_plaintext = substr($_iv, $_orig_pos) ^ $_text;
1808                          $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i);
1809                      }
1810                      while ($_len >= '.$block_size.') {
1811                          $in = $_iv;
1812                          '.$encrypt_block.'
1813                          $_iv = $in;
1814                          $cb = substr($_text, $_i, '.$block_size.');
1815                          $_plaintext.= $_iv ^ $cb;
1816                          $_iv = $cb;
1817                          $_len-= '.$block_size.';
1818                          $_i+= '.$block_size.';
1819                      }
1820                      if ($_len) {
1821                          $in = $_iv;
1822                          '.$encrypt_block.'
1823                          $_iv = $in;
1824                          $_plaintext.= $_iv ^ substr($_text, $_i);
1825                          $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len);
1826                          $_pos = $_len;
1827                      }
1828  
1829                      return $_plaintext;
1830                      ';
1831                  break;
1832              case CRYPT_MODE_OFB:
1833                  $encrypt = $init_encrypt . '
1834                      $_ciphertext = "";
1835                      $_plaintext_len = strlen($_text);
1836                      $_xor = $self->encryptIV;
1837                      $_buffer = &$self->enbuffer;
1838  
1839                      if (strlen($_buffer["xor"])) {
1840                          for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
1841                              $_block = substr($_text, $_i, '.$block_size.');
1842                              if (strlen($_block) > strlen($_buffer["xor"])) {
1843                                  $in = $_xor;
1844                                  '.$encrypt_block.'
1845                                  $_xor = $in;
1846                                  $_buffer["xor"].= $_xor;
1847                              }
1848                              $_key = $self->_stringShift($_buffer["xor"], '.$block_size.');
1849                              $_ciphertext.= $_block ^ $_key;
1850                          }
1851                      } else {
1852                          for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
1853                              $in = $_xor;
1854                              '.$encrypt_block.'
1855                              $_xor = $in;
1856                              $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
1857                          }
1858                          $_key = $_xor;
1859                      }
1860                      if ($self->continuousBuffer) {
1861                          $self->encryptIV = $_xor;
1862                          if ($_start = $_plaintext_len % '.$block_size.') {
1863                               $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
1864                          }
1865                      }
1866                      return $_ciphertext;
1867                      ';
1868  
1869                  $decrypt = $init_encrypt . '
1870                      $_plaintext = "";
1871                      $_ciphertext_len = strlen($_text);
1872                      $_xor = $self->decryptIV;
1873                      $_buffer = &$self->debuffer;
1874  
1875                      if (strlen($_buffer["xor"])) {
1876                          for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
1877                              $_block = substr($_text, $_i, '.$block_size.');
1878                              if (strlen($_block) > strlen($_buffer["xor"])) {
1879                                  $in = $_xor;
1880                                  '.$encrypt_block.'
1881                                  $_xor = $in;
1882                                  $_buffer["xor"].= $_xor;
1883                              }
1884                              $_key = $self->_stringShift($_buffer["xor"], '.$block_size.');
1885                              $_plaintext.= $_block ^ $_key;
1886                          }
1887                      } else {
1888                          for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
1889                              $in = $_xor;
1890                              '.$encrypt_block.'
1891                              $_xor = $in;
1892                              $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
1893                          }
1894                          $_key = $_xor;
1895                      }
1896                      if ($self->continuousBuffer) {
1897                          $self->decryptIV = $_xor;
1898                          if ($_start = $_ciphertext_len % '.$block_size.') {
1899                               $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
1900                          }
1901                      }
1902                      return $_plaintext;
1903                      ';
1904                  break;
1905              case CRYPT_MODE_STREAM:
1906                  $encrypt = $init_encrypt . '
1907                      $_ciphertext = "";
1908                      '.$encrypt_block.'
1909                      return $_ciphertext;
1910                      ';
1911                  $decrypt = $init_decrypt . '
1912                      $_plaintext = "";
1913                      '.$decrypt_block.'
1914                      return $_plaintext;
1915                      ';
1916                  break;
1917              // case CRYPT_MODE_CBC:
1918              default:
1919                  $encrypt = $init_encrypt . '
1920                      $_ciphertext = "";
1921                      $_text = $self->_pad($_text);
1922                      $_plaintext_len = strlen($_text);
1923  
1924                      $in = $self->encryptIV;
1925  
1926                      for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
1927                          $in = substr($_text, $_i, '.$block_size.') ^ $in;
1928                          '.$encrypt_block.'
1929                          $_ciphertext.= $in;
1930                      }
1931  
1932                      if ($self->continuousBuffer) {
1933                          $self->encryptIV = $in;
1934                      }
1935  
1936                      return $_ciphertext;
1937                      ';
1938  
1939                  $decrypt = $init_decrypt . '
1940                      $_plaintext = "";
1941                      $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
1942                      $_ciphertext_len = strlen($_text);
1943  
1944                      $_iv = $self->decryptIV;
1945  
1946                      for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
1947                          $in = $_block = substr($_text, $_i, '.$block_size.');
1948                          '.$decrypt_block.'
1949                          $_plaintext.= $in ^ $_iv;
1950                          $_iv = $_block;
1951                      }
1952  
1953                      if ($self->continuousBuffer) {
1954                          $self->decryptIV = $_iv;
1955                      }
1956  
1957                      return $self->_unpad($_plaintext);
1958                      ';
1959                  break;
1960          }
1961  
1962          // Create the $inline function and return its name as string. Ready to run!
1963          return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }');
1964      }
1965  
1966      /**
1967       * Holds the lambda_functions table (classwide)
1968       *
1969       * Each name of the lambda function, created from
1970       * _setupInlineCrypt() && _createInlineCryptFunction()
1971       * is stored, classwide (!), here for reusing.
1972       *
1973       * The string-based index of $function is a classwide
1974       * uniqe value representing, at least, the $mode of
1975       * operation (or more... depends of the optimizing level)
1976       * for which $mode the lambda function was created.
1977       *
1978       * @access private
1979       * @return &Array
1980       */
1981      function &_getLambdaFunctions()
1982      {
1983          static $functions = array();
1984          return $functions;
1985      }
1986  }
1987  
1988  // vim: ts=4:sw=4:et:
1989  // vim6: fdl=1: