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