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 36namespace phpseclib\Crypt; 37 38/** 39 * Pure-PHP implementation of RC2. 40 * 41 * @package RC2 42 * @access public 43 */ 44class 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} 689