1<?php 2 3/** 4 * Base Class for all \phpseclib\Crypt\* cipher classes 5 * 6 * PHP version 5 7 * 8 * Internally for phpseclib developers: 9 * If you plan to add a new cipher class, please note following rules: 10 * 11 * - The new \phpseclib\Crypt\* cipher class should extend \phpseclib\Crypt\Base 12 * 13 * - Following methods are then required to be overridden/overloaded: 14 * 15 * - _encryptBlock() 16 * 17 * - _decryptBlock() 18 * 19 * - _setupKey() 20 * 21 * - All other methods are optional to be overridden/overloaded 22 * 23 * - Look at the source code of the current ciphers how they extend \phpseclib\Crypt\Base 24 * and take one of them as a start up for the new cipher class. 25 * 26 * - Please read all the other comments/notes/hints here also for each class var/method 27 * 28 * @category Crypt 29 * @package Base 30 * @author Jim Wigginton <terrafrost@php.net> 31 * @author Hans-Juergen Petrich <petrich@tronic-media.com> 32 * @copyright 2007 Jim Wigginton 33 * @license http://www.opensource.org/licenses/mit-license.html MIT License 34 * @link http://phpseclib.sourceforge.net 35 */ 36 37namespace phpseclib\Crypt; 38 39/** 40 * Base Class for all \phpseclib\Crypt\* cipher classes 41 * 42 * @package Base 43 * @author Jim Wigginton <terrafrost@php.net> 44 * @author Hans-Juergen Petrich <petrich@tronic-media.com> 45 */ 46abstract class Base 47{ 48 /**#@+ 49 * @access public 50 * @see \phpseclib\Crypt\Base::encrypt() 51 * @see \phpseclib\Crypt\Base::decrypt() 52 */ 53 /** 54 * Encrypt / decrypt using the Counter mode. 55 * 56 * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. 57 * 58 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 59 */ 60 const MODE_CTR = -1; 61 /** 62 * Encrypt / decrypt using the Electronic Code Book mode. 63 * 64 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 65 */ 66 const MODE_ECB = 1; 67 /** 68 * Encrypt / decrypt using the Code Book Chaining mode. 69 * 70 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 71 */ 72 const MODE_CBC = 2; 73 /** 74 * Encrypt / decrypt using the Cipher Feedback mode. 75 * 76 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 77 */ 78 const MODE_CFB = 3; 79 /** 80 * Encrypt / decrypt using the Cipher Feedback mode (8bit) 81 */ 82 const MODE_CFB8 = 38; 83 /** 84 * Encrypt / decrypt using the Output Feedback mode. 85 * 86 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 87 */ 88 const MODE_OFB = 4; 89 /** 90 * Encrypt / decrypt using streaming mode. 91 */ 92 const MODE_STREAM = 5; 93 /**#@-*/ 94 95 /** 96 * Whirlpool available flag 97 * 98 * @see \phpseclib\Crypt\Base::_hashInlineCryptFunction() 99 * @var bool 100 * @access private 101 */ 102 static $WHIRLPOOL_AVAILABLE; 103 104 /**#@+ 105 * @access private 106 * @see \phpseclib\Crypt\Base::__construct() 107 */ 108 /** 109 * Base value for the internal implementation $engine switch 110 */ 111 const ENGINE_INTERNAL = 1; 112 /** 113 * Base value for the mcrypt implementation $engine switch 114 */ 115 const ENGINE_MCRYPT = 2; 116 /** 117 * Base value for the mcrypt implementation $engine switch 118 */ 119 const ENGINE_OPENSSL = 3; 120 /**#@-*/ 121 122 /** 123 * The Encryption Mode 124 * 125 * @see self::__construct() 126 * @var int 127 * @access private 128 */ 129 var $mode; 130 131 /** 132 * The Block Length of the block cipher 133 * 134 * @var int 135 * @access private 136 */ 137 var $block_size = 16; 138 139 /** 140 * The Key 141 * 142 * @see self::setKey() 143 * @var string 144 * @access private 145 */ 146 var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 147 148 /** 149 * The Initialization Vector 150 * 151 * @see self::setIV() 152 * @var string 153 * @access private 154 */ 155 var $iv; 156 157 /** 158 * A "sliding" Initialization Vector 159 * 160 * @see self::enableContinuousBuffer() 161 * @see self::_clearBuffers() 162 * @var string 163 * @access private 164 */ 165 var $encryptIV; 166 167 /** 168 * A "sliding" Initialization Vector 169 * 170 * @see self::enableContinuousBuffer() 171 * @see self::_clearBuffers() 172 * @var string 173 * @access private 174 */ 175 var $decryptIV; 176 177 /** 178 * Continuous Buffer status 179 * 180 * @see self::enableContinuousBuffer() 181 * @var bool 182 * @access private 183 */ 184 var $continuousBuffer = false; 185 186 /** 187 * Encryption buffer for CTR, OFB and CFB modes 188 * 189 * @see self::encrypt() 190 * @see self::_clearBuffers() 191 * @var array 192 * @access private 193 */ 194 var $enbuffer; 195 196 /** 197 * Decryption buffer for CTR, OFB and CFB modes 198 * 199 * @see self::decrypt() 200 * @see self::_clearBuffers() 201 * @var array 202 * @access private 203 */ 204 var $debuffer; 205 206 /** 207 * mcrypt resource for encryption 208 * 209 * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. 210 * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. 211 * 212 * @see self::encrypt() 213 * @var resource 214 * @access private 215 */ 216 var $enmcrypt; 217 218 /** 219 * mcrypt resource for decryption 220 * 221 * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. 222 * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. 223 * 224 * @see self::decrypt() 225 * @var resource 226 * @access private 227 */ 228 var $demcrypt; 229 230 /** 231 * Does the enmcrypt resource need to be (re)initialized? 232 * 233 * @see \phpseclib\Crypt\Twofish::setKey() 234 * @see \phpseclib\Crypt\Twofish::setIV() 235 * @var bool 236 * @access private 237 */ 238 var $enchanged = true; 239 240 /** 241 * Does the demcrypt resource need to be (re)initialized? 242 * 243 * @see \phpseclib\Crypt\Twofish::setKey() 244 * @see \phpseclib\Crypt\Twofish::setIV() 245 * @var bool 246 * @access private 247 */ 248 var $dechanged = true; 249 250 /** 251 * mcrypt resource for CFB mode 252 * 253 * mcrypt's CFB mode, in (and only in) buffered context, 254 * is broken, so phpseclib implements the CFB mode by it self, 255 * even when the mcrypt php extension is available. 256 * 257 * In order to do the CFB-mode work (fast) phpseclib 258 * use a separate ECB-mode mcrypt resource. 259 * 260 * @link http://phpseclib.sourceforge.net/cfb-demo.phps 261 * @see self::encrypt() 262 * @see self::decrypt() 263 * @see self::_setupMcrypt() 264 * @var resource 265 * @access private 266 */ 267 var $ecb; 268 269 /** 270 * Optimizing value while CFB-encrypting 271 * 272 * Only relevant if $continuousBuffer enabled 273 * and $engine == self::ENGINE_MCRYPT 274 * 275 * It's faster to re-init $enmcrypt if 276 * $buffer bytes > $cfb_init_len than 277 * using the $ecb resource furthermore. 278 * 279 * This value depends of the chosen cipher 280 * and the time it would be needed for it's 281 * initialization [by mcrypt_generic_init()] 282 * which, typically, depends on the complexity 283 * on its internaly Key-expanding algorithm. 284 * 285 * @see self::encrypt() 286 * @var int 287 * @access private 288 */ 289 var $cfb_init_len = 600; 290 291 /** 292 * Does internal cipher state need to be (re)initialized? 293 * 294 * @see self::setKey() 295 * @see self::setIV() 296 * @see self::disableContinuousBuffer() 297 * @var bool 298 * @access private 299 */ 300 var $changed = true; 301 302 /** 303 * Padding status 304 * 305 * @see self::enablePadding() 306 * @var bool 307 * @access private 308 */ 309 var $padding = true; 310 311 /** 312 * Is the mode one that is paddable? 313 * 314 * @see self::__construct() 315 * @var bool 316 * @access private 317 */ 318 var $paddable = false; 319 320 /** 321 * Holds which crypt engine internaly should be use, 322 * which will be determined automatically on __construct() 323 * 324 * Currently available $engines are: 325 * - self::ENGINE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required) 326 * - self::ENGINE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required) 327 * - self::ENGINE_INTERNAL (slower, pure php-engine, no php-extension required) 328 * 329 * @see self::_setEngine() 330 * @see self::encrypt() 331 * @see self::decrypt() 332 * @var int 333 * @access private 334 */ 335 var $engine; 336 337 /** 338 * Holds the preferred crypt engine 339 * 340 * @see self::_setEngine() 341 * @see self::setPreferredEngine() 342 * @var int 343 * @access private 344 */ 345 var $preferredEngine; 346 347 /** 348 * The mcrypt specific name of the cipher 349 * 350 * Only used if $engine == self::ENGINE_MCRYPT 351 * 352 * @link http://www.php.net/mcrypt_module_open 353 * @link http://www.php.net/mcrypt_list_algorithms 354 * @see self::_setupMcrypt() 355 * @var string 356 * @access private 357 */ 358 var $cipher_name_mcrypt; 359 360 /** 361 * The openssl specific name of the cipher 362 * 363 * Only used if $engine == self::ENGINE_OPENSSL 364 * 365 * @link http://www.php.net/openssl-get-cipher-methods 366 * @var string 367 * @access private 368 */ 369 var $cipher_name_openssl; 370 371 /** 372 * The openssl specific name of the cipher in ECB mode 373 * 374 * If OpenSSL does not support the mode we're trying to use (CTR) 375 * it can still be emulated with ECB mode. 376 * 377 * @link http://www.php.net/openssl-get-cipher-methods 378 * @var string 379 * @access private 380 */ 381 var $cipher_name_openssl_ecb; 382 383 /** 384 * The default salt used by setPassword() 385 * 386 * @see self::setPassword() 387 * @var string 388 * @access private 389 */ 390 var $password_default_salt = 'phpseclib/salt'; 391 392 /** 393 * The name of the performance-optimized callback function 394 * 395 * Used by encrypt() / decrypt() 396 * only if $engine == self::ENGINE_INTERNAL 397 * 398 * @see self::encrypt() 399 * @see self::decrypt() 400 * @see self::_setupInlineCrypt() 401 * @see self::$use_inline_crypt 402 * @var Callback 403 * @access private 404 */ 405 var $inline_crypt; 406 407 /** 408 * Holds whether performance-optimized $inline_crypt() can/should be used. 409 * 410 * @see self::encrypt() 411 * @see self::decrypt() 412 * @see self::inline_crypt 413 * @var mixed 414 * @access private 415 */ 416 var $use_inline_crypt; 417 418 /** 419 * If OpenSSL can be used in ECB but not in CTR we can emulate CTR 420 * 421 * @see self::_openssl_ctr_process() 422 * @var bool 423 * @access private 424 */ 425 var $openssl_emulate_ctr = false; 426 427 /** 428 * Determines what options are passed to openssl_encrypt/decrypt 429 * 430 * @see self::isValidEngine() 431 * @var mixed 432 * @access private 433 */ 434 var $openssl_options; 435 436 /** 437 * Has the key length explicitly been set or should it be derived from the key, itself? 438 * 439 * @see self::setKeyLength() 440 * @var bool 441 * @access private 442 */ 443 var $explicit_key_length = false; 444 445 /** 446 * Don't truncate / null pad key 447 * 448 * @see self::_clearBuffers() 449 * @var bool 450 * @access private 451 */ 452 var $skip_key_adjustment = false; 453 454 /** 455 * Default Constructor. 456 * 457 * Determines whether or not the mcrypt extension should be used. 458 * 459 * $mode could be: 460 * 461 * - self::MODE_ECB 462 * 463 * - self::MODE_CBC 464 * 465 * - self::MODE_CTR 466 * 467 * - self::MODE_CFB 468 * 469 * - self::MODE_OFB 470 * 471 * If not explicitly set, self::MODE_CBC will be used. 472 * 473 * @param int $mode 474 * @access public 475 */ 476 function __construct($mode = self::MODE_CBC) 477 { 478 // $mode dependent settings 479 switch ($mode) { 480 case self::MODE_ECB: 481 $this->paddable = true; 482 $this->mode = self::MODE_ECB; 483 break; 484 case self::MODE_CTR: 485 case self::MODE_CFB: 486 case self::MODE_CFB8: 487 case self::MODE_OFB: 488 case self::MODE_STREAM: 489 $this->mode = $mode; 490 break; 491 case self::MODE_CBC: 492 default: 493 $this->paddable = true; 494 $this->mode = self::MODE_CBC; 495 } 496 497 $this->_setEngine(); 498 499 // Determining whether inline crypting can be used by the cipher 500 if ($this->use_inline_crypt !== false) { 501 $this->use_inline_crypt = version_compare(PHP_VERSION, '5.3.0') >= 0 || function_exists('create_function'); 502 } 503 } 504 505 /** 506 * Sets the initialization vector. (optional) 507 * 508 * SetIV is not required when self::MODE_ECB (or ie for AES: \phpseclib\Crypt\AES::MODE_ECB) is being used. If not explicitly set, it'll be assumed 509 * to be all zero's. 510 * 511 * @access public 512 * @param string $iv 513 * @internal Can be overwritten by a sub class, but does not have to be 514 */ 515 function setIV($iv) 516 { 517 if ($this->mode == self::MODE_ECB) { 518 return; 519 } 520 521 $this->iv = $iv; 522 $this->changed = true; 523 } 524 525 /** 526 * Sets the key length. 527 * 528 * Keys with explicitly set lengths need to be treated accordingly 529 * 530 * @access public 531 * @param int $length 532 */ 533 function setKeyLength($length) 534 { 535 $this->explicit_key_length = true; 536 $this->changed = true; 537 $this->_setEngine(); 538 } 539 540 /** 541 * Returns the current key length in bits 542 * 543 * @access public 544 * @return int 545 */ 546 function getKeyLength() 547 { 548 return $this->key_length << 3; 549 } 550 551 /** 552 * Returns the current block length in bits 553 * 554 * @access public 555 * @return int 556 */ 557 function getBlockLength() 558 { 559 return $this->block_size << 3; 560 } 561 562 /** 563 * Sets the key. 564 * 565 * The min/max length(s) of the key depends on the cipher which is used. 566 * If the key not fits the length(s) of the cipher it will paded with null bytes 567 * up to the closest valid key length. If the key is more than max length, 568 * we trim the excess bits. 569 * 570 * If the key is not explicitly set, it'll be assumed to be all null bytes. 571 * 572 * @access public 573 * @param string $key 574 * @internal Could, but not must, extend by the child Crypt_* class 575 */ 576 function setKey($key) 577 { 578 if (!$this->explicit_key_length) { 579 $this->setKeyLength(strlen($key) << 3); 580 $this->explicit_key_length = false; 581 } 582 583 $this->key = $key; 584 $this->changed = true; 585 $this->_setEngine(); 586 } 587 588 /** 589 * Sets the password. 590 * 591 * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: 592 * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1: 593 * $hash, $salt, $count, $dkLen 594 * 595 * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php 596 * 597 * @see Crypt/Hash.php 598 * @param string $password 599 * @param string $method 600 * @return bool 601 * @access public 602 * @internal Could, but not must, extend by the child Crypt_* class 603 */ 604 function setPassword($password, $method = 'pbkdf2') 605 { 606 $key = ''; 607 608 switch ($method) { 609 default: // 'pbkdf2' or 'pbkdf1' 610 $func_args = func_get_args(); 611 612 // Hash function 613 $hash = isset($func_args[2]) ? $func_args[2] : 'sha1'; 614 615 // WPA and WPA2 use the SSID as the salt 616 $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt; 617 618 // RFC2898#section-4.2 uses 1,000 iterations by default 619 // WPA and WPA2 use 4,096. 620 $count = isset($func_args[4]) ? $func_args[4] : 1000; 621 622 // Keylength 623 if (isset($func_args[5])) { 624 $dkLen = $func_args[5]; 625 } else { 626 $dkLen = $method == 'pbkdf1' ? 2 * $this->key_length : $this->key_length; 627 } 628 629 switch (true) { 630 case $method == 'pbkdf1': 631 $hashObj = new Hash(); 632 $hashObj->setHash($hash); 633 if ($dkLen > $hashObj->getLength()) { 634 user_error('Derived key too long'); 635 return false; 636 } 637 $t = $password . $salt; 638 for ($i = 0; $i < $count; ++$i) { 639 $t = $hashObj->hash($t); 640 } 641 $key = substr($t, 0, $dkLen); 642 643 $this->setKey(substr($key, 0, $dkLen >> 1)); 644 $this->setIV(substr($key, $dkLen >> 1)); 645 646 return true; 647 // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable 648 case !function_exists('hash_pbkdf2'): 649 case !function_exists('hash_algos'): 650 case !in_array($hash, hash_algos()): 651 $i = 1; 652 $hmac = new Hash(); 653 $hmac->setHash($hash); 654 $hmac->setKey($password); 655 while (strlen($key) < $dkLen) { 656 $f = $u = $hmac->hash($salt . pack('N', $i++)); 657 for ($j = 2; $j <= $count; ++$j) { 658 $u = $hmac->hash($u); 659 $f^= $u; 660 } 661 $key.= $f; 662 } 663 $key = substr($key, 0, $dkLen); 664 break; 665 default: 666 $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true); 667 } 668 } 669 670 $this->setKey($key); 671 672 return true; 673 } 674 675 /** 676 * Encrypts a message. 677 * 678 * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher 679 * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's 680 * necessary are discussed in the following 681 * URL: 682 * 683 * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} 684 * 685 * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. 686 * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that 687 * length. 688 * 689 * @see self::decrypt() 690 * @access public 691 * @param string $plaintext 692 * @return string $ciphertext 693 * @internal Could, but not must, extend by the child Crypt_* class 694 */ 695 function encrypt($plaintext) 696 { 697 if ($this->paddable) { 698 $plaintext = $this->_pad($plaintext); 699 } 700 701 if ($this->engine === self::ENGINE_OPENSSL) { 702 if ($this->changed) { 703 $this->_clearBuffers(); 704 $this->changed = false; 705 } 706 switch ($this->mode) { 707 case self::MODE_STREAM: 708 return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options); 709 case self::MODE_ECB: 710 $result = @openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options); 711 return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result; 712 case self::MODE_CBC: 713 $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV); 714 if (!defined('OPENSSL_RAW_DATA')) { 715 $result = substr($result, 0, -$this->block_size); 716 } 717 if ($this->continuousBuffer) { 718 $this->encryptIV = substr($result, -$this->block_size); 719 } 720 return $result; 721 case self::MODE_CTR: 722 return $this->_openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer); 723 case self::MODE_CFB: 724 // cfb loosely routines inspired by openssl's: 725 // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1} 726 $ciphertext = ''; 727 if ($this->continuousBuffer) { 728 $iv = &$this->encryptIV; 729 $pos = &$this->enbuffer['pos']; 730 } else { 731 $iv = $this->encryptIV; 732 $pos = 0; 733 } 734 $len = strlen($plaintext); 735 $i = 0; 736 if ($pos) { 737 $orig_pos = $pos; 738 $max = $this->block_size - $pos; 739 if ($len >= $max) { 740 $i = $max; 741 $len-= $max; 742 $pos = 0; 743 } else { 744 $i = $len; 745 $pos+= $len; 746 $len = 0; 747 } 748 // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize 749 $ciphertext = substr($iv, $orig_pos) ^ $plaintext; 750 $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); 751 $plaintext = substr($plaintext, $i); 752 } 753 754 $overflow = $len % $this->block_size; 755 756 if ($overflow) { 757 $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv); 758 $iv = $this->_string_pop($ciphertext, $this->block_size); 759 760 $size = $len - $overflow; 761 $block = $iv ^ substr($plaintext, -$overflow); 762 $iv = substr_replace($iv, $block, 0, $overflow); 763 $ciphertext.= $block; 764 $pos = $overflow; 765 } elseif ($len) { 766 $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv); 767 $iv = substr($ciphertext, -$this->block_size); 768 } 769 770 return $ciphertext; 771 case self::MODE_CFB8: 772 $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV); 773 if ($this->continuousBuffer) { 774 if (($len = strlen($ciphertext)) >= $this->block_size) { 775 $this->encryptIV = substr($ciphertext, -$this->block_size); 776 } else { 777 $this->encryptIV = substr($this->encryptIV, $len - $this->block_size) . substr($ciphertext, -$len); 778 } 779 } 780 return $ciphertext; 781 case self::MODE_OFB: 782 return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer); 783 } 784 } 785 786 if ($this->engine === self::ENGINE_MCRYPT) { 787 if ($this->changed) { 788 $this->_setupMcrypt(); 789 $this->changed = false; 790 } 791 if ($this->enchanged) { 792 @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); 793 $this->enchanged = false; 794 } 795 796 // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps} 797 // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's 798 // rewritten CFB implementation the above outputs the same thing twice. 799 if ($this->mode == self::MODE_CFB && $this->continuousBuffer) { 800 $block_size = $this->block_size; 801 $iv = &$this->encryptIV; 802 $pos = &$this->enbuffer['pos']; 803 $len = strlen($plaintext); 804 $ciphertext = ''; 805 $i = 0; 806 if ($pos) { 807 $orig_pos = $pos; 808 $max = $block_size - $pos; 809 if ($len >= $max) { 810 $i = $max; 811 $len-= $max; 812 $pos = 0; 813 } else { 814 $i = $len; 815 $pos+= $len; 816 $len = 0; 817 } 818 $ciphertext = substr($iv, $orig_pos) ^ $plaintext; 819 $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); 820 $this->enbuffer['enmcrypt_init'] = true; 821 } 822 if ($len >= $block_size) { 823 if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) { 824 if ($this->enbuffer['enmcrypt_init'] === true) { 825 @mcrypt_generic_init($this->enmcrypt, $this->key, $iv); 826 $this->enbuffer['enmcrypt_init'] = false; 827 } 828 $ciphertext.= @mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size)); 829 $iv = substr($ciphertext, -$block_size); 830 $len%= $block_size; 831 } else { 832 while ($len >= $block_size) { 833 $iv = @mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size); 834 $ciphertext.= $iv; 835 $len-= $block_size; 836 $i+= $block_size; 837 } 838 } 839 } 840 841 if ($len) { 842 $iv = @mcrypt_generic($this->ecb, $iv); 843 $block = $iv ^ substr($plaintext, -$len); 844 $iv = substr_replace($iv, $block, 0, $len); 845 $ciphertext.= $block; 846 $pos = $len; 847 } 848 849 return $ciphertext; 850 } 851 852 $ciphertext = @mcrypt_generic($this->enmcrypt, $plaintext); 853 854 if (!$this->continuousBuffer) { 855 @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); 856 } 857 858 return $ciphertext; 859 } 860 861 if ($this->changed) { 862 $this->_setup(); 863 $this->changed = false; 864 } 865 if ($this->use_inline_crypt) { 866 $inline = $this->inline_crypt; 867 return $inline('encrypt', $this, $plaintext); 868 } 869 870 $buffer = &$this->enbuffer; 871 $block_size = $this->block_size; 872 $ciphertext = ''; 873 switch ($this->mode) { 874 case self::MODE_ECB: 875 for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { 876 $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size)); 877 } 878 break; 879 case self::MODE_CBC: 880 $xor = $this->encryptIV; 881 for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { 882 $block = substr($plaintext, $i, $block_size); 883 $block = $this->_encryptBlock($block ^ $xor); 884 $xor = $block; 885 $ciphertext.= $block; 886 } 887 if ($this->continuousBuffer) { 888 $this->encryptIV = $xor; 889 } 890 break; 891 case self::MODE_CTR: 892 $xor = $this->encryptIV; 893 if (strlen($buffer['ciphertext'])) { 894 for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { 895 $block = substr($plaintext, $i, $block_size); 896 if (strlen($block) > strlen($buffer['ciphertext'])) { 897 $buffer['ciphertext'].= $this->_encryptBlock($xor); 898 } 899 $this->_increment_str($xor); 900 $key = $this->_string_shift($buffer['ciphertext'], $block_size); 901 $ciphertext.= $block ^ $key; 902 } 903 } else { 904 for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { 905 $block = substr($plaintext, $i, $block_size); 906 $key = $this->_encryptBlock($xor); 907 $this->_increment_str($xor); 908 $ciphertext.= $block ^ $key; 909 } 910 } 911 if ($this->continuousBuffer) { 912 $this->encryptIV = $xor; 913 if ($start = strlen($plaintext) % $block_size) { 914 $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext']; 915 } 916 } 917 break; 918 case self::MODE_CFB: 919 // cfb loosely routines inspired by openssl's: 920 // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1} 921 if ($this->continuousBuffer) { 922 $iv = &$this->encryptIV; 923 $pos = &$buffer['pos']; 924 } else { 925 $iv = $this->encryptIV; 926 $pos = 0; 927 } 928 $len = strlen($plaintext); 929 $i = 0; 930 if ($pos) { 931 $orig_pos = $pos; 932 $max = $block_size - $pos; 933 if ($len >= $max) { 934 $i = $max; 935 $len-= $max; 936 $pos = 0; 937 } else { 938 $i = $len; 939 $pos+= $len; 940 $len = 0; 941 } 942 // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize 943 $ciphertext = substr($iv, $orig_pos) ^ $plaintext; 944 $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); 945 } 946 while ($len >= $block_size) { 947 $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size); 948 $ciphertext.= $iv; 949 $len-= $block_size; 950 $i+= $block_size; 951 } 952 if ($len) { 953 $iv = $this->_encryptBlock($iv); 954 $block = $iv ^ substr($plaintext, $i); 955 $iv = substr_replace($iv, $block, 0, $len); 956 $ciphertext.= $block; 957 $pos = $len; 958 } 959 break; 960 case self::MODE_CFB8: 961 $ciphertext = ''; 962 $len = strlen($plaintext); 963 $iv = $this->encryptIV; 964 965 for ($i = 0; $i < $len; ++$i) { 966 $ciphertext .= ($c = $plaintext[$i] ^ $this->_encryptBlock($iv)); 967 $iv = substr($iv, 1) . $c; 968 } 969 970 if ($this->continuousBuffer) { 971 if ($len >= $block_size) { 972 $this->encryptIV = substr($ciphertext, -$block_size); 973 } else { 974 $this->encryptIV = substr($this->encryptIV, $len - $block_size) . substr($ciphertext, -$len); 975 } 976 } 977 break; 978 case self::MODE_OFB: 979 $xor = $this->encryptIV; 980 if (strlen($buffer['xor'])) { 981 for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { 982 $block = substr($plaintext, $i, $block_size); 983 if (strlen($block) > strlen($buffer['xor'])) { 984 $xor = $this->_encryptBlock($xor); 985 $buffer['xor'].= $xor; 986 } 987 $key = $this->_string_shift($buffer['xor'], $block_size); 988 $ciphertext.= $block ^ $key; 989 } 990 } else { 991 for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { 992 $xor = $this->_encryptBlock($xor); 993 $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor; 994 } 995 $key = $xor; 996 } 997 if ($this->continuousBuffer) { 998 $this->encryptIV = $xor; 999 if ($start = strlen($plaintext) % $block_size) { 1000 $buffer['xor'] = substr($key, $start) . $buffer['xor']; 1001 } 1002 } 1003 break; 1004 case self::MODE_STREAM: 1005 $ciphertext = $this->_encryptBlock($plaintext); 1006 break; 1007 } 1008 1009 return $ciphertext; 1010 } 1011 1012 /** 1013 * Decrypts a message. 1014 * 1015 * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until 1016 * it is. 1017 * 1018 * @see self::encrypt() 1019 * @access public 1020 * @param string $ciphertext 1021 * @return string $plaintext 1022 * @internal Could, but not must, extend by the child Crypt_* class 1023 */ 1024 function decrypt($ciphertext) 1025 { 1026 if ($this->paddable) { 1027 // we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}: 1028 // "The data is padded with "\0" to make sure the length of the data is n * blocksize." 1029 $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0)); 1030 } 1031 1032 if ($this->engine === self::ENGINE_OPENSSL) { 1033 if ($this->changed) { 1034 $this->_clearBuffers(); 1035 $this->changed = false; 1036 } 1037 switch ($this->mode) { 1038 case self::MODE_STREAM: 1039 $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options); 1040 break; 1041 case self::MODE_ECB: 1042 if (!defined('OPENSSL_RAW_DATA')) { 1043 $ciphertext.= @openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true); 1044 } 1045 $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options); 1046 break; 1047 case self::MODE_CBC: 1048 if (!defined('OPENSSL_RAW_DATA')) { 1049 $padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size); 1050 $ciphertext.= substr(@openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size); 1051 $offset = 2 * $this->block_size; 1052 } else { 1053 $offset = $this->block_size; 1054 } 1055 $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV); 1056 if ($this->continuousBuffer) { 1057 $this->decryptIV = substr($ciphertext, -$offset, $this->block_size); 1058 } 1059 break; 1060 case self::MODE_CTR: 1061 $plaintext = $this->_openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer); 1062 break; 1063 case self::MODE_CFB: 1064 // cfb loosely routines inspired by openssl's: 1065 // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1} 1066 $plaintext = ''; 1067 if ($this->continuousBuffer) { 1068 $iv = &$this->decryptIV; 1069 $pos = &$this->buffer['pos']; 1070 } else { 1071 $iv = $this->decryptIV; 1072 $pos = 0; 1073 } 1074 $len = strlen($ciphertext); 1075 $i = 0; 1076 if ($pos) { 1077 $orig_pos = $pos; 1078 $max = $this->block_size - $pos; 1079 if ($len >= $max) { 1080 $i = $max; 1081 $len-= $max; 1082 $pos = 0; 1083 } else { 1084 $i = $len; 1085 $pos+= $len; 1086 $len = 0; 1087 } 1088 // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $this->blocksize 1089 $plaintext = substr($iv, $orig_pos) ^ $ciphertext; 1090 $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); 1091 $ciphertext = substr($ciphertext, $i); 1092 } 1093 $overflow = $len % $this->block_size; 1094 if ($overflow) { 1095 $plaintext.= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv); 1096 if ($len - $overflow) { 1097 $iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow); 1098 } 1099 $iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv); 1100 $plaintext.= $iv ^ substr($ciphertext, -$overflow); 1101 $iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow); 1102 $pos = $overflow; 1103 } elseif ($len) { 1104 $plaintext.= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv); 1105 $iv = substr($ciphertext, -$this->block_size); 1106 } 1107 break; 1108 case self::MODE_CFB8: 1109 $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV); 1110 if ($this->continuousBuffer) { 1111 if (($len = strlen($ciphertext)) >= $this->block_size) { 1112 $this->decryptIV = substr($ciphertext, -$this->block_size); 1113 } else { 1114 $this->decryptIV = substr($this->decryptIV, $len - $this->block_size) . substr($ciphertext, -$len); 1115 } 1116 } 1117 break; 1118 case self::MODE_OFB: 1119 $plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer); 1120 } 1121 1122 return $this->paddable ? $this->_unpad($plaintext) : $plaintext; 1123 } 1124 1125 if ($this->engine === self::ENGINE_MCRYPT) { 1126 $block_size = $this->block_size; 1127 if ($this->changed) { 1128 $this->_setupMcrypt(); 1129 $this->changed = false; 1130 } 1131 if ($this->dechanged) { 1132 @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); 1133 $this->dechanged = false; 1134 } 1135 1136 if ($this->mode == self::MODE_CFB && $this->continuousBuffer) { 1137 $iv = &$this->decryptIV; 1138 $pos = &$this->debuffer['pos']; 1139 $len = strlen($ciphertext); 1140 $plaintext = ''; 1141 $i = 0; 1142 if ($pos) { 1143 $orig_pos = $pos; 1144 $max = $block_size - $pos; 1145 if ($len >= $max) { 1146 $i = $max; 1147 $len-= $max; 1148 $pos = 0; 1149 } else { 1150 $i = $len; 1151 $pos+= $len; 1152 $len = 0; 1153 } 1154 // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize 1155 $plaintext = substr($iv, $orig_pos) ^ $ciphertext; 1156 $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); 1157 } 1158 if ($len >= $block_size) { 1159 $cb = substr($ciphertext, $i, $len - $len % $block_size); 1160 $plaintext.= @mcrypt_generic($this->ecb, $iv . $cb) ^ $cb; 1161 $iv = substr($cb, -$block_size); 1162 $len%= $block_size; 1163 } 1164 if ($len) { 1165 $iv = @mcrypt_generic($this->ecb, $iv); 1166 $plaintext.= $iv ^ substr($ciphertext, -$len); 1167 $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len); 1168 $pos = $len; 1169 } 1170 1171 return $plaintext; 1172 } 1173 1174 $plaintext = @mdecrypt_generic($this->demcrypt, $ciphertext); 1175 1176 if (!$this->continuousBuffer) { 1177 @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); 1178 } 1179 1180 return $this->paddable ? $this->_unpad($plaintext) : $plaintext; 1181 } 1182 1183 if ($this->changed) { 1184 $this->_setup(); 1185 $this->changed = false; 1186 } 1187 if ($this->use_inline_crypt) { 1188 $inline = $this->inline_crypt; 1189 return $inline('decrypt', $this, $ciphertext); 1190 } 1191 1192 $block_size = $this->block_size; 1193 1194 $buffer = &$this->debuffer; 1195 $plaintext = ''; 1196 switch ($this->mode) { 1197 case self::MODE_ECB: 1198 for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { 1199 $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size)); 1200 } 1201 break; 1202 case self::MODE_CBC: 1203 $xor = $this->decryptIV; 1204 for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { 1205 $block = substr($ciphertext, $i, $block_size); 1206 $plaintext.= $this->_decryptBlock($block) ^ $xor; 1207 $xor = $block; 1208 } 1209 if ($this->continuousBuffer) { 1210 $this->decryptIV = $xor; 1211 } 1212 break; 1213 case self::MODE_CTR: 1214 $xor = $this->decryptIV; 1215 if (strlen($buffer['ciphertext'])) { 1216 for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { 1217 $block = substr($ciphertext, $i, $block_size); 1218 if (strlen($block) > strlen($buffer['ciphertext'])) { 1219 $buffer['ciphertext'].= $this->_encryptBlock($xor); 1220 $this->_increment_str($xor); 1221 } 1222 $key = $this->_string_shift($buffer['ciphertext'], $block_size); 1223 $plaintext.= $block ^ $key; 1224 } 1225 } else { 1226 for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { 1227 $block = substr($ciphertext, $i, $block_size); 1228 $key = $this->_encryptBlock($xor); 1229 $this->_increment_str($xor); 1230 $plaintext.= $block ^ $key; 1231 } 1232 } 1233 if ($this->continuousBuffer) { 1234 $this->decryptIV = $xor; 1235 if ($start = strlen($ciphertext) % $block_size) { 1236 $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext']; 1237 } 1238 } 1239 break; 1240 case self::MODE_CFB: 1241 if ($this->continuousBuffer) { 1242 $iv = &$this->decryptIV; 1243 $pos = &$buffer['pos']; 1244 } else { 1245 $iv = $this->decryptIV; 1246 $pos = 0; 1247 } 1248 $len = strlen($ciphertext); 1249 $i = 0; 1250 if ($pos) { 1251 $orig_pos = $pos; 1252 $max = $block_size - $pos; 1253 if ($len >= $max) { 1254 $i = $max; 1255 $len-= $max; 1256 $pos = 0; 1257 } else { 1258 $i = $len; 1259 $pos+= $len; 1260 $len = 0; 1261 } 1262 // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize 1263 $plaintext = substr($iv, $orig_pos) ^ $ciphertext; 1264 $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); 1265 } 1266 while ($len >= $block_size) { 1267 $iv = $this->_encryptBlock($iv); 1268 $cb = substr($ciphertext, $i, $block_size); 1269 $plaintext.= $iv ^ $cb; 1270 $iv = $cb; 1271 $len-= $block_size; 1272 $i+= $block_size; 1273 } 1274 if ($len) { 1275 $iv = $this->_encryptBlock($iv); 1276 $plaintext.= $iv ^ substr($ciphertext, $i); 1277 $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len); 1278 $pos = $len; 1279 } 1280 break; 1281 case self::MODE_CFB8: 1282 $plaintext = ''; 1283 $len = strlen($ciphertext); 1284 $iv = $this->decryptIV; 1285 1286 for ($i = 0; $i < $len; ++$i) { 1287 $plaintext .= $ciphertext[$i] ^ $this->_encryptBlock($iv); 1288 $iv = substr($iv, 1) . $ciphertext[$i]; 1289 } 1290 1291 if ($this->continuousBuffer) { 1292 if ($len >= $block_size) { 1293 $this->decryptIV = substr($ciphertext, -$block_size); 1294 } else { 1295 $this->decryptIV = substr($this->decryptIV, $len - $block_size) . substr($ciphertext, -$len); 1296 } 1297 } 1298 break; 1299 case self::MODE_OFB: 1300 $xor = $this->decryptIV; 1301 if (strlen($buffer['xor'])) { 1302 for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { 1303 $block = substr($ciphertext, $i, $block_size); 1304 if (strlen($block) > strlen($buffer['xor'])) { 1305 $xor = $this->_encryptBlock($xor); 1306 $buffer['xor'].= $xor; 1307 } 1308 $key = $this->_string_shift($buffer['xor'], $block_size); 1309 $plaintext.= $block ^ $key; 1310 } 1311 } else { 1312 for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { 1313 $xor = $this->_encryptBlock($xor); 1314 $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor; 1315 } 1316 $key = $xor; 1317 } 1318 if ($this->continuousBuffer) { 1319 $this->decryptIV = $xor; 1320 if ($start = strlen($ciphertext) % $block_size) { 1321 $buffer['xor'] = substr($key, $start) . $buffer['xor']; 1322 } 1323 } 1324 break; 1325 case self::MODE_STREAM: 1326 $plaintext = $this->_decryptBlock($ciphertext); 1327 break; 1328 } 1329 return $this->paddable ? $this->_unpad($plaintext) : $plaintext; 1330 } 1331 1332 /** 1333 * OpenSSL CTR Processor 1334 * 1335 * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream 1336 * for CTR is the same for both encrypting and decrypting this function is re-used by both Base::encrypt() 1337 * and Base::decrypt(). Also, OpenSSL doesn't implement CTR for all of it's symmetric ciphers so this 1338 * function will emulate CTR with ECB when necessary. 1339 * 1340 * @see self::encrypt() 1341 * @see self::decrypt() 1342 * @param string $plaintext 1343 * @param string $encryptIV 1344 * @param array $buffer 1345 * @return string 1346 * @access private 1347 */ 1348 function _openssl_ctr_process($plaintext, &$encryptIV, &$buffer) 1349 { 1350 $ciphertext = ''; 1351 1352 $block_size = $this->block_size; 1353 $key = $this->key; 1354 1355 if ($this->openssl_emulate_ctr) { 1356 $xor = $encryptIV; 1357 if (strlen($buffer['ciphertext'])) { 1358 for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { 1359 $block = substr($plaintext, $i, $block_size); 1360 if (strlen($block) > strlen($buffer['ciphertext'])) { 1361 $result = @openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options); 1362 $result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result; 1363 $buffer['ciphertext'].= $result; 1364 } 1365 $this->_increment_str($xor); 1366 $otp = $this->_string_shift($buffer['ciphertext'], $block_size); 1367 $ciphertext.= $block ^ $otp; 1368 } 1369 } else { 1370 for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { 1371 $block = substr($plaintext, $i, $block_size); 1372 $otp = @openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options); 1373 $otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp; 1374 $this->_increment_str($xor); 1375 $ciphertext.= $block ^ $otp; 1376 } 1377 } 1378 if ($this->continuousBuffer) { 1379 $encryptIV = $xor; 1380 if ($start = strlen($plaintext) % $block_size) { 1381 $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext']; 1382 } 1383 } 1384 1385 return $ciphertext; 1386 } 1387 1388 if (strlen($buffer['ciphertext'])) { 1389 $ciphertext = $plaintext ^ $this->_string_shift($buffer['ciphertext'], strlen($plaintext)); 1390 $plaintext = substr($plaintext, strlen($ciphertext)); 1391 1392 if (!strlen($plaintext)) { 1393 return $ciphertext; 1394 } 1395 } 1396 1397 $overflow = strlen($plaintext) % $block_size; 1398 if ($overflow) { 1399 $plaintext2 = $this->_string_pop($plaintext, $overflow); // ie. trim $plaintext to a multiple of $block_size and put rest of $plaintext in $plaintext2 1400 $encrypted = openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV); 1401 $temp = $this->_string_pop($encrypted, $block_size); 1402 $ciphertext.= $encrypted . ($plaintext2 ^ $temp); 1403 if ($this->continuousBuffer) { 1404 $buffer['ciphertext'] = substr($temp, $overflow); 1405 $encryptIV = $temp; 1406 } 1407 } elseif (!strlen($buffer['ciphertext'])) { 1408 $ciphertext.= openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV); 1409 $temp = $this->_string_pop($ciphertext, $block_size); 1410 if ($this->continuousBuffer) { 1411 $encryptIV = $temp; 1412 } 1413 } 1414 if ($this->continuousBuffer) { 1415 if (!defined('OPENSSL_RAW_DATA')) { 1416 $encryptIV.= @openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options); 1417 } 1418 $encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options); 1419 if ($overflow) { 1420 $this->_increment_str($encryptIV); 1421 } 1422 } 1423 1424 return $ciphertext; 1425 } 1426 1427 /** 1428 * OpenSSL OFB Processor 1429 * 1430 * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream 1431 * for OFB is the same for both encrypting and decrypting this function is re-used by both Base::encrypt() 1432 * and Base::decrypt(). 1433 * 1434 * @see self::encrypt() 1435 * @see self::decrypt() 1436 * @param string $plaintext 1437 * @param string $encryptIV 1438 * @param array $buffer 1439 * @return string 1440 * @access private 1441 */ 1442 function _openssl_ofb_process($plaintext, &$encryptIV, &$buffer) 1443 { 1444 if (strlen($buffer['xor'])) { 1445 $ciphertext = $plaintext ^ $buffer['xor']; 1446 $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); 1447 $plaintext = substr($plaintext, strlen($ciphertext)); 1448 } else { 1449 $ciphertext = ''; 1450 } 1451 1452 $block_size = $this->block_size; 1453 1454 $len = strlen($plaintext); 1455 $key = $this->key; 1456 $overflow = $len % $block_size; 1457 1458 if (strlen($plaintext)) { 1459 if ($overflow) { 1460 $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV); 1461 $xor = $this->_string_pop($ciphertext, $block_size); 1462 if ($this->continuousBuffer) { 1463 $encryptIV = $xor; 1464 } 1465 $ciphertext.= $this->_string_shift($xor, $overflow) ^ substr($plaintext, -$overflow); 1466 if ($this->continuousBuffer) { 1467 $buffer['xor'] = $xor; 1468 } 1469 } else { 1470 $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV); 1471 if ($this->continuousBuffer) { 1472 $encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size); 1473 } 1474 } 1475 } 1476 1477 return $ciphertext; 1478 } 1479 1480 /** 1481 * phpseclib <-> OpenSSL Mode Mapper 1482 * 1483 * May need to be overwritten by classes extending this one in some cases 1484 * 1485 * @return int 1486 * @access private 1487 */ 1488 function _openssl_translate_mode() 1489 { 1490 switch ($this->mode) { 1491 case self::MODE_ECB: 1492 return 'ecb'; 1493 case self::MODE_CBC: 1494 return 'cbc'; 1495 case self::MODE_CTR: 1496 return 'ctr'; 1497 case self::MODE_CFB: 1498 return 'cfb'; 1499 case self::MODE_CFB8: 1500 return 'cfb8'; 1501 case self::MODE_OFB: 1502 return 'ofb'; 1503 } 1504 } 1505 1506 /** 1507 * Pad "packets". 1508 * 1509 * Block ciphers working by encrypting between their specified [$this->]block_size at a time 1510 * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to 1511 * pad the input so that it is of the proper length. 1512 * 1513 * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH, 1514 * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping 1515 * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is 1516 * transmitted separately) 1517 * 1518 * @see self::disablePadding() 1519 * @access public 1520 */ 1521 function enablePadding() 1522 { 1523 $this->padding = true; 1524 } 1525 1526 /** 1527 * Do not pad packets. 1528 * 1529 * @see self::enablePadding() 1530 * @access public 1531 */ 1532 function disablePadding() 1533 { 1534 $this->padding = false; 1535 } 1536 1537 /** 1538 * Treat consecutive "packets" as if they are a continuous buffer. 1539 * 1540 * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets 1541 * will yield different outputs: 1542 * 1543 * <code> 1544 * echo $rijndael->encrypt(substr($plaintext, 0, 16)); 1545 * echo $rijndael->encrypt(substr($plaintext, 16, 16)); 1546 * </code> 1547 * <code> 1548 * echo $rijndael->encrypt($plaintext); 1549 * </code> 1550 * 1551 * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates 1552 * another, as demonstrated with the following: 1553 * 1554 * <code> 1555 * $rijndael->encrypt(substr($plaintext, 0, 16)); 1556 * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16))); 1557 * </code> 1558 * <code> 1559 * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16))); 1560 * </code> 1561 * 1562 * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different 1563 * outputs. The reason is due to the fact that the initialization vector's change after every encryption / 1564 * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. 1565 * 1566 * Put another way, when the continuous buffer is enabled, the state of the \phpseclib\Crypt\*() object changes after each 1567 * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that 1568 * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), 1569 * however, they are also less intuitive and more likely to cause you problems. 1570 * 1571 * @see self::disableContinuousBuffer() 1572 * @access public 1573 * @internal Could, but not must, extend by the child Crypt_* class 1574 */ 1575 function enableContinuousBuffer() 1576 { 1577 if ($this->mode == self::MODE_ECB) { 1578 return; 1579 } 1580 1581 $this->continuousBuffer = true; 1582 1583 $this->_setEngine(); 1584 } 1585 1586 /** 1587 * Treat consecutive packets as if they are a discontinuous buffer. 1588 * 1589 * The default behavior. 1590 * 1591 * @see self::enableContinuousBuffer() 1592 * @access public 1593 * @internal Could, but not must, extend by the child Crypt_* class 1594 */ 1595 function disableContinuousBuffer() 1596 { 1597 if ($this->mode == self::MODE_ECB) { 1598 return; 1599 } 1600 if (!$this->continuousBuffer) { 1601 return; 1602 } 1603 1604 $this->continuousBuffer = false; 1605 $this->changed = true; 1606 1607 $this->_setEngine(); 1608 } 1609 1610 /** 1611 * Test for engine validity 1612 * 1613 * @see self::__construct() 1614 * @param int $engine 1615 * @access public 1616 * @return bool 1617 */ 1618 function isValidEngine($engine) 1619 { 1620 switch ($engine) { 1621 case self::ENGINE_OPENSSL: 1622 if ($this->mode == self::MODE_STREAM && $this->continuousBuffer) { 1623 return false; 1624 } 1625 $this->openssl_emulate_ctr = false; 1626 $result = $this->cipher_name_openssl && 1627 extension_loaded('openssl') && 1628 // PHP 5.3.0 - 5.3.2 did not let you set IV's 1629 version_compare(PHP_VERSION, '5.3.3', '>='); 1630 if (!$result) { 1631 return false; 1632 } 1633 1634 // prior to PHP 5.4.0 OPENSSL_RAW_DATA and OPENSSL_ZERO_PADDING were not defined. instead of expecting an integer 1635 // $options openssl_encrypt expected a boolean $raw_data. 1636 if (!defined('OPENSSL_RAW_DATA')) { 1637 $this->openssl_options = true; 1638 } else { 1639 $this->openssl_options = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING; 1640 } 1641 1642 $methods = openssl_get_cipher_methods(); 1643 if (in_array($this->cipher_name_openssl, $methods)) { 1644 return true; 1645 } 1646 // not all of openssl's symmetric cipher's support ctr. for those 1647 // that don't we'll emulate it 1648 switch ($this->mode) { 1649 case self::MODE_CTR: 1650 if (in_array($this->cipher_name_openssl_ecb, $methods)) { 1651 $this->openssl_emulate_ctr = true; 1652 return true; 1653 } 1654 } 1655 return false; 1656 case self::ENGINE_MCRYPT: 1657 return $this->cipher_name_mcrypt && 1658 extension_loaded('mcrypt') && 1659 in_array($this->cipher_name_mcrypt, @mcrypt_list_algorithms()); 1660 case self::ENGINE_INTERNAL: 1661 return true; 1662 } 1663 1664 return false; 1665 } 1666 1667 /** 1668 * Sets the preferred crypt engine 1669 * 1670 * Currently, $engine could be: 1671 * 1672 * - \phpseclib\Crypt\Base::ENGINE_OPENSSL [very fast] 1673 * 1674 * - \phpseclib\Crypt\Base::ENGINE_MCRYPT [fast] 1675 * 1676 * - \phpseclib\Crypt\Base::ENGINE_INTERNAL [slow] 1677 * 1678 * If the preferred crypt engine is not available the fastest available one will be used 1679 * 1680 * @see self::__construct() 1681 * @param int $engine 1682 * @access public 1683 */ 1684 function setPreferredEngine($engine) 1685 { 1686 switch ($engine) { 1687 //case self::ENGINE_OPENSSL; 1688 case self::ENGINE_MCRYPT: 1689 case self::ENGINE_INTERNAL: 1690 $this->preferredEngine = $engine; 1691 break; 1692 default: 1693 $this->preferredEngine = self::ENGINE_OPENSSL; 1694 } 1695 1696 $this->_setEngine(); 1697 } 1698 1699 /** 1700 * Returns the engine currently being utilized 1701 * 1702 * @see self::_setEngine() 1703 * @access public 1704 */ 1705 function getEngine() 1706 { 1707 return $this->engine; 1708 } 1709 1710 /** 1711 * Sets the engine as appropriate 1712 * 1713 * @see self::__construct() 1714 * @access private 1715 */ 1716 function _setEngine() 1717 { 1718 $this->engine = null; 1719 1720 $candidateEngines = array( 1721 $this->preferredEngine, 1722 self::ENGINE_OPENSSL, 1723 self::ENGINE_MCRYPT 1724 ); 1725 foreach ($candidateEngines as $engine) { 1726 if ($this->isValidEngine($engine)) { 1727 $this->engine = $engine; 1728 break; 1729 } 1730 } 1731 if (!$this->engine) { 1732 $this->engine = self::ENGINE_INTERNAL; 1733 } 1734 1735 if ($this->engine != self::ENGINE_MCRYPT && $this->enmcrypt) { 1736 // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed, 1737 // (re)open them with the module named in $this->cipher_name_mcrypt 1738 @mcrypt_module_close($this->enmcrypt); 1739 @mcrypt_module_close($this->demcrypt); 1740 $this->enmcrypt = null; 1741 $this->demcrypt = null; 1742 1743 if ($this->ecb) { 1744 @mcrypt_module_close($this->ecb); 1745 $this->ecb = null; 1746 } 1747 } 1748 1749 $this->changed = true; 1750 } 1751 1752 /** 1753 * Encrypts a block 1754 * 1755 * Note: Must be extended by the child \phpseclib\Crypt\* class 1756 * 1757 * @access private 1758 * @param string $in 1759 * @return string 1760 */ 1761 abstract function _encryptBlock($in); 1762 1763 /** 1764 * Decrypts a block 1765 * 1766 * Note: Must be extended by the child \phpseclib\Crypt\* class 1767 * 1768 * @access private 1769 * @param string $in 1770 * @return string 1771 */ 1772 abstract function _decryptBlock($in); 1773 1774 /** 1775 * Setup the key (expansion) 1776 * 1777 * Only used if $engine == self::ENGINE_INTERNAL 1778 * 1779 * Note: Must extend by the child \phpseclib\Crypt\* class 1780 * 1781 * @see self::_setup() 1782 * @access private 1783 */ 1784 abstract function _setupKey(); 1785 1786 /** 1787 * Setup the self::ENGINE_INTERNAL $engine 1788 * 1789 * (re)init, if necessary, the internal cipher $engine and flush all $buffers 1790 * Used (only) if $engine == self::ENGINE_INTERNAL 1791 * 1792 * _setup() will be called each time if $changed === true 1793 * typically this happens when using one or more of following public methods: 1794 * 1795 * - setKey() 1796 * 1797 * - setIV() 1798 * 1799 * - disableContinuousBuffer() 1800 * 1801 * - First run of encrypt() / decrypt() with no init-settings 1802 * 1803 * @see self::setKey() 1804 * @see self::setIV() 1805 * @see self::disableContinuousBuffer() 1806 * @access private 1807 * @internal _setup() is always called before en/decryption. 1808 * @internal Could, but not must, extend by the child Crypt_* class 1809 */ 1810 function _setup() 1811 { 1812 $this->_clearBuffers(); 1813 $this->_setupKey(); 1814 1815 if ($this->use_inline_crypt) { 1816 $this->_setupInlineCrypt(); 1817 } 1818 } 1819 1820 /** 1821 * Setup the self::ENGINE_MCRYPT $engine 1822 * 1823 * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers 1824 * Used (only) if $engine = self::ENGINE_MCRYPT 1825 * 1826 * _setupMcrypt() will be called each time if $changed === true 1827 * typically this happens when using one or more of following public methods: 1828 * 1829 * - setKey() 1830 * 1831 * - setIV() 1832 * 1833 * - disableContinuousBuffer() 1834 * 1835 * - First run of encrypt() / decrypt() 1836 * 1837 * @see self::setKey() 1838 * @see self::setIV() 1839 * @see self::disableContinuousBuffer() 1840 * @access private 1841 * @internal Could, but not must, extend by the child Crypt_* class 1842 */ 1843 function _setupMcrypt() 1844 { 1845 $this->_clearBuffers(); 1846 $this->enchanged = $this->dechanged = true; 1847 1848 if (!isset($this->enmcrypt)) { 1849 static $mcrypt_modes = array( 1850 self::MODE_CTR => 'ctr', 1851 self::MODE_ECB => MCRYPT_MODE_ECB, 1852 self::MODE_CBC => MCRYPT_MODE_CBC, 1853 self::MODE_CFB => 'ncfb', 1854 self::MODE_CFB8 => MCRYPT_MODE_CFB, 1855 self::MODE_OFB => MCRYPT_MODE_NOFB, 1856 self::MODE_STREAM => MCRYPT_MODE_STREAM, 1857 ); 1858 1859 $this->demcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], ''); 1860 $this->enmcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], ''); 1861 1862 // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer() 1863 // to workaround mcrypt's broken ncfb implementation in buffered mode 1864 // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps} 1865 if ($this->mode == self::MODE_CFB) { 1866 $this->ecb = @mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, ''); 1867 } 1868 } // else should mcrypt_generic_deinit be called? 1869 1870 if ($this->mode == self::MODE_CFB) { 1871 @mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size)); 1872 } 1873 } 1874 1875 /** 1876 * Pads a string 1877 * 1878 * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize. 1879 * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to 1880 * chr($this->block_size - (strlen($text) % $this->block_size) 1881 * 1882 * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless 1883 * and padding will, hence forth, be enabled. 1884 * 1885 * @see self::_unpad() 1886 * @param string $text 1887 * @access private 1888 * @return string 1889 */ 1890 function _pad($text) 1891 { 1892 $length = strlen($text); 1893 1894 if (!$this->padding) { 1895 if ($length % $this->block_size == 0) { 1896 return $text; 1897 } else { 1898 user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})"); 1899 $this->padding = true; 1900 } 1901 } 1902 1903 $pad = $this->block_size - ($length % $this->block_size); 1904 1905 return str_pad($text, $length + $pad, chr($pad)); 1906 } 1907 1908 /** 1909 * Unpads a string. 1910 * 1911 * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong 1912 * and false will be returned. 1913 * 1914 * @see self::_pad() 1915 * @param string $text 1916 * @access private 1917 * @return string 1918 */ 1919 function _unpad($text) 1920 { 1921 if (!$this->padding) { 1922 return $text; 1923 } 1924 1925 $length = ord($text[strlen($text) - 1]); 1926 1927 if (!$length || $length > $this->block_size) { 1928 return false; 1929 } 1930 1931 return substr($text, 0, -$length); 1932 } 1933 1934 /** 1935 * Clears internal buffers 1936 * 1937 * Clearing/resetting the internal buffers is done everytime 1938 * after disableContinuousBuffer() or on cipher $engine (re)init 1939 * ie after setKey() or setIV() 1940 * 1941 * @access public 1942 * @internal Could, but not must, extend by the child Crypt_* class 1943 */ 1944 function _clearBuffers() 1945 { 1946 $this->enbuffer = $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); 1947 1948 // mcrypt's handling of invalid's $iv: 1949 // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size); 1950 $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0"); 1951 1952 if (!$this->skip_key_adjustment) { 1953 $this->key = str_pad(substr($this->key, 0, $this->key_length), $this->key_length, "\0"); 1954 } 1955 } 1956 1957 /** 1958 * String Shift 1959 * 1960 * Inspired by array_shift 1961 * 1962 * @param string $string 1963 * @param int $index 1964 * @access private 1965 * @return string 1966 */ 1967 function _string_shift(&$string, $index = 1) 1968 { 1969 $substr = substr($string, 0, $index); 1970 $string = substr($string, $index); 1971 return $substr; 1972 } 1973 1974 /** 1975 * String Pop 1976 * 1977 * Inspired by array_pop 1978 * 1979 * @param string $string 1980 * @param int $index 1981 * @access private 1982 * @return string 1983 */ 1984 function _string_pop(&$string, $index = 1) 1985 { 1986 $substr = substr($string, -$index); 1987 $string = substr($string, 0, -$index); 1988 return $substr; 1989 } 1990 1991 /** 1992 * Increment the current string 1993 * 1994 * @see self::decrypt() 1995 * @see self::encrypt() 1996 * @param string $var 1997 * @access private 1998 */ 1999 function _increment_str(&$var) 2000 { 2001 for ($i = 4; $i <= strlen($var); $i+= 4) { 2002 $temp = substr($var, -$i, 4); 2003 switch ($temp) { 2004 case "\xFF\xFF\xFF\xFF": 2005 $var = substr_replace($var, "\x00\x00\x00\x00", -$i, 4); 2006 break; 2007 case "\x7F\xFF\xFF\xFF": 2008 $var = substr_replace($var, "\x80\x00\x00\x00", -$i, 4); 2009 return; 2010 default: 2011 $temp = unpack('Nnum', $temp); 2012 $var = substr_replace($var, pack('N', $temp['num'] + 1), -$i, 4); 2013 return; 2014 } 2015 } 2016 2017 $remainder = strlen($var) % 4; 2018 2019 if ($remainder == 0) { 2020 return; 2021 } 2022 2023 $temp = unpack('Nnum', str_pad(substr($var, 0, $remainder), 4, "\0", STR_PAD_LEFT)); 2024 $temp = substr(pack('N', $temp['num'] + 1), -$remainder); 2025 $var = substr_replace($var, $temp, 0, $remainder); 2026 } 2027 2028 /** 2029 * Setup the performance-optimized function for de/encrypt() 2030 * 2031 * Stores the created (or existing) callback function-name 2032 * in $this->inline_crypt 2033 * 2034 * Internally for phpseclib developers: 2035 * 2036 * _setupInlineCrypt() would be called only if: 2037 * 2038 * - $engine == self::ENGINE_INTERNAL and 2039 * 2040 * - $use_inline_crypt === true 2041 * 2042 * - each time on _setup(), after(!) _setupKey() 2043 * 2044 * 2045 * This ensures that _setupInlineCrypt() has always a 2046 * full ready2go initializated internal cipher $engine state 2047 * where, for example, the keys allready expanded, 2048 * keys/block_size calculated and such. 2049 * 2050 * It is, each time if called, the responsibility of _setupInlineCrypt(): 2051 * 2052 * - to set $this->inline_crypt to a valid and fully working callback function 2053 * as a (faster) replacement for encrypt() / decrypt() 2054 * 2055 * - NOT to create unlimited callback functions (for memory reasons!) 2056 * no matter how often _setupInlineCrypt() would be called. At some 2057 * point of amount they must be generic re-useable. 2058 * 2059 * - the code of _setupInlineCrypt() it self, 2060 * and the generated callback code, 2061 * must be, in following order: 2062 * - 100% safe 2063 * - 100% compatible to encrypt()/decrypt() 2064 * - using only php5+ features/lang-constructs/php-extensions if 2065 * compatibility (down to php4) or fallback is provided 2066 * - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-) 2067 * - >= 10% faster than encrypt()/decrypt() [which is, by the way, 2068 * the reason for the existence of _setupInlineCrypt() :-)] 2069 * - memory-nice 2070 * - short (as good as possible) 2071 * 2072 * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code. 2073 * - In case of using inline crypting, _setupInlineCrypt() must extend by the child \phpseclib\Crypt\* class. 2074 * - The following variable names are reserved: 2075 * - $_* (all variable names prefixed with an underscore) 2076 * - $self (object reference to it self. Do not use $this, but $self instead) 2077 * - $in (the content of $in has to en/decrypt by the generated code) 2078 * - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only 2079 * 2080 * 2081 * @see self::_setup() 2082 * @see self::_createInlineCryptFunction() 2083 * @see self::encrypt() 2084 * @see self::decrypt() 2085 * @access private 2086 * @internal If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt() 2087 */ 2088 function _setupInlineCrypt() 2089 { 2090 // If, for any reason, an extending \phpseclib\Crypt\Base() \phpseclib\Crypt\* class 2091 // not using inline crypting then it must be ensured that: $this->use_inline_crypt = false 2092 // ie in the class var declaration of $use_inline_crypt in general for the \phpseclib\Crypt\* class, 2093 // in the constructor at object instance-time 2094 // or, if it's runtime-specific, at runtime 2095 2096 $this->use_inline_crypt = false; 2097 } 2098 2099 /** 2100 * Creates the performance-optimized function for en/decrypt() 2101 * 2102 * Internally for phpseclib developers: 2103 * 2104 * _createInlineCryptFunction(): 2105 * 2106 * - merge the $cipher_code [setup'ed by _setupInlineCrypt()] 2107 * with the current [$this->]mode of operation code 2108 * 2109 * - create the $inline function, which called by encrypt() / decrypt() 2110 * as its replacement to speed up the en/decryption operations. 2111 * 2112 * - return the name of the created $inline callback function 2113 * 2114 * - used to speed up en/decryption 2115 * 2116 * 2117 * 2118 * The main reason why can speed up things [up to 50%] this way are: 2119 * 2120 * - using variables more effective then regular. 2121 * (ie no use of expensive arrays but integers $k_0, $k_1 ... 2122 * or even, for example, the pure $key[] values hardcoded) 2123 * 2124 * - avoiding 1000's of function calls of ie _encryptBlock() 2125 * but inlining the crypt operations. 2126 * in the mode of operation for() loop. 2127 * 2128 * - full loop unroll the (sometimes key-dependent) rounds 2129 * avoiding this way ++$i counters and runtime-if's etc... 2130 * 2131 * The basic code architectur of the generated $inline en/decrypt() 2132 * lambda function, in pseudo php, is: 2133 * 2134 * <code> 2135 * +----------------------------------------------------------------------------------------------+ 2136 * | callback $inline = create_function: | 2137 * | lambda_function_0001_crypt_ECB($action, $text) | 2138 * | { | 2139 * | INSERT PHP CODE OF: | 2140 * | $cipher_code['init_crypt']; // general init code. | 2141 * | // ie: $sbox'es declarations used for | 2142 * | // encrypt and decrypt'ing. | 2143 * | | 2144 * | switch ($action) { | 2145 * | case 'encrypt': | 2146 * | INSERT PHP CODE OF: | 2147 * | $cipher_code['init_encrypt']; // encrypt sepcific init code. | 2148 * | ie: specified $key or $box | 2149 * | declarations for encrypt'ing. | 2150 * | | 2151 * | foreach ($ciphertext) { | 2152 * | $in = $block_size of $ciphertext; | 2153 * | | 2154 * | INSERT PHP CODE OF: | 2155 * | $cipher_code['encrypt_block']; // encrypt's (string) $in, which is always: | 2156 * | // strlen($in) == $this->block_size | 2157 * | // here comes the cipher algorithm in action | 2158 * | // for encryption. | 2159 * | // $cipher_code['encrypt_block'] has to | 2160 * | // encrypt the content of the $in variable | 2161 * | | 2162 * | $plaintext .= $in; | 2163 * | } | 2164 * | return $plaintext; | 2165 * | | 2166 * | case 'decrypt': | 2167 * | INSERT PHP CODE OF: | 2168 * | $cipher_code['init_decrypt']; // decrypt sepcific init code | 2169 * | ie: specified $key or $box | 2170 * | declarations for decrypt'ing. | 2171 * | foreach ($plaintext) { | 2172 * | $in = $block_size of $plaintext; | 2173 * | | 2174 * | INSERT PHP CODE OF: | 2175 * | $cipher_code['decrypt_block']; // decrypt's (string) $in, which is always | 2176 * | // strlen($in) == $this->block_size | 2177 * | // here comes the cipher algorithm in action | 2178 * | // for decryption. | 2179 * | // $cipher_code['decrypt_block'] has to | 2180 * | // decrypt the content of the $in variable | 2181 * | $ciphertext .= $in; | 2182 * | } | 2183 * | return $ciphertext; | 2184 * | } | 2185 * | } | 2186 * +----------------------------------------------------------------------------------------------+ 2187 * </code> 2188 * 2189 * See also the \phpseclib\Crypt\*::_setupInlineCrypt()'s for 2190 * productive inline $cipher_code's how they works. 2191 * 2192 * Structure of: 2193 * <code> 2194 * $cipher_code = array( 2195 * 'init_crypt' => (string) '', // optional 2196 * 'init_encrypt' => (string) '', // optional 2197 * 'init_decrypt' => (string) '', // optional 2198 * 'encrypt_block' => (string) '', // required 2199 * 'decrypt_block' => (string) '' // required 2200 * ); 2201 * </code> 2202 * 2203 * @see self::_setupInlineCrypt() 2204 * @see self::encrypt() 2205 * @see self::decrypt() 2206 * @param array $cipher_code 2207 * @access private 2208 * @return string (the name of the created callback function) 2209 */ 2210 function _createInlineCryptFunction($cipher_code) 2211 { 2212 $block_size = $this->block_size; 2213 2214 // optional 2215 $init_crypt = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : ''; 2216 $init_encrypt = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : ''; 2217 $init_decrypt = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : ''; 2218 // required 2219 $encrypt_block = $cipher_code['encrypt_block']; 2220 $decrypt_block = $cipher_code['decrypt_block']; 2221 2222 // Generating mode of operation inline code, 2223 // merged with the $cipher_code algorithm 2224 // for encrypt- and decryption. 2225 switch ($this->mode) { 2226 case self::MODE_ECB: 2227 $encrypt = $init_encrypt . ' 2228 $_ciphertext = ""; 2229 $_plaintext_len = strlen($_text); 2230 2231 for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { 2232 $in = substr($_text, $_i, '.$block_size.'); 2233 '.$encrypt_block.' 2234 $_ciphertext.= $in; 2235 } 2236 2237 return $_ciphertext; 2238 '; 2239 2240 $decrypt = $init_decrypt . ' 2241 $_plaintext = ""; 2242 $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0)); 2243 $_ciphertext_len = strlen($_text); 2244 2245 for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { 2246 $in = substr($_text, $_i, '.$block_size.'); 2247 '.$decrypt_block.' 2248 $_plaintext.= $in; 2249 } 2250 2251 return $self->_unpad($_plaintext); 2252 '; 2253 break; 2254 case self::MODE_CTR: 2255 $encrypt = $init_encrypt . ' 2256 $_ciphertext = ""; 2257 $_plaintext_len = strlen($_text); 2258 $_xor = $self->encryptIV; 2259 $_buffer = &$self->enbuffer; 2260 if (strlen($_buffer["ciphertext"])) { 2261 for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { 2262 $_block = substr($_text, $_i, '.$block_size.'); 2263 if (strlen($_block) > strlen($_buffer["ciphertext"])) { 2264 $in = $_xor; 2265 '.$encrypt_block.' 2266 $self->_increment_str($_xor); 2267 $_buffer["ciphertext"].= $in; 2268 } 2269 $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.'); 2270 $_ciphertext.= $_block ^ $_key; 2271 } 2272 } else { 2273 for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { 2274 $_block = substr($_text, $_i, '.$block_size.'); 2275 $in = $_xor; 2276 '.$encrypt_block.' 2277 $self->_increment_str($_xor); 2278 $_key = $in; 2279 $_ciphertext.= $_block ^ $_key; 2280 } 2281 } 2282 if ($self->continuousBuffer) { 2283 $self->encryptIV = $_xor; 2284 if ($_start = $_plaintext_len % '.$block_size.') { 2285 $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"]; 2286 } 2287 } 2288 2289 return $_ciphertext; 2290 '; 2291 2292 $decrypt = $init_encrypt . ' 2293 $_plaintext = ""; 2294 $_ciphertext_len = strlen($_text); 2295 $_xor = $self->decryptIV; 2296 $_buffer = &$self->debuffer; 2297 2298 if (strlen($_buffer["ciphertext"])) { 2299 for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { 2300 $_block = substr($_text, $_i, '.$block_size.'); 2301 if (strlen($_block) > strlen($_buffer["ciphertext"])) { 2302 $in = $_xor; 2303 '.$encrypt_block.' 2304 $self->_increment_str($_xor); 2305 $_buffer["ciphertext"].= $in; 2306 } 2307 $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.'); 2308 $_plaintext.= $_block ^ $_key; 2309 } 2310 } else { 2311 for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { 2312 $_block = substr($_text, $_i, '.$block_size.'); 2313 $in = $_xor; 2314 '.$encrypt_block.' 2315 $self->_increment_str($_xor); 2316 $_key = $in; 2317 $_plaintext.= $_block ^ $_key; 2318 } 2319 } 2320 if ($self->continuousBuffer) { 2321 $self->decryptIV = $_xor; 2322 if ($_start = $_ciphertext_len % '.$block_size.') { 2323 $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"]; 2324 } 2325 } 2326 2327 return $_plaintext; 2328 '; 2329 break; 2330 case self::MODE_CFB: 2331 $encrypt = $init_encrypt . ' 2332 $_ciphertext = ""; 2333 $_buffer = &$self->enbuffer; 2334 2335 if ($self->continuousBuffer) { 2336 $_iv = &$self->encryptIV; 2337 $_pos = &$_buffer["pos"]; 2338 } else { 2339 $_iv = $self->encryptIV; 2340 $_pos = 0; 2341 } 2342 $_len = strlen($_text); 2343 $_i = 0; 2344 if ($_pos) { 2345 $_orig_pos = $_pos; 2346 $_max = '.$block_size.' - $_pos; 2347 if ($_len >= $_max) { 2348 $_i = $_max; 2349 $_len-= $_max; 2350 $_pos = 0; 2351 } else { 2352 $_i = $_len; 2353 $_pos+= $_len; 2354 $_len = 0; 2355 } 2356 $_ciphertext = substr($_iv, $_orig_pos) ^ $_text; 2357 $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i); 2358 } 2359 while ($_len >= '.$block_size.') { 2360 $in = $_iv; 2361 '.$encrypt_block.'; 2362 $_iv = $in ^ substr($_text, $_i, '.$block_size.'); 2363 $_ciphertext.= $_iv; 2364 $_len-= '.$block_size.'; 2365 $_i+= '.$block_size.'; 2366 } 2367 if ($_len) { 2368 $in = $_iv; 2369 '.$encrypt_block.' 2370 $_iv = $in; 2371 $_block = $_iv ^ substr($_text, $_i); 2372 $_iv = substr_replace($_iv, $_block, 0, $_len); 2373 $_ciphertext.= $_block; 2374 $_pos = $_len; 2375 } 2376 return $_ciphertext; 2377 '; 2378 2379 $decrypt = $init_encrypt . ' 2380 $_plaintext = ""; 2381 $_buffer = &$self->debuffer; 2382 2383 if ($self->continuousBuffer) { 2384 $_iv = &$self->decryptIV; 2385 $_pos = &$_buffer["pos"]; 2386 } else { 2387 $_iv = $self->decryptIV; 2388 $_pos = 0; 2389 } 2390 $_len = strlen($_text); 2391 $_i = 0; 2392 if ($_pos) { 2393 $_orig_pos = $_pos; 2394 $_max = '.$block_size.' - $_pos; 2395 if ($_len >= $_max) { 2396 $_i = $_max; 2397 $_len-= $_max; 2398 $_pos = 0; 2399 } else { 2400 $_i = $_len; 2401 $_pos+= $_len; 2402 $_len = 0; 2403 } 2404 $_plaintext = substr($_iv, $_orig_pos) ^ $_text; 2405 $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i); 2406 } 2407 while ($_len >= '.$block_size.') { 2408 $in = $_iv; 2409 '.$encrypt_block.' 2410 $_iv = $in; 2411 $cb = substr($_text, $_i, '.$block_size.'); 2412 $_plaintext.= $_iv ^ $cb; 2413 $_iv = $cb; 2414 $_len-= '.$block_size.'; 2415 $_i+= '.$block_size.'; 2416 } 2417 if ($_len) { 2418 $in = $_iv; 2419 '.$encrypt_block.' 2420 $_iv = $in; 2421 $_plaintext.= $_iv ^ substr($_text, $_i); 2422 $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len); 2423 $_pos = $_len; 2424 } 2425 2426 return $_plaintext; 2427 '; 2428 break; 2429 case self::MODE_CFB8: 2430 $encrypt = $init_encrypt . ' 2431 $_ciphertext = ""; 2432 $_len = strlen($_text); 2433 $_iv = $self->encryptIV; 2434 2435 for ($_i = 0; $_i < $_len; ++$_i) { 2436 $in = $_iv; 2437 '.$encrypt_block.' 2438 $_ciphertext .= ($_c = $_text[$_i] ^ $in); 2439 $_iv = substr($_iv, 1) . $_c; 2440 } 2441 2442 if ($self->continuousBuffer) { 2443 if ($_len >= '.$block_size.') { 2444 $self->encryptIV = substr($_ciphertext, -'.$block_size.'); 2445 } else { 2446 $self->encryptIV = substr($self->encryptIV, $_len - '.$block_size.') . substr($_ciphertext, -$_len); 2447 } 2448 } 2449 2450 return $_ciphertext; 2451 '; 2452 $decrypt = $init_encrypt . ' 2453 $_plaintext = ""; 2454 $_len = strlen($_text); 2455 $_iv = $self->decryptIV; 2456 2457 for ($_i = 0; $_i < $_len; ++$_i) { 2458 $in = $_iv; 2459 '.$encrypt_block.' 2460 $_plaintext .= $_text[$_i] ^ $in; 2461 $_iv = substr($_iv, 1) . $_text[$_i]; 2462 } 2463 2464 if ($self->continuousBuffer) { 2465 if ($_len >= '.$block_size.') { 2466 $self->decryptIV = substr($_text, -'.$block_size.'); 2467 } else { 2468 $self->decryptIV = substr($self->decryptIV, $_len - '.$block_size.') . substr($_text, -$_len); 2469 } 2470 } 2471 2472 return $_plaintext; 2473 '; 2474 break; 2475 case self::MODE_OFB: 2476 $encrypt = $init_encrypt . ' 2477 $_ciphertext = ""; 2478 $_plaintext_len = strlen($_text); 2479 $_xor = $self->encryptIV; 2480 $_buffer = &$self->enbuffer; 2481 2482 if (strlen($_buffer["xor"])) { 2483 for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { 2484 $_block = substr($_text, $_i, '.$block_size.'); 2485 if (strlen($_block) > strlen($_buffer["xor"])) { 2486 $in = $_xor; 2487 '.$encrypt_block.' 2488 $_xor = $in; 2489 $_buffer["xor"].= $_xor; 2490 } 2491 $_key = $self->_string_shift($_buffer["xor"], '.$block_size.'); 2492 $_ciphertext.= $_block ^ $_key; 2493 } 2494 } else { 2495 for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { 2496 $in = $_xor; 2497 '.$encrypt_block.' 2498 $_xor = $in; 2499 $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor; 2500 } 2501 $_key = $_xor; 2502 } 2503 if ($self->continuousBuffer) { 2504 $self->encryptIV = $_xor; 2505 if ($_start = $_plaintext_len % '.$block_size.') { 2506 $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"]; 2507 } 2508 } 2509 return $_ciphertext; 2510 '; 2511 2512 $decrypt = $init_encrypt . ' 2513 $_plaintext = ""; 2514 $_ciphertext_len = strlen($_text); 2515 $_xor = $self->decryptIV; 2516 $_buffer = &$self->debuffer; 2517 2518 if (strlen($_buffer["xor"])) { 2519 for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { 2520 $_block = substr($_text, $_i, '.$block_size.'); 2521 if (strlen($_block) > strlen($_buffer["xor"])) { 2522 $in = $_xor; 2523 '.$encrypt_block.' 2524 $_xor = $in; 2525 $_buffer["xor"].= $_xor; 2526 } 2527 $_key = $self->_string_shift($_buffer["xor"], '.$block_size.'); 2528 $_plaintext.= $_block ^ $_key; 2529 } 2530 } else { 2531 for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { 2532 $in = $_xor; 2533 '.$encrypt_block.' 2534 $_xor = $in; 2535 $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor; 2536 } 2537 $_key = $_xor; 2538 } 2539 if ($self->continuousBuffer) { 2540 $self->decryptIV = $_xor; 2541 if ($_start = $_ciphertext_len % '.$block_size.') { 2542 $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"]; 2543 } 2544 } 2545 return $_plaintext; 2546 '; 2547 break; 2548 case self::MODE_STREAM: 2549 $encrypt = $init_encrypt . ' 2550 $_ciphertext = ""; 2551 '.$encrypt_block.' 2552 return $_ciphertext; 2553 '; 2554 $decrypt = $init_decrypt . ' 2555 $_plaintext = ""; 2556 '.$decrypt_block.' 2557 return $_plaintext; 2558 '; 2559 break; 2560 // case self::MODE_CBC: 2561 default: 2562 $encrypt = $init_encrypt . ' 2563 $_ciphertext = ""; 2564 $_plaintext_len = strlen($_text); 2565 2566 $in = $self->encryptIV; 2567 2568 for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { 2569 $in = substr($_text, $_i, '.$block_size.') ^ $in; 2570 '.$encrypt_block.' 2571 $_ciphertext.= $in; 2572 } 2573 2574 if ($self->continuousBuffer) { 2575 $self->encryptIV = $in; 2576 } 2577 2578 return $_ciphertext; 2579 '; 2580 2581 $decrypt = $init_decrypt . ' 2582 $_plaintext = ""; 2583 $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0)); 2584 $_ciphertext_len = strlen($_text); 2585 2586 $_iv = $self->decryptIV; 2587 2588 for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { 2589 $in = $_block = substr($_text, $_i, '.$block_size.'); 2590 '.$decrypt_block.' 2591 $_plaintext.= $in ^ $_iv; 2592 $_iv = $_block; 2593 } 2594 2595 if ($self->continuousBuffer) { 2596 $self->decryptIV = $_iv; 2597 } 2598 2599 return $self->_unpad($_plaintext); 2600 '; 2601 break; 2602 } 2603 2604 // Create the $inline function and return its name as string. Ready to run! 2605 if (version_compare(PHP_VERSION, '5.3.0') >= 0) { 2606 eval('$func = function ($_action, &$self, $_text) { ' . $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' } };'); 2607 return $func; 2608 } 2609 2610 return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }'); 2611 } 2612 2613 /** 2614 * Holds the lambda_functions table (classwide) 2615 * 2616 * Each name of the lambda function, created from 2617 * _setupInlineCrypt() && _createInlineCryptFunction() 2618 * is stored, classwide (!), here for reusing. 2619 * 2620 * The string-based index of $function is a classwide 2621 * unique value representing, at least, the $mode of 2622 * operation (or more... depends of the optimizing level) 2623 * for which $mode the lambda function was created. 2624 * 2625 * @access private 2626 * @return array &$functions 2627 */ 2628 function &_getLambdaFunctions() 2629 { 2630 static $functions = array(); 2631 return $functions; 2632 } 2633 2634 /** 2635 * Generates a digest from $bytes 2636 * 2637 * @see self::_setupInlineCrypt() 2638 * @access private 2639 * @param $bytes 2640 * @return string 2641 */ 2642 function _hashInlineCryptFunction($bytes) 2643 { 2644 if (!isset(self::$WHIRLPOOL_AVAILABLE)) { 2645 self::$WHIRLPOOL_AVAILABLE = extension_loaded('hash') && in_array('whirlpool', hash_algos()); 2646 } 2647 2648 $result = ''; 2649 $hash = $bytes; 2650 2651 switch (true) { 2652 case self::$WHIRLPOOL_AVAILABLE: 2653 foreach (str_split($bytes, 64) as $t) { 2654 $hash = hash('whirlpool', $hash, true); 2655 $result .= $t ^ $hash; 2656 } 2657 return $result . hash('whirlpool', $hash, true); 2658 default: 2659 $len = strlen($bytes); 2660 for ($i = 0; $i < $len; $i+=20) { 2661 $t = substr($bytes, $i, 20); 2662 $hash = pack('H*', sha1($hash)); 2663 $result .= $t ^ $hash; 2664 } 2665 return $result . pack('H*', sha1($hash)); 2666 } 2667 } 2668 2669 /** 2670 * Convert float to int 2671 * 2672 * On ARM CPUs converting floats to ints doesn't always work 2673 * 2674 * @access private 2675 * @param string $x 2676 * @return int 2677 */ 2678 function safe_intval($x) 2679 { 2680 switch (true) { 2681 case is_int($x): 2682 // PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding" 2683 case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM': 2684 return $x; 2685 } 2686 return (fmod($x, 0x80000000) & 0x7FFFFFFF) | 2687 ((fmod(floor($x / 0x80000000), 2) & 1) << 31); 2688 } 2689 2690 /** 2691 * eval()'able string for in-line float to int 2692 * 2693 * @access private 2694 * @return string 2695 */ 2696 function safe_intval_inline() 2697 { 2698 switch (true) { 2699 case defined('PHP_INT_SIZE') && PHP_INT_SIZE == 8: 2700 case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM': 2701 return '%s'; 2702 break; 2703 default: 2704 $safeint = '(is_int($temp = %s) ? $temp : (fmod($temp, 0x80000000) & 0x7FFFFFFF) | '; 2705 return $safeint . '((fmod(floor($temp / 0x80000000), 2) & 1) << 31))'; 2706 } 2707 } 2708} 2709