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 34namespace phpseclib3\Crypt; 35 36use phpseclib3\Crypt\Common\BlockCipher; 37use phpseclib3\Exception\BadModeException; 38 39/** 40 * Pure-PHP implementation of RC2. 41 * 42 */ 43class 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} 641