[ 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                  // quoting https://www.openssl.org/news/openssl-3.0-notes.html, OpenSSL 3.0.1
 277                  // "Moved all variations of the EVP ciphers CAST5, BF, IDEA, SEED, RC2, RC4, RC5, and DES to the legacy provider"
 278                  // in theory openssl_get_cipher_methods() should catch this but, on GitHub Actions, at least, it does not
 279                  if (defined('OPENSSL_VERSION_TEXT') && version_compare(preg_replace('#OpenSSL (\d+\.\d+\.\d+) .*#', '$1', OPENSSL_VERSION_TEXT), '3.0.1', '>=')) {
 280                      return false;
 281                  }
 282                  if ($this->current_key_length != 128 || strlen($this->orig_key) < 16) {
 283                      return false;
 284                  }
 285                  $this->cipher_name_openssl_ecb = 'rc2-ecb';
 286                  $this->cipher_name_openssl = 'rc2-' . $this->_openssl_translate_mode();
 287          }
 288  
 289          return parent::isValidEngine($engine);
 290      }
 291  
 292      /**
 293       * Sets the key length.
 294       *
 295       * Valid key lengths are 8 to 1024.
 296       * Calling this function after setting the key has no effect until the next
 297       *  \phpseclib\Crypt\RC2::setKey() call.
 298       *
 299       * @access public
 300       * @param int $length in bits
 301       */
 302      function setKeyLength($length)
 303      {
 304          if ($length < 8) {
 305              $this->default_key_length = 1;
 306          } elseif ($length > 1024) {
 307              $this->default_key_length = 128;
 308          } else {
 309              $this->default_key_length = $length;
 310          }
 311          $this->current_key_length = $this->default_key_length;
 312  
 313          parent::setKeyLength($length);
 314      }
 315  
 316      /**
 317       * Returns the current key length
 318       *
 319       * @access public
 320       * @return int
 321       */
 322      function getKeyLength()
 323      {
 324          return $this->current_key_length;
 325      }
 326  
 327      /**
 328       * Sets the key.
 329       *
 330       * Keys can be of any length. RC2, itself, uses 8 to 1024 bit keys (eg.
 331       * strlen($key) <= 128), however, we only use the first 128 bytes if $key
 332       * has more then 128 bytes in it, and set $key to a single null byte if
 333       * it is empty.
 334       *
 335       * If the key is not explicitly set, it'll be assumed to be a single
 336       * null byte.
 337       *
 338       * @see \phpseclib\Crypt\Base::setKey()
 339       * @access public
 340       * @param string $key
 341       * @param int $t1 optional Effective key length in bits.
 342       */
 343      function setKey($key, $t1 = 0)
 344      {
 345          $this->orig_key = $key;
 346  
 347          if ($t1 <= 0) {
 348              $t1 = $this->default_key_length;
 349          } elseif ($t1 > 1024) {
 350              $t1 = 1024;
 351          }
 352          $this->current_key_length = $t1;
 353          // Key byte count should be 1..128.
 354          $key = strlen($key) ? substr($key, 0, 128) : "\x00";
 355          $t = strlen($key);
 356  
 357          // The mcrypt RC2 implementation only supports effective key length
 358          // of 1024 bits. It is however possible to handle effective key
 359          // lengths in range 1..1024 by expanding the key and applying
 360          // inverse pitable mapping to the first byte before submitting it
 361          // to mcrypt.
 362  
 363          // Key expansion.
 364          $l = array_values(unpack('C*', $key));
 365          $t8 = ($t1 + 7) >> 3;
 366          $tm = 0xFF >> (8 * $t8 - $t1);
 367  
 368          // Expand key.
 369          $pitable = $this->pitable;
 370          for ($i = $t; $i < 128; $i++) {
 371              $l[$i] = $pitable[$l[$i - 1] + $l[$i - $t]];
 372          }
 373          $i = 128 - $t8;
 374          $l[$i] = $pitable[$l[$i] & $tm];
 375          while ($i--) {
 376              $l[$i] = $pitable[$l[$i + 1] ^ $l[$i + $t8]];
 377          }
 378  
 379          // Prepare the key for mcrypt.
 380          $l[0] = $this->invpitable[$l[0]];
 381          array_unshift($l, 'C*');
 382  
 383          parent::setKey(call_user_func_array('pack', $l));
 384      }
 385  
 386      /**
 387       * Encrypts a message.
 388       *
 389       * Mostly a wrapper for \phpseclib\Crypt\Base::encrypt, with some additional OpenSSL handling code
 390       *
 391       * @see self::decrypt()
 392       * @access public
 393       * @param string $plaintext
 394       * @return string $ciphertext
 395       */
 396      function encrypt($plaintext)
 397      {
 398          if ($this->engine == self::ENGINE_OPENSSL) {
 399              $temp = $this->key;
 400              $this->key = $this->orig_key;
 401              $result = parent::encrypt($plaintext);
 402              $this->key = $temp;
 403              return $result;
 404          }
 405  
 406          return parent::encrypt($plaintext);
 407      }
 408  
 409      /**
 410       * Decrypts a message.
 411       *
 412       * Mostly a wrapper for \phpseclib\Crypt\Base::decrypt, with some additional OpenSSL handling code
 413       *
 414       * @see self::encrypt()
 415       * @access public
 416       * @param string $ciphertext
 417       * @return string $plaintext
 418       */
 419      function decrypt($ciphertext)
 420      {
 421          if ($this->engine == self::ENGINE_OPENSSL) {
 422              $temp = $this->key;
 423              $this->key = $this->orig_key;
 424              $result = parent::decrypt($ciphertext);
 425              $this->key = $temp;
 426              return $result;
 427          }
 428  
 429          return parent::decrypt($ciphertext);
 430      }
 431  
 432      /**
 433       * Encrypts a block
 434       *
 435       * @see \phpseclib\Crypt\Base::_encryptBlock()
 436       * @see \phpseclib\Crypt\Base::encrypt()
 437       * @access private
 438       * @param string $in
 439       * @return string
 440       */
 441      function _encryptBlock($in)
 442      {
 443          list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
 444          $keys = $this->keys;
 445          $limit = 20;
 446          $actions = array($limit => 44, 44 => 64);
 447          $j = 0;
 448  
 449          for (;;) {
 450              // Mixing round.
 451              $r0 = (($r0 + $keys[$j++] + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
 452              $r0 |= $r0 >> 16;
 453              $r1 = (($r1 + $keys[$j++] + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
 454              $r1 |= $r1 >> 16;
 455              $r2 = (($r2 + $keys[$j++] + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
 456              $r2 |= $r2 >> 16;
 457              $r3 = (($r3 + $keys[$j++] + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
 458              $r3 |= $r3 >> 16;
 459  
 460              if ($j === $limit) {
 461                  if ($limit === 64) {
 462                      break;
 463                  }
 464  
 465                  // Mashing round.
 466                  $r0 += $keys[$r3 & 0x3F];
 467                  $r1 += $keys[$r0 & 0x3F];
 468                  $r2 += $keys[$r1 & 0x3F];
 469                  $r3 += $keys[$r2 & 0x3F];
 470                  $limit = $actions[$limit];
 471              }
 472          }
 473  
 474          return pack('vvvv', $r0, $r1, $r2, $r3);
 475      }
 476  
 477      /**
 478       * Decrypts a block
 479       *
 480       * @see \phpseclib\Crypt\Base::_decryptBlock()
 481       * @see \phpseclib\Crypt\Base::decrypt()
 482       * @access private
 483       * @param string $in
 484       * @return string
 485       */
 486      function _decryptBlock($in)
 487      {
 488          list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
 489          $keys = $this->keys;
 490          $limit = 44;
 491          $actions = array($limit => 20, 20 => 0);
 492          $j = 64;
 493  
 494          for (;;) {
 495              // R-mixing round.
 496              $r3 = ($r3 | ($r3 << 16)) >> 5;
 497              $r3 = ($r3 - $keys[--$j] - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
 498              $r2 = ($r2 | ($r2 << 16)) >> 3;
 499              $r2 = ($r2 - $keys[--$j] - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
 500              $r1 = ($r1 | ($r1 << 16)) >> 2;
 501              $r1 = ($r1 - $keys[--$j] - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
 502              $r0 = ($r0 | ($r0 << 16)) >> 1;
 503              $r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;
 504  
 505              if ($j === $limit) {
 506                  if ($limit === 0) {
 507                      break;
 508                  }
 509  
 510                  // R-mashing round.
 511                  $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
 512                  $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
 513                  $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
 514                  $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;
 515                  $limit = $actions[$limit];
 516              }
 517          }
 518  
 519          return pack('vvvv', $r0, $r1, $r2, $r3);
 520      }
 521  
 522      /**
 523       * Setup the \phpseclib\Crypt\Base::ENGINE_MCRYPT $engine
 524       *
 525       * @see \phpseclib\Crypt\Base::_setupMcrypt()
 526       * @access private
 527       */
 528      function _setupMcrypt()
 529      {
 530          if (!isset($this->key)) {
 531              $this->setKey('');
 532          }
 533  
 534          parent::_setupMcrypt();
 535      }
 536  
 537      /**
 538       * Creates the key schedule
 539       *
 540       * @see \phpseclib\Crypt\Base::_setupKey()
 541       * @access private
 542       */
 543      function _setupKey()
 544      {
 545          if (!isset($this->key)) {
 546              $this->setKey('');
 547          }
 548  
 549          // Key has already been expanded in \phpseclib\Crypt\RC2::setKey():
 550          // Only the first value must be altered.
 551          $l = unpack('Ca/Cb/v*', $this->key);
 552          array_unshift($l, $this->pitable[$l['a']] | ($l['b'] << 8));
 553          unset($l['a']);
 554          unset($l['b']);
 555          $this->keys = $l;
 556      }
 557  
 558      /**
 559       * Setup the performance-optimized function for de/encrypt()
 560       *
 561       * @see \phpseclib\Crypt\Base::_setupInlineCrypt()
 562       * @access private
 563       */
 564      function _setupInlineCrypt()
 565      {
 566          $lambda_functions =& self::_getLambdaFunctions();
 567  
 568          // The first 10 generated $lambda_functions will use the $keys hardcoded as integers
 569          // for the mixing rounds, for better inline crypt performance [~20% faster].
 570          // But for memory reason we have to limit those ultra-optimized $lambda_functions to an amount of 10.
 571          // (Currently, for Crypt_RC2, one generated $lambda_function cost on php5.5@32bit ~60kb unfreeable mem and ~100kb on php5.5@64bit)
 572          $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
 573  
 574          // Generation of a unique hash for our generated code
 575          $code_hash = "Crypt_RC2, {$this->mode}";
 576          if ($gen_hi_opt_code) {
 577              $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
 578          }
 579  
 580          // Is there a re-usable $lambda_functions in there?
 581          // If not, we have to create it.
 582          if (!isset($lambda_functions[$code_hash])) {
 583              // Init code for both, encrypt and decrypt.
 584              $init_crypt = '$keys = $self->keys;';
 585  
 586              switch (true) {
 587                  case $gen_hi_opt_code:
 588                      $keys = $this->keys;
 589                  default:
 590                      $keys = array();
 591                      foreach ($this->keys as $k => $v) {
 592                          $keys[$k] = '$keys[' . $k . ']';
 593                      }
 594              }
 595  
 596              // $in is the current 8 bytes block which has to be en/decrypt
 597              $encrypt_block = $decrypt_block = '
 598                  $in = unpack("v4", $in);
 599                  $r0 = $in[1];
 600                  $r1 = $in[2];
 601                  $r2 = $in[3];
 602                  $r3 = $in[4];
 603              ';
 604  
 605              // Create code for encryption.
 606              $limit = 20;
 607              $actions = array($limit => 44, 44 => 64);
 608              $j = 0;
 609  
 610              for (;;) {
 611                  // Mixing round.
 612                  $encrypt_block .= '
 613                      $r0 = (($r0 + ' . $keys[$j++] . ' +
 614                             ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
 615                      $r0 |= $r0 >> 16;
 616                      $r1 = (($r1 + ' . $keys[$j++] . ' +
 617                             ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
 618                      $r1 |= $r1 >> 16;
 619                      $r2 = (($r2 + ' . $keys[$j++] . ' +
 620                             ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
 621                      $r2 |= $r2 >> 16;
 622                      $r3 = (($r3 + ' . $keys[$j++] . ' +
 623                             ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
 624                      $r3 |= $r3 >> 16;';
 625  
 626                  if ($j === $limit) {
 627                      if ($limit === 64) {
 628                          break;
 629                      }
 630  
 631                      // Mashing round.
 632                      $encrypt_block .= '
 633                          $r0 += $keys[$r3 & 0x3F];
 634                          $r1 += $keys[$r0 & 0x3F];
 635                          $r2 += $keys[$r1 & 0x3F];
 636                          $r3 += $keys[$r2 & 0x3F];';
 637                      $limit = $actions[$limit];
 638                  }
 639              }
 640  
 641              $encrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
 642  
 643              // Create code for decryption.
 644              $limit = 44;
 645              $actions = array($limit => 20, 20 => 0);
 646              $j = 64;
 647  
 648              for (;;) {
 649                  // R-mixing round.
 650                  $decrypt_block .= '
 651                      $r3 = ($r3 | ($r3 << 16)) >> 5;
 652                      $r3 = ($r3 - ' . $keys[--$j] . ' -
 653                             ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
 654                      $r2 = ($r2 | ($r2 << 16)) >> 3;
 655                      $r2 = ($r2 - ' . $keys[--$j] . ' -
 656                             ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
 657                      $r1 = ($r1 | ($r1 << 16)) >> 2;
 658                      $r1 = ($r1 - ' . $keys[--$j] . ' -
 659                             ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
 660                      $r0 = ($r0 | ($r0 << 16)) >> 1;
 661                      $r0 = ($r0 - ' . $keys[--$j] . ' -
 662                             ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;';
 663  
 664                  if ($j === $limit) {
 665                      if ($limit === 0) {
 666                          break;
 667                      }
 668  
 669                      // R-mashing round.
 670                      $decrypt_block .= '
 671                          $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
 672                          $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
 673                          $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
 674                          $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;';
 675                      $limit = $actions[$limit];
 676                  }
 677              }
 678  
 679              $decrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
 680  
 681              // Creates the inline-crypt function
 682              $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
 683                  array(
 684                     'init_crypt'    => $init_crypt,
 685                     'encrypt_block' => $encrypt_block,
 686                     'decrypt_block' => $decrypt_block
 687                  )
 688              );
 689          }
 690  
 691          // Set the inline-crypt function as callback in: $this->inline_crypt
 692          $this->inline_crypt = $lambda_functions[$code_hash];
 693      }
 694  }