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