[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

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

   1  <?php
   2  
   3  /**
   4   * Pure-PHP implementation of RC2.
   5   *
   6   * Uses mcrypt, if available, and an internal implementation, otherwise.
   7   *
   8   * PHP version 5
   9   *
  10   * Useful resources are as follows:
  11   *
  12   *  - {@link http://tools.ietf.org/html/rfc2268}
  13   *
  14   * Here's a short example of how to use this library:
  15   * <code>
  16   * <?php
  17   *    include 'vendor/autoload.php';
  18   *
  19   *    $rc2 = new \phpseclib\Crypt\RC2();
  20   *
  21   *    $rc2->setKey('abcdefgh');
  22   *
  23   *    $plaintext = str_repeat('a', 1024);
  24   *
  25   *    echo $rc2->decrypt($rc2->encrypt($plaintext));
  26   * ?>
  27   * </code>
  28   *
  29   * @category Crypt
  30   * @package  RC2
  31   * @author   Patrick Monnerat <pm@datasphere.ch>
  32   * @license  http://www.opensource.org/licenses/mit-license.html  MIT License
  33   * @link     http://phpseclib.sourceforge.net
  34   */
  35  
  36  namespace phpseclib\Crypt;
  37  
  38  /**
  39   * Pure-PHP implementation of RC2.
  40   *
  41   * @package RC2
  42   * @access  public
  43   */
  44  class RC2 extends Base
  45  {
  46      /**
  47       * Block Length of the cipher
  48       *
  49       * @see \phpseclib\Crypt\Base::block_size
  50       * @var int
  51       * @access private
  52       */
  53      var $block_size = 8;
  54  
  55      /**
  56       * The Key
  57       *
  58       * @see \phpseclib\Crypt\Base::key
  59       * @see self::setKey()
  60       * @var string
  61       * @access private
  62       */
  63      var $key;
  64  
  65      /**
  66       * The Original (unpadded) Key
  67       *
  68       * @see \phpseclib\Crypt\Base::key
  69       * @see self::setKey()
  70       * @see self::encrypt()
  71       * @see self::decrypt()
  72       * @var string
  73       * @access private
  74       */
  75      var $orig_key;
  76  
  77      /**
  78       * Don't truncate / null pad key
  79       *
  80       * @see \phpseclib\Crypt\Base::_clearBuffers()
  81       * @var bool
  82       * @access private
  83       */
  84      var $skip_key_adjustment = true;
  85  
  86      /**
  87       * Key Length (in bytes)
  88       *
  89       * @see \phpseclib\Crypt\RC2::setKeyLength()
  90       * @var int
  91       * @access private
  92       */
  93      var $key_length = 16; // = 128 bits
  94  
  95      /**
  96       * The mcrypt specific name of the cipher
  97       *
  98       * @see \phpseclib\Crypt\Base::cipher_name_mcrypt
  99       * @var string
 100       * @access private
 101       */
 102      var $cipher_name_mcrypt = 'rc2';
 103  
 104      /**
 105       * Optimizing value while CFB-encrypting
 106       *
 107       * @see \phpseclib\Crypt\Base::cfb_init_len
 108       * @var int
 109       * @access private
 110       */
 111      var $cfb_init_len = 500;
 112  
 113      /**
 114       * The key length in bits.
 115       *
 116       * @see self::setKeyLength()
 117       * @see self::setKey()
 118       * @var int
 119       * @access private
 120       * @internal Should be in range [1..1024].
 121       * @internal Changing this value after setting the key has no effect.
 122       */
 123      var $default_key_length = 1024;
 124  
 125      /**
 126       * The key length in bits.
 127       *
 128       * @see self::isValidEnine()
 129       * @see self::setKey()
 130       * @var int
 131       * @access private
 132       * @internal Should be in range [1..1024].
 133       */
 134      var $current_key_length;
 135  
 136      /**
 137       * The Key Schedule
 138       *
 139       * @see self::_setupKey()
 140       * @var array
 141       * @access private
 142       */
 143      var $keys;
 144  
 145      /**
 146       * Key expansion randomization table.
 147       * Twice the same 256-value sequence to save a modulus in key expansion.
 148       *
 149       * @see self::setKey()
 150       * @var array
 151       * @access private
 152       */
 153      var $pitable = array(
 154          0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
 155          0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
 156          0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
 157          0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
 158          0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
 159          0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
 160          0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
 161          0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
 162          0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
 163          0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
 164          0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
 165          0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
 166          0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
 167          0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
 168          0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
 169          0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
 170          0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
 171          0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
 172          0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
 173          0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
 174          0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
 175          0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
 176          0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
 177          0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
 178          0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
 179          0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
 180          0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
 181          0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
 182          0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
 183          0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
 184          0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
 185          0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD,
 186          0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
 187          0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
 188          0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
 189          0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
 190          0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
 191          0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
 192          0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
 193          0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
 194          0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
 195          0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
 196          0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
 197          0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
 198          0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
 199          0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
 200          0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
 201          0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
 202          0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
 203          0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
 204          0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
 205          0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
 206          0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
 207          0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
 208          0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
 209          0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
 210          0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
 211          0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
 212          0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
 213          0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
 214          0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
 215          0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
 216          0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
 217          0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD
 218      );
 219  
 220      /**
 221       * Inverse key expansion randomization table.
 222       *
 223       * @see self::setKey()
 224       * @var array
 225       * @access private
 226       */
 227      var $invpitable = array(
 228          0xD1, 0xDA, 0xB9, 0x6F, 0x9C, 0xC8, 0x78, 0x66,
 229          0x80, 0x2C, 0xF8, 0x37, 0xEA, 0xE0, 0x62, 0xA4,
 230          0xCB, 0x71, 0x50, 0x27, 0x4B, 0x95, 0xD9, 0x20,
 231          0x9D, 0x04, 0x91, 0xE3, 0x47, 0x6A, 0x7E, 0x53,
 232          0xFA, 0x3A, 0x3B, 0xB4, 0xA8, 0xBC, 0x5F, 0x68,
 233          0x08, 0xCA, 0x8F, 0x14, 0xD7, 0xC0, 0xEF, 0x7B,
 234          0x5B, 0xBF, 0x2F, 0xE5, 0xE2, 0x8C, 0xBA, 0x12,
 235          0xE1, 0xAF, 0xB2, 0x54, 0x5D, 0x59, 0x76, 0xDB,
 236          0x32, 0xA2, 0x58, 0x6E, 0x1C, 0x29, 0x64, 0xF3,
 237          0xE9, 0x96, 0x0C, 0x98, 0x19, 0x8D, 0x3E, 0x26,
 238          0xAB, 0xA5, 0x85, 0x16, 0x40, 0xBD, 0x49, 0x67,
 239          0xDC, 0x22, 0x94, 0xBB, 0x3C, 0xC1, 0x9B, 0xEB,
 240          0x45, 0x28, 0x18, 0xD8, 0x1A, 0x42, 0x7D, 0xCC,
 241          0xFB, 0x65, 0x8E, 0x3D, 0xCD, 0x2A, 0xA3, 0x60,
 242          0xAE, 0x93, 0x8A, 0x48, 0x97, 0x51, 0x15, 0xF7,
 243          0x01, 0x0B, 0xB7, 0x36, 0xB1, 0x2E, 0x11, 0xFD,
 244          0x84, 0x2D, 0x3F, 0x13, 0x88, 0xB3, 0x34, 0x24,
 245          0x1B, 0xDE, 0xC5, 0x1D, 0x4D, 0x2B, 0x17, 0x31,
 246          0x74, 0xA9, 0xC6, 0x43, 0x6D, 0x39, 0x90, 0xBE,
 247          0xC3, 0xB0, 0x21, 0x6B, 0xF6, 0x0F, 0xD5, 0x99,
 248          0x0D, 0xAC, 0x1F, 0x5C, 0x9E, 0xF5, 0xF9, 0x4C,
 249          0xD6, 0xDF, 0x89, 0xE4, 0x8B, 0xFF, 0xC7, 0xAA,
 250          0xE7, 0xED, 0x46, 0x25, 0xB6, 0x06, 0x5E, 0x35,
 251          0xB5, 0xEC, 0xCE, 0xE8, 0x6C, 0x30, 0x55, 0x61,
 252          0x4A, 0xFE, 0xA0, 0x79, 0x03, 0xF0, 0x10, 0x72,
 253          0x7C, 0xCF, 0x52, 0xA6, 0xA7, 0xEE, 0x44, 0xD3,
 254          0x9A, 0x57, 0x92, 0xD0, 0x5A, 0x7A, 0x41, 0x7F,
 255          0x0E, 0x00, 0x63, 0xF2, 0x4F, 0x05, 0x83, 0xC9,
 256          0xA1, 0xD4, 0xDD, 0xC4, 0x56, 0xF4, 0xD2, 0x77,
 257          0x81, 0x09, 0x82, 0x33, 0x9F, 0x07, 0x86, 0x75,
 258          0x38, 0x4E, 0x69, 0xF1, 0xAD, 0x23, 0x73, 0x87,
 259          0x70, 0x02, 0xC2, 0x1E, 0xB8, 0x0A, 0xFC, 0xE6
 260      );
 261  
 262      /**
 263       * Test for engine validity
 264       *
 265       * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Base::isValidEngine()
 266       *
 267       * @see \phpseclib\Crypt\Base::__construct()
 268       * @param int $engine
 269       * @access public
 270       * @return bool
 271       */
 272      function isValidEngine($engine)
 273      {
 274          switch ($engine) {
 275              case self::ENGINE_OPENSSL:
 276                  if ($this->current_key_length != 128 || strlen($this->orig_key) < 16) {
 277                      return false;
 278                  }
 279                  $this->cipher_name_openssl_ecb = 'rc2-ecb';
 280                  $this->cipher_name_openssl = 'rc2-' . $this->_openssl_translate_mode();
 281          }
 282  
 283          return parent::isValidEngine($engine);
 284      }
 285  
 286      /**
 287       * Sets the key length.
 288       *
 289       * Valid key lengths are 8 to 1024.
 290       * Calling this function after setting the key has no effect until the next
 291       *  \phpseclib\Crypt\RC2::setKey() call.
 292       *
 293       * @access public
 294       * @param int $length in bits
 295       */
 296      function setKeyLength($length)
 297      {
 298          if ($length < 8) {
 299              $this->default_key_length = 1;
 300          } elseif ($length > 1024) {
 301              $this->default_key_length = 128;
 302          } else {
 303              $this->default_key_length = $length;
 304          }
 305          $this->current_key_length = $this->default_key_length;
 306  
 307          parent::setKeyLength($length);
 308      }
 309  
 310      /**
 311       * Returns the current key length
 312       *
 313       * @access public
 314       * @return int
 315       */
 316      function getKeyLength()
 317      {
 318          return $this->current_key_length;
 319      }
 320  
 321      /**
 322       * Sets the key.
 323       *
 324       * Keys can be of any length. RC2, itself, uses 8 to 1024 bit keys (eg.
 325       * strlen($key) <= 128), however, we only use the first 128 bytes if $key
 326       * has more then 128 bytes in it, and set $key to a single null byte if
 327       * it is empty.
 328       *
 329       * If the key is not explicitly set, it'll be assumed to be a single
 330       * null byte.
 331       *
 332       * @see \phpseclib\Crypt\Base::setKey()
 333       * @access public
 334       * @param string $key
 335       * @param int $t1 optional Effective key length in bits.
 336       */
 337      function setKey($key, $t1 = 0)
 338      {
 339          $this->orig_key = $key;
 340  
 341          if ($t1 <= 0) {
 342              $t1 = $this->default_key_length;
 343          } elseif ($t1 > 1024) {
 344              $t1 = 1024;
 345          }
 346          $this->current_key_length = $t1;
 347          // Key byte count should be 1..128.
 348          $key = strlen($key) ? substr($key, 0, 128) : "\x00";
 349          $t = strlen($key);
 350  
 351          // The mcrypt RC2 implementation only supports effective key length
 352          // of 1024 bits. It is however possible to handle effective key
 353          // lengths in range 1..1024 by expanding the key and applying
 354          // inverse pitable mapping to the first byte before submitting it
 355          // to mcrypt.
 356  
 357          // Key expansion.
 358          $l = array_values(unpack('C*', $key));
 359          $t8 = ($t1 + 7) >> 3;
 360          $tm = 0xFF >> (8 * $t8 - $t1);
 361  
 362          // Expand key.
 363          $pitable = $this->pitable;
 364          for ($i = $t; $i < 128; $i++) {
 365              $l[$i] = $pitable[$l[$i - 1] + $l[$i - $t]];
 366          }
 367          $i = 128 - $t8;
 368          $l[$i] = $pitable[$l[$i] & $tm];
 369          while ($i--) {
 370              $l[$i] = $pitable[$l[$i + 1] ^ $l[$i + $t8]];
 371          }
 372  
 373          // Prepare the key for mcrypt.
 374          $l[0] = $this->invpitable[$l[0]];
 375          array_unshift($l, 'C*');
 376  
 377          parent::setKey(call_user_func_array('pack', $l));
 378      }
 379  
 380      /**
 381       * Encrypts a message.
 382       *
 383       * Mostly a wrapper for \phpseclib\Crypt\Base::encrypt, with some additional OpenSSL handling code
 384       *
 385       * @see self::decrypt()
 386       * @access public
 387       * @param string $plaintext
 388       * @return string $ciphertext
 389       */
 390      function encrypt($plaintext)
 391      {
 392          if ($this->engine == self::ENGINE_OPENSSL) {
 393              $temp = $this->key;
 394              $this->key = $this->orig_key;
 395              $result = parent::encrypt($plaintext);
 396              $this->key = $temp;
 397              return $result;
 398          }
 399  
 400          return parent::encrypt($plaintext);
 401      }
 402  
 403      /**
 404       * Decrypts a message.
 405       *
 406       * Mostly a wrapper for \phpseclib\Crypt\Base::decrypt, with some additional OpenSSL handling code
 407       *
 408       * @see self::encrypt()
 409       * @access public
 410       * @param string $ciphertext
 411       * @return string $plaintext
 412       */
 413      function decrypt($ciphertext)
 414      {
 415          if ($this->engine == self::ENGINE_OPENSSL) {
 416              $temp = $this->key;
 417              $this->key = $this->orig_key;
 418              $result = parent::decrypt($ciphertext);
 419              $this->key = $temp;
 420              return $result;
 421          }
 422  
 423          return parent::decrypt($ciphertext);
 424      }
 425  
 426      /**
 427       * Encrypts a block
 428       *
 429       * @see \phpseclib\Crypt\Base::_encryptBlock()
 430       * @see \phpseclib\Crypt\Base::encrypt()
 431       * @access private
 432       * @param string $in
 433       * @return string
 434       */
 435      function _encryptBlock($in)
 436      {
 437          list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
 438          $keys = $this->keys;
 439          $limit = 20;
 440          $actions = array($limit => 44, 44 => 64);
 441          $j = 0;
 442  
 443          for (;;) {
 444              // Mixing round.
 445              $r0 = (($r0 + $keys[$j++] + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
 446              $r0 |= $r0 >> 16;
 447              $r1 = (($r1 + $keys[$j++] + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
 448              $r1 |= $r1 >> 16;
 449              $r2 = (($r2 + $keys[$j++] + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
 450              $r2 |= $r2 >> 16;
 451              $r3 = (($r3 + $keys[$j++] + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
 452              $r3 |= $r3 >> 16;
 453  
 454              if ($j === $limit) {
 455                  if ($limit === 64) {
 456                      break;
 457                  }
 458  
 459                  // Mashing round.
 460                  $r0 += $keys[$r3 & 0x3F];
 461                  $r1 += $keys[$r0 & 0x3F];
 462                  $r2 += $keys[$r1 & 0x3F];
 463                  $r3 += $keys[$r2 & 0x3F];
 464                  $limit = $actions[$limit];
 465              }
 466          }
 467  
 468          return pack('vvvv', $r0, $r1, $r2, $r3);
 469      }
 470  
 471      /**
 472       * Decrypts a block
 473       *
 474       * @see \phpseclib\Crypt\Base::_decryptBlock()
 475       * @see \phpseclib\Crypt\Base::decrypt()
 476       * @access private
 477       * @param string $in
 478       * @return string
 479       */
 480      function _decryptBlock($in)
 481      {
 482          list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
 483          $keys = $this->keys;
 484          $limit = 44;
 485          $actions = array($limit => 20, 20 => 0);
 486          $j = 64;
 487  
 488          for (;;) {
 489              // R-mixing round.
 490              $r3 = ($r3 | ($r3 << 16)) >> 5;
 491              $r3 = ($r3 - $keys[--$j] - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
 492              $r2 = ($r2 | ($r2 << 16)) >> 3;
 493              $r2 = ($r2 - $keys[--$j] - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
 494              $r1 = ($r1 | ($r1 << 16)) >> 2;
 495              $r1 = ($r1 - $keys[--$j] - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
 496              $r0 = ($r0 | ($r0 << 16)) >> 1;
 497              $r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;
 498  
 499              if ($j === $limit) {
 500                  if ($limit === 0) {
 501                      break;
 502                  }
 503  
 504                  // R-mashing round.
 505                  $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
 506                  $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
 507                  $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
 508                  $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;
 509                  $limit = $actions[$limit];
 510              }
 511          }
 512  
 513          return pack('vvvv', $r0, $r1, $r2, $r3);
 514      }
 515  
 516      /**
 517       * Setup the \phpseclib\Crypt\Base::ENGINE_MCRYPT $engine
 518       *
 519       * @see \phpseclib\Crypt\Base::_setupMcrypt()
 520       * @access private
 521       */
 522      function _setupMcrypt()
 523      {
 524          if (!isset($this->key)) {
 525              $this->setKey('');
 526          }
 527  
 528          parent::_setupMcrypt();
 529      }
 530  
 531      /**
 532       * Creates the key schedule
 533       *
 534       * @see \phpseclib\Crypt\Base::_setupKey()
 535       * @access private
 536       */
 537      function _setupKey()
 538      {
 539          if (!isset($this->key)) {
 540              $this->setKey('');
 541          }
 542  
 543          // Key has already been expanded in \phpseclib\Crypt\RC2::setKey():
 544          // Only the first value must be altered.
 545          $l = unpack('Ca/Cb/v*', $this->key);
 546          array_unshift($l, $this->pitable[$l['a']] | ($l['b'] << 8));
 547          unset($l['a']);
 548          unset($l['b']);
 549          $this->keys = $l;
 550      }
 551  
 552      /**
 553       * Setup the performance-optimized function for de/encrypt()
 554       *
 555       * @see \phpseclib\Crypt\Base::_setupInlineCrypt()
 556       * @access private
 557       */
 558      function _setupInlineCrypt()
 559      {
 560          $lambda_functions =& self::_getLambdaFunctions();
 561  
 562          // The first 10 generated $lambda_functions will use the $keys hardcoded as integers
 563          // for the mixing rounds, for better inline crypt performance [~20% faster].
 564          // But for memory reason we have to limit those ultra-optimized $lambda_functions to an amount of 10.
 565          // (Currently, for Crypt_RC2, one generated $lambda_function cost on php5.5@32bit ~60kb unfreeable mem and ~100kb on php5.5@64bit)
 566          $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
 567  
 568          // Generation of a unique hash for our generated code
 569          $code_hash = "Crypt_RC2, {$this->mode}";
 570          if ($gen_hi_opt_code) {
 571              $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
 572          }
 573  
 574          // Is there a re-usable $lambda_functions in there?
 575          // If not, we have to create it.
 576          if (!isset($lambda_functions[$code_hash])) {
 577              // Init code for both, encrypt and decrypt.
 578              $init_crypt = '$keys = $self->keys;';
 579  
 580              switch (true) {
 581                  case $gen_hi_opt_code:
 582                      $keys = $this->keys;
 583                  default:
 584                      $keys = array();
 585                      foreach ($this->keys as $k => $v) {
 586                          $keys[$k] = '$keys[' . $k . ']';
 587                      }
 588              }
 589  
 590              // $in is the current 8 bytes block which has to be en/decrypt
 591              $encrypt_block = $decrypt_block = '
 592                  $in = unpack("v4", $in);
 593                  $r0 = $in[1];
 594                  $r1 = $in[2];
 595                  $r2 = $in[3];
 596                  $r3 = $in[4];
 597              ';
 598  
 599              // Create code for encryption.
 600              $limit = 20;
 601              $actions = array($limit => 44, 44 => 64);
 602              $j = 0;
 603  
 604              for (;;) {
 605                  // Mixing round.
 606                  $encrypt_block .= '
 607                      $r0 = (($r0 + ' . $keys[$j++] . ' +
 608                             ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
 609                      $r0 |= $r0 >> 16;
 610                      $r1 = (($r1 + ' . $keys[$j++] . ' +
 611                             ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
 612                      $r1 |= $r1 >> 16;
 613                      $r2 = (($r2 + ' . $keys[$j++] . ' +
 614                             ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
 615                      $r2 |= $r2 >> 16;
 616                      $r3 = (($r3 + ' . $keys[$j++] . ' +
 617                             ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
 618                      $r3 |= $r3 >> 16;';
 619  
 620                  if ($j === $limit) {
 621                      if ($limit === 64) {
 622                          break;
 623                      }
 624  
 625                      // Mashing round.
 626                      $encrypt_block .= '
 627                          $r0 += $keys[$r3 & 0x3F];
 628                          $r1 += $keys[$r0 & 0x3F];
 629                          $r2 += $keys[$r1 & 0x3F];
 630                          $r3 += $keys[$r2 & 0x3F];';
 631                      $limit = $actions[$limit];
 632                  }
 633              }
 634  
 635              $encrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
 636  
 637              // Create code for decryption.
 638              $limit = 44;
 639              $actions = array($limit => 20, 20 => 0);
 640              $j = 64;
 641  
 642              for (;;) {
 643                  // R-mixing round.
 644                  $decrypt_block .= '
 645                      $r3 = ($r3 | ($r3 << 16)) >> 5;
 646                      $r3 = ($r3 - ' . $keys[--$j] . ' -
 647                             ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
 648                      $r2 = ($r2 | ($r2 << 16)) >> 3;
 649                      $r2 = ($r2 - ' . $keys[--$j] . ' -
 650                             ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
 651                      $r1 = ($r1 | ($r1 << 16)) >> 2;
 652                      $r1 = ($r1 - ' . $keys[--$j] . ' -
 653                             ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
 654                      $r0 = ($r0 | ($r0 << 16)) >> 1;
 655                      $r0 = ($r0 - ' . $keys[--$j] . ' -
 656                             ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;';
 657  
 658                  if ($j === $limit) {
 659                      if ($limit === 0) {
 660                          break;
 661                      }
 662  
 663                      // R-mashing round.
 664                      $decrypt_block .= '
 665                          $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
 666                          $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
 667                          $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
 668                          $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;';
 669                      $limit = $actions[$limit];
 670                  }
 671              }
 672  
 673              $decrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
 674  
 675              // Creates the inline-crypt function
 676              $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
 677                  array(
 678                     'init_crypt'    => $init_crypt,
 679                     'encrypt_block' => $encrypt_block,
 680                     'decrypt_block' => $decrypt_block
 681                  )
 682              );
 683          }
 684  
 685          // Set the inline-crypt function as callback in: $this->inline_crypt
 686          $this->inline_crypt = $lambda_functions[$code_hash];
 687      }
 688  }