PluginProbe
Contact Forms by Cimatti / 1.9.2
Contact Forms by Cimatti v1.9.2
2.3.6 2.3.5 2.3.0 2.2.32 2.2.4 2.2.0 2.1.2 2.1.1 trunk 1.0 1.1 1.2 1.2.1 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 All 62 releases
contact-forms / phpseclib-crypt / Base.php

Base.php in Contact Forms by Cimatti 1.9.2, at phpseclib-crypt/Base.php

2,662 lines 101.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Base Class for all Crypt_* cipher classes
5 *
6 * PHP versions 4 and 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 Crypt_* cipher class should extend 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 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 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
29 * of this software and associated documentation files (the "Software"), to deal
30 * in the Software without restriction, including without limitation the rights
31 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32 * copies of the Software, and to permit persons to whom the Software is
33 * furnished to do so, subject to the following conditions:
34 *
35 * The above copyright notice and this permission notice shall be included in
36 * all copies or substantial portions of the Software.
37 *
38 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44 * THE SOFTWARE.
45 *
46 * @category Crypt
47 * @package Crypt_Base
48 * @author Jim Wigginton <terrafrost@php.net>
49 * @author Hans-Juergen Petrich <petrich@tronic-media.com>
50 * @copyright 2007 Jim Wigginton
51 * @license http://www.opensource.org/licenses/mit-license.html MIT License
52 * @link http://phpseclib.sourceforge.net
53 */
54
55 /**#@+
56 * @access public
57 * @see self::encrypt()
58 * @see self::decrypt()
59 */
60 /**
61 * Encrypt / decrypt using the Counter mode.
62 *
63 * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
64 *
65 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
66 */
67 define('CRYPT_MODE_CTR', -1);
68 /**
69 * Encrypt / decrypt using the Electronic Code Book mode.
70 *
71 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
72 */
73 define('CRYPT_MODE_ECB', 1);
74 /**
75 * Encrypt / decrypt using the Code Book Chaining mode.
76 *
77 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
78 */
79 define('CRYPT_MODE_CBC', 2);
80 /**
81 * Encrypt / decrypt using the Cipher Feedback mode.
82 *
83 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
84 */
85 define('CRYPT_MODE_CFB', 3);
86 /**
87 * Encrypt / decrypt using the Output Feedback mode.
88 *
89 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
90 */
91 define('CRYPT_MODE_OFB', 4);
92 /**
93 * Encrypt / decrypt using streaming mode.
94 */
95 define('CRYPT_MODE_STREAM', 5);
96 /**#@-*/
97
98 /**#@+
99 * @access private
100 * @see self::Crypt_Base()
101 * @internal These constants are for internal use only
102 */
103 /**
104 * Base value for the internal implementation $engine switch
105 */
106 define('CRYPT_ENGINE_INTERNAL', 1);
107 /**
108 * Base value for the mcrypt implementation $engine switch
109 */
110 define('CRYPT_ENGINE_MCRYPT', 2);
111 /**
112 * Base value for the OpenSSL implementation $engine switch
113 */
114 define('CRYPT_ENGINE_OPENSSL', 3);
115 /**#@-*/
116
117 /**
118 * Base Class for all Crypt_* cipher classes
119 *
120 * @package Crypt_Base
121 * @author Jim Wigginton <terrafrost@php.net>
122 * @author Hans-Juergen Petrich <petrich@tronic-media.com>
123 * @access public
124 */
125 #[AllowDynamicProperties]
126 class Crypt_Base
127 {
128 /**
129 * The Encryption Mode
130 *
131 * @see self::Crypt_Base()
132 * @var int
133 * @access private
134 */
135 var $mode;
136
137 /**
138 * The Block Length of the block cipher
139 *
140 * @var int
141 * @access private
142 */
143 var $block_size = 16;
144
145 /**
146 * The Key
147 *
148 * @see self::setKey()
149 * @var string
150 * @access private
151 */
152 var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
153
154 /**
155 * The Initialization Vector
156 *
157 * @see self::setIV()
158 * @var string
159 * @access private
160 */
161 var $iv;
162
163 /**
164 * A "sliding" Initialization Vector
165 *
166 * @see self::enableContinuousBuffer()
167 * @see self::_clearBuffers()
168 * @var string
169 * @access private
170 */
171 var $encryptIV;
172
173 /**
174 * A "sliding" Initialization Vector
175 *
176 * @see self::enableContinuousBuffer()
177 * @see self::_clearBuffers()
178 * @var string
179 * @access private
180 */
181 var $decryptIV;
182
183 /**
184 * Continuous Buffer status
185 *
186 * @see self::enableContinuousBuffer()
187 * @var bool
188 * @access private
189 */
190 var $continuousBuffer = false;
191
192 /**
193 * Encryption buffer for CTR, OFB and CFB modes
194 *
195 * @see self::encrypt()
196 * @see self::_clearBuffers()
197 * @var array
198 * @access private
199 */
200 var $enbuffer;
201
202 /**
203 * Decryption buffer for CTR, OFB and CFB modes
204 *
205 * @see self::decrypt()
206 * @see self::_clearBuffers()
207 * @var array
208 * @access private
209 */
210 var $debuffer;
211
212 /**
213 * mcrypt resource for encryption
214 *
215 * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
216 * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
217 *
218 * @see self::encrypt()
219 * @var resource
220 * @access private
221 */
222 var $enmcrypt;
223
224 /**
225 * mcrypt resource for decryption
226 *
227 * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
228 * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
229 *
230 * @see self::decrypt()
231 * @var resource
232 * @access private
233 */
234 var $demcrypt;
235
236 /**
237 * Does the enmcrypt resource need to be (re)initialized?
238 *
239 * @see Crypt_Twofish::setKey()
240 * @see Crypt_Twofish::setIV()
241 * @var bool
242 * @access private
243 */
244 var $enchanged = true;
245
246 /**
247 * Does the demcrypt resource need to be (re)initialized?
248 *
249 * @see Crypt_Twofish::setKey()
250 * @see Crypt_Twofish::setIV()
251 * @var bool
252 * @access private
253 */
254 var $dechanged = true;
255
256 /**
257 * mcrypt resource for CFB mode
258 *
259 * mcrypt's CFB mode, in (and only in) buffered context,
260 * is broken, so phpseclib implements the CFB mode by it self,
261 * even when the mcrypt php extension is available.
262 *
263 * In order to do the CFB-mode work (fast) phpseclib
264 * use a separate ECB-mode mcrypt resource.
265 *
266 * @link http://phpseclib.sourceforge.net/cfb-demo.phps
267 * @see self::encrypt()
268 * @see self::decrypt()
269 * @see self::_setupMcrypt()
270 * @var resource
271 * @access private
272 */
273 var $ecb;
274
275 /**
276 * Optimizing value while CFB-encrypting
277 *
278 * Only relevant if $continuousBuffer enabled
279 * and $engine == CRYPT_ENGINE_MCRYPT
280 *
281 * It's faster to re-init $enmcrypt if
282 * $buffer bytes > $cfb_init_len than
283 * using the $ecb resource furthermore.
284 *
285 * This value depends of the chosen cipher
286 * and the time it would be needed for it's
287 * initialization [by mcrypt_generic_init()]
288 * which, typically, depends on the complexity
289 * on its internaly Key-expanding algorithm.
290 *
291 * @see self::encrypt()
292 * @var int
293 * @access private
294 */
295 var $cfb_init_len = 600;
296
297 /**
298 * Does internal cipher state need to be (re)initialized?
299 *
300 * @see self::setKey()
301 * @see self::setIV()
302 * @see self::disableContinuousBuffer()
303 * @var bool
304 * @access private
305 */
306 var $changed = true;
307
308 /**
309 * Padding status
310 *
311 * @see self::enablePadding()
312 * @var bool
313 * @access private
314 */
315 var $padding = true;
316
317 /**
318 * Is the mode one that is paddable?
319 *
320 * @see self::Crypt_Base()
321 * @var bool
322 * @access private
323 */
324 var $paddable = false;
325
326 /**
327 * Holds which crypt engine internaly should be use,
328 * which will be determined automatically on __construct()
329 *
330 * Currently available $engines are:
331 * - CRYPT_ENGINE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required)
332 * - CRYPT_ENGINE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required)
333 * - CRYPT_ENGINE_INTERNAL (slower, pure php-engine, no php-extension required)
334 *
335 * @see self::_setEngine()
336 * @see self::encrypt()
337 * @see self::decrypt()
338 * @var int
339 * @access private
340 */
341 var $engine;
342
343 /**
344 * Holds the preferred crypt engine
345 *
346 * @see self::_setEngine()
347 * @see self::setPreferredEngine()
348 * @var int
349 * @access private
350 */
351 var $preferredEngine;
352
353 /**
354 * The mcrypt specific name of the cipher
355 *
356 * Only used if $engine == CRYPT_ENGINE_MCRYPT
357 *
358 * @link http://www.php.net/mcrypt_module_open
359 * @link http://www.php.net/mcrypt_list_algorithms
360 * @see self::_setupMcrypt()
361 * @var string
362 * @access private
363 */
364 var $cipher_name_mcrypt;
365
366 /**
367 * The openssl specific name of the cipher
368 *
369 * Only used if $engine == CRYPT_ENGINE_OPENSSL
370 *
371 * @link http://www.php.net/openssl-get-cipher-methods
372 * @var string
373 * @access private
374 */
375 var $cipher_name_openssl;
376
377 /**
378 * The openssl specific name of the cipher in ECB mode
379 *
380 * If OpenSSL does not support the mode we're trying to use (CTR)
381 * it can still be emulated with ECB mode.
382 *
383 * @link http://www.php.net/openssl-get-cipher-methods
384 * @var string
385 * @access private
386 */
387 var $cipher_name_openssl_ecb;
388
389 /**
390 * The default salt used by setPassword()
391 *
392 * @see self::setPassword()
393 * @var string
394 * @access private
395 */
396 var $password_default_salt = 'phpseclib/salt';
397
398 /**
399 * The namespace used by the cipher for its constants.
400 *
401 * ie: AES.php is using CRYPT_AES_MODE_* for its constants
402 * so $const_namespace is AES
403 *
404 * DES.php is using CRYPT_DES_MODE_* for its constants
405 * so $const_namespace is DES... and so on
406 *
407 * All CRYPT_<$const_namespace>_MODE_* are aliases of
408 * the generic CRYPT_MODE_* constants, so both could be used
409 * for each cipher.
410 *
411 * Example:
412 * $aes = new Crypt_AES(CRYPT_AES_MODE_CFB); // $aes will operate in cfb mode
413 * $aes = new Crypt_AES(CRYPT_MODE_CFB); // identical
414 *
415 * @see self::Crypt_Base()
416 * @var string
417 * @access private
418 */
419 var $const_namespace;
420
421 /**
422 * The name of the performance-optimized callback function
423 *
424 * Used by encrypt() / decrypt()
425 * only if $engine == CRYPT_ENGINE_INTERNAL
426 *
427 * @see self::encrypt()
428 * @see self::decrypt()
429 * @see self::_setupInlineCrypt()
430 * @see self::$use_inline_crypt
431 * @var Callback
432 * @access private
433 */
434 var $inline_crypt;
435
436 /**
437 * Holds whether performance-optimized $inline_crypt() can/should be used.
438 *
439 * @see self::encrypt()
440 * @see self::decrypt()
441 * @see self::inline_crypt
442 * @var mixed
443 * @access private
444 */
445 var $use_inline_crypt;
446
447 /**
448 * If OpenSSL can be used in ECB but not in CTR we can emulate CTR
449 *
450 * @see self::_openssl_ctr_process()
451 * @var bool
452 * @access private
453 */
454 var $openssl_emulate_ctr = false;
455
456 /**
457 * Determines what options are passed to openssl_encrypt/decrypt
458 *
459 * @see self::isValidEngine()
460 * @var mixed
461 * @access private
462 */
463 var $openssl_options;
464
465 /**
466 * Has the key length explicitly been set or should it be derived from the key, itself?
467 *
468 * @see self::setKeyLength()
469 * @var bool
470 * @access private
471 */
472 var $explicit_key_length = false;
473
474 /**
475 * Don't truncate / null pad key
476 *
477 * @see self::_clearBuffers()
478 * @var bool
479 * @access private
480 */
481 var $skip_key_adjustment = false;
482
483 /**
484 * Default Constructor.
485 *
486 * Determines whether or not the mcrypt extension should be used.
487 *
488 * $mode could be:
489 *
490 * - CRYPT_MODE_ECB
491 *
492 * - CRYPT_MODE_CBC
493 *
494 * - CRYPT_MODE_CTR
495 *
496 * - CRYPT_MODE_CFB
497 *
498 * - CRYPT_MODE_OFB
499 *
500 * (or the alias constants of the chosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...)
501 *
502 * If not explicitly set, CRYPT_MODE_CBC will be used.
503 *
504 * @param int $mode
505 * @access public
506 */
507 function __construct($mode = CRYPT_MODE_CBC)
508 {
509 // $mode dependent settings
510 switch ($mode) {
511 case CRYPT_MODE_ECB:
512 $this->paddable = true;
513 $this->mode = CRYPT_MODE_ECB;
514 break;
515 case CRYPT_MODE_CTR:
516 case CRYPT_MODE_CFB:
517 case CRYPT_MODE_OFB:
518 case CRYPT_MODE_STREAM:
519 $this->mode = $mode;
520 break;
521 case CRYPT_MODE_CBC:
522 default:
523 $this->paddable = true;
524 $this->mode = CRYPT_MODE_CBC;
525 }
526
527 $this->_setEngine();
528
529 // Determining whether inline crypting can be used by the cipher
530 if ($this->use_inline_crypt !== false) {
531 $this->use_inline_crypt = version_compare(PHP_VERSION, '5.3.0') >= 0 || function_exists('create_function');
532 }
533 }
534
535 /**
536 * PHP4 compatible Default Constructor.
537 *
538 * @see self::__construct()
539 * @param int $mode
540 * @access public
541 */
542 function Crypt_Base($mode = CRYPT_MODE_CBC)
543 {
544 $this->__construct($mode);
545 }
546
547 /**
548 * Sets the initialization vector. (optional)
549 *
550 * SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used. If not explicitly set, it'll be assumed
551 * to be all zero's.
552 *
553 * @access public
554 * @param string $iv
555 * @internal Can be overwritten by a sub class, but does not have to be
556 */
557 function setIV($iv)
558 {
559 if ($this->mode == CRYPT_MODE_ECB) {
560 return;
561 }
562
563 $this->iv = $iv;
564 $this->changed = true;
565 }
566
567 /**
568 * Sets the key length.
569 *
570 * Keys with explicitly set lengths need to be treated accordingly
571 *
572 * @access public
573 * @param int $length
574 */
575 function setKeyLength($length)
576 {
577 $this->explicit_key_length = true;
578 $this->changed = true;
579 $this->_setEngine();
580 }
581
582 /**
583 * Returns the current key length in bits
584 *
585 * @access public
586 * @return int
587 */
588 function getKeyLength()
589 {
590 return $this->key_length << 3;
591 }
592
593 /**
594 * Returns the current block length in bits
595 *
596 * @access public
597 * @return int
598 */
599 function getBlockLength()
600 {
601 return $this->block_size << 3;
602 }
603
604 /**
605 * Sets the key.
606 *
607 * The min/max length(s) of the key depends on the cipher which is used.
608 * If the key not fits the length(s) of the cipher it will paded with null bytes
609 * up to the closest valid key length. If the key is more than max length,
610 * we trim the excess bits.
611 *
612 * If the key is not explicitly set, it'll be assumed to be all null bytes.
613 *
614 * @access public
615 * @param string $key
616 * @internal Could, but not must, extend by the child Crypt_* class
617 */
618 function setKey($key)
619 {
620 if (!$this->explicit_key_length) {
621 $this->setKeyLength(strlen($key) << 3);
622 $this->explicit_key_length = false;
623 }
624
625 $this->key = $key;
626 $this->changed = true;
627 $this->_setEngine();
628 }
629
630 /**
631 * Sets the password.
632 *
633 * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
634 * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
635 * $hash, $salt, $count, $dkLen
636 *
637 * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
638 *
639 * @see Crypt/Hash.php
640 * @param string $password
641 * @param string $method
642 * @return bool
643 * @access public
644 * @internal Could, but not must, extend by the child Crypt_* class
645 */
646 function setPassword($password, $method = 'pbkdf2')
647 {
648 $key = '';
649
650 switch ($method) {
651 default: // 'pbkdf2' or 'pbkdf1'
652 $func_args = func_get_args();
653
654 // Hash function
655 $hash = isset($func_args[2]) ? $func_args[2] : 'sha1';
656
657 // WPA and WPA2 use the SSID as the salt
658 $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;
659
660 // RFC2898#section-4.2 uses 1,000 iterations by default
661 // WPA and WPA2 use 4,096.
662 $count = isset($func_args[4]) ? $func_args[4] : 1000;
663
664 // Keylength
665 if (isset($func_args[5]) && $func_args[5] > 0) {
666 $dkLen = $func_args[5];
667 } else {
668 $dkLen = $method == 'pbkdf1' ? 2 * $this->key_length : $this->key_length;
669 }
670
671 switch (true) {
672 case $method == 'pbkdf1':
673 if (!class_exists('Crypt_Hash')) {
674 include_once 'Hash.php';
675 }
676 $hashObj = new Crypt_Hash();
677 $hashObj->setHash($hash);
678 if ($dkLen > $hashObj->getLength()) {
679 user_error('Derived key too long');
680 return false;
681 }
682 $t = $password . $salt;
683 for ($i = 0; $i < $count; ++$i) {
684 $t = $hashObj->hash($t);
685 }
686 $key = substr($t, 0, $dkLen);
687
688 $this->setKey(substr($key, 0, $dkLen >> 1));
689 $this->setIV(substr($key, $dkLen >> 1));
690
691 return true;
692 // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
693 case !function_exists('hash_pbkdf2'):
694 case !function_exists('hash_algos'):
695 case !in_array($hash, hash_algos()):
696 if (!class_exists('Crypt_Hash')) {
697 include_once 'Hash.php';
698 }
699 $i = 1;
700 $hmac = new Crypt_Hash();
701 $hmac->setHash($hash);
702 $hmac->setKey($password);
703 while (strlen($key) < $dkLen) {
704 $f = $u = $hmac->hash($salt . pack('N', $i++));
705 for ($j = 2; $j <= $count; ++$j) {
706 $u = $hmac->hash($u);
707 $f^= $u;
708 }
709 $key.= $f;
710 }
711 $key = substr($key, 0, $dkLen);
712 break;
713 default:
714 $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
715 }
716 }
717
718 $this->setKey($key);
719
720 return true;
721 }
722
723 /**
724 * Encrypts a message.
725 *
726 * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher
727 * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
728 * necessary are discussed in the following
729 * URL:
730 *
731 * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
732 *
733 * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
734 * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that
735 * length.
736 *
737 * @see self::decrypt()
738 * @access public
739 * @param string $plaintext
740 * @return string $ciphertext
741 * @internal Could, but not must, extend by the child Crypt_* class
742 */
743 function encrypt($plaintext)
744 {
745 if ($this->paddable) {
746 $plaintext = $this->_pad($plaintext);
747 }
748
749 if ($this->engine === CRYPT_ENGINE_OPENSSL) {
750 if ($this->changed) {
751 $this->_clearBuffers();
752 $this->changed = false;
753 }
754 switch ($this->mode) {
755 case CRYPT_MODE_STREAM:
756 return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
757 case CRYPT_MODE_ECB:
758 $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
759 return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
760 case CRYPT_MODE_CBC:
761 $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
762 if (!defined('OPENSSL_RAW_DATA')) {
763 $result = substr($result, 0, -$this->block_size);
764 }
765 if ($this->continuousBuffer) {
766 $this->encryptIV = substr($result, -$this->block_size);
767 }
768 return $result;
769 case CRYPT_MODE_CTR:
770 return $this->_openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer);
771 case CRYPT_MODE_CFB:
772 // cfb loosely routines inspired by openssl's:
773 // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
774 $ciphertext = '';
775 if ($this->continuousBuffer) {
776 $iv = &$this->encryptIV;
777 $pos = &$this->enbuffer['pos'];
778 } else {
779 $iv = $this->encryptIV;
780 $pos = 0;
781 }
782 $len = strlen($plaintext);
783 $i = 0;
784 if ($pos) {
785 $orig_pos = $pos;
786 $max = $this->block_size - $pos;
787 if ($len >= $max) {
788 $i = $max;
789 $len-= $max;
790 $pos = 0;
791 } else {
792 $i = $len;
793 $pos+= $len;
794 $len = 0;
795 }
796 // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
797 $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
798 $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
799 $plaintext = substr($plaintext, $i);
800 }
801
802 $overflow = $len % $this->block_size;
803
804 if ($overflow) {
805 $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
806 $iv = $this->_string_pop($ciphertext, $this->block_size);
807
808 $size = $len - $overflow;
809 $block = $iv ^ substr($plaintext, -$overflow);
810 $iv = substr_replace($iv, $block, 0, $overflow);
811 $ciphertext.= $block;
812 $pos = $overflow;
813 } elseif ($len) {
814 $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
815 $iv = substr($ciphertext, -$this->block_size);
816 }
817
818 return $ciphertext;
819 case CRYPT_MODE_OFB:
820 return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
821 }
822 }
823
824 if ($this->engine === CRYPT_ENGINE_MCRYPT) {
825 if ($this->changed) {
826 $this->_setupMcrypt();
827 $this->changed = false;
828 }
829 if ($this->enchanged) {
830 @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
831 $this->enchanged = false;
832 }
833
834 // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
835 // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
836 // rewritten CFB implementation the above outputs the same thing twice.
837 if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) {
838 $block_size = $this->block_size;
839 $iv = &$this->encryptIV;
840 $pos = &$this->enbuffer['pos'];
841 $len = strlen($plaintext);
842 $ciphertext = '';
843 $i = 0;
844 if ($pos) {
845 $orig_pos = $pos;
846 $max = $block_size - $pos;
847 if ($len >= $max) {
848 $i = $max;
849 $len-= $max;
850 $pos = 0;
851 } else {
852 $i = $len;
853 $pos+= $len;
854 $len = 0;
855 }
856 $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
857 $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
858 $this->enbuffer['enmcrypt_init'] = true;
859 }
860 if ($len >= $block_size) {
861 if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) {
862 if ($this->enbuffer['enmcrypt_init'] === true) {
863 @mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
864 $this->enbuffer['enmcrypt_init'] = false;
865 }
866 $ciphertext.= @mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
867 $iv = substr($ciphertext, -$block_size);
868 $len%= $block_size;
869 } else {
870 while ($len >= $block_size) {
871 $iv = @mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
872 $ciphertext.= $iv;
873 $len-= $block_size;
874 $i+= $block_size;
875 }
876 }
877 }
878
879 if ($len) {
880 $iv = @mcrypt_generic($this->ecb, $iv);
881 $block = $iv ^ substr($plaintext, -$len);
882 $iv = substr_replace($iv, $block, 0, $len);
883 $ciphertext.= $block;
884 $pos = $len;
885 }
886
887 return $ciphertext;
888 }
889
890 $ciphertext = @mcrypt_generic($this->enmcrypt, $plaintext);
891
892 if (!$this->continuousBuffer) {
893 @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
894 }
895
896 return $ciphertext;
897 }
898
899 if ($this->changed) {
900 $this->_setup();
901 $this->changed = false;
902 }
903 if ($this->use_inline_crypt) {
904 $inline = $this->inline_crypt;
905 return $inline('encrypt', $this, $plaintext);
906 }
907
908 $buffer = &$this->enbuffer;
909 $block_size = $this->block_size;
910 $ciphertext = '';
911 switch ($this->mode) {
912 case CRYPT_MODE_ECB:
913 for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
914 $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
915 }
916 break;
917 case CRYPT_MODE_CBC:
918 $xor = $this->encryptIV;
919 for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
920 $block = substr($plaintext, $i, $block_size);
921 $block = $this->_encryptBlock($block ^ $xor);
922 $xor = $block;
923 $ciphertext.= $block;
924 }
925 if ($this->continuousBuffer) {
926 $this->encryptIV = $xor;
927 }
928 break;
929 case CRYPT_MODE_CTR:
930 $xor = $this->encryptIV;
931 if (strlen($buffer['ciphertext'])) {
932 for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
933 $block = substr($plaintext, $i, $block_size);
934 if (strlen($block) > strlen($buffer['ciphertext'])) {
935 $buffer['ciphertext'].= $this->_encryptBlock($xor);
936 }
937 $this->_increment_str($xor);
938 $key = $this->_string_shift($buffer['ciphertext'], $block_size);
939 $ciphertext.= $block ^ $key;
940 }
941 } else {
942 for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
943 $block = substr($plaintext, $i, $block_size);
944 $key = $this->_encryptBlock($xor);
945 $this->_increment_str($xor);
946 $ciphertext.= $block ^ $key;
947 }
948 }
949 if ($this->continuousBuffer) {
950 $this->encryptIV = $xor;
951 if ($start = strlen($plaintext) % $block_size) {
952 $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
953 }
954 }
955 break;
956 case CRYPT_MODE_CFB:
957 // cfb loosely routines inspired by openssl's:
958 // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
959 if ($this->continuousBuffer) {
960 $iv = &$this->encryptIV;
961 $pos = &$buffer['pos'];
962 } else {
963 $iv = $this->encryptIV;
964 $pos = 0;
965 }
966 $len = strlen($plaintext);
967 $i = 0;
968 if ($pos) {
969 $orig_pos = $pos;
970 $max = $block_size - $pos;
971 if ($len >= $max) {
972 $i = $max;
973 $len-= $max;
974 $pos = 0;
975 } else {
976 $i = $len;
977 $pos+= $len;
978 $len = 0;
979 }
980 // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
981 $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
982 $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
983 }
984 while ($len >= $block_size) {
985 $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
986 $ciphertext.= $iv;
987 $len-= $block_size;
988 $i+= $block_size;
989 }
990 if ($len) {
991 $iv = $this->_encryptBlock($iv);
992 $block = $iv ^ substr($plaintext, $i);
993 $iv = substr_replace($iv, $block, 0, $len);
994 $ciphertext.= $block;
995 $pos = $len;
996 }
997 break;
998 case CRYPT_MODE_OFB:
999 $xor = $this->encryptIV;
1000 if (strlen($buffer['xor'])) {
1001 for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1002 $block = substr($plaintext, $i, $block_size);
1003 if (strlen($block) > strlen($buffer['xor'])) {
1004 $xor = $this->_encryptBlock($xor);
1005 $buffer['xor'].= $xor;
1006 }
1007 $key = $this->_string_shift($buffer['xor'], $block_size);
1008 $ciphertext.= $block ^ $key;
1009 }
1010 } else {
1011 for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1012 $xor = $this->_encryptBlock($xor);
1013 $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
1014 }
1015 $key = $xor;
1016 }
1017 if ($this->continuousBuffer) {
1018 $this->encryptIV = $xor;
1019 if ($start = strlen($plaintext) % $block_size) {
1020 $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1021 }
1022 }
1023 break;
1024 case CRYPT_MODE_STREAM:
1025 $ciphertext = $this->_encryptBlock($plaintext);
1026 break;
1027 }
1028
1029 return $ciphertext;
1030 }
1031
1032 /**
1033 * Decrypts a message.
1034 *
1035 * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
1036 * it is.
1037 *
1038 * @see self::encrypt()
1039 * @access public
1040 * @param string $ciphertext
1041 * @return string $plaintext
1042 * @internal Could, but not must, extend by the child Crypt_* class
1043 */
1044 function decrypt($ciphertext)
1045 {
1046 if ($this->paddable) {
1047 // we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}:
1048 // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
1049 $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
1050 }
1051
1052 if ($this->engine === CRYPT_ENGINE_OPENSSL) {
1053 if ($this->changed) {
1054 $this->_clearBuffers();
1055 $this->changed = false;
1056 }
1057 switch ($this->mode) {
1058 case CRYPT_MODE_STREAM:
1059 $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1060 break;
1061 case CRYPT_MODE_ECB:
1062 if (!defined('OPENSSL_RAW_DATA')) {
1063 $ciphertext.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true);
1064 }
1065 $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1066 break;
1067 case CRYPT_MODE_CBC:
1068 if (!defined('OPENSSL_RAW_DATA')) {
1069 $padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size);
1070 $ciphertext.= substr(openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size);
1071 $offset = 2 * $this->block_size;
1072 } else {
1073 $offset = $this->block_size;
1074 }
1075 $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV);
1076 if ($this->continuousBuffer) {
1077 $this->decryptIV = substr($ciphertext, -$offset, $this->block_size);
1078 }
1079 break;
1080 case CRYPT_MODE_CTR:
1081 $plaintext = $this->_openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer);
1082 break;
1083 case CRYPT_MODE_CFB:
1084 // cfb loosely routines inspired by openssl's:
1085 // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
1086 $plaintext = '';
1087 if ($this->continuousBuffer) {
1088 $iv = &$this->decryptIV;
1089 $pos = &$this->buffer['pos'];
1090 } else {
1091 $iv = $this->decryptIV;
1092 $pos = 0;
1093 }
1094 $len = strlen($ciphertext);
1095 $i = 0;
1096 if ($pos) {
1097 $orig_pos = $pos;
1098 $max = $this->block_size - $pos;
1099 if ($len >= $max) {
1100 $i = $max;
1101 $len-= $max;
1102 $pos = 0;
1103 } else {
1104 $i = $len;
1105 $pos+= $len;
1106 $len = 0;
1107 }
1108 // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $this->blocksize
1109 $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1110 $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1111 $ciphertext = substr($ciphertext, $i);
1112 }
1113 $overflow = $len % $this->block_size;
1114 if ($overflow) {
1115 $plaintext.= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1116 if ($len - $overflow) {
1117 $iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow);
1118 }
1119 $iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1120 $plaintext.= $iv ^ substr($ciphertext, -$overflow);
1121 $iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow);
1122 $pos = $overflow;
1123 } elseif ($len) {
1124 $plaintext.= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1125 $iv = substr($ciphertext, -$this->block_size);
1126 }
1127 break;
1128 case CRYPT_MODE_OFB:
1129 $plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
1130 }
1131
1132 return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1133 }
1134
1135 if ($this->engine === CRYPT_ENGINE_MCRYPT) {
1136 $block_size = $this->block_size;
1137 if ($this->changed) {
1138 $this->_setupMcrypt();
1139 $this->changed = false;
1140 }
1141 if ($this->dechanged) {
1142 @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
1143 $this->dechanged = false;
1144 }
1145
1146 if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) {
1147 $iv = &$this->decryptIV;
1148 $pos = &$this->debuffer['pos'];
1149 $len = strlen($ciphertext);
1150 $plaintext = '';
1151 $i = 0;
1152 if ($pos) {
1153 $orig_pos = $pos;
1154 $max = $block_size - $pos;
1155 if ($len >= $max) {
1156 $i = $max;
1157 $len-= $max;
1158 $pos = 0;
1159 } else {
1160 $i = $len;
1161 $pos+= $len;
1162 $len = 0;
1163 }
1164 // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1165 $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1166 $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1167 }
1168 if ($len >= $block_size) {
1169 $cb = substr($ciphertext, $i, $len - $len % $block_size);
1170 $plaintext.= @mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
1171 $iv = substr($cb, -$block_size);
1172 $len%= $block_size;
1173 }
1174 if ($len) {
1175 $iv = @mcrypt_generic($this->ecb, $iv);
1176 $plaintext.= $iv ^ substr($ciphertext, -$len);
1177 $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
1178 $pos = $len;
1179 }
1180
1181 return $plaintext;
1182 }
1183
1184 $plaintext = @mdecrypt_generic($this->demcrypt, $ciphertext);
1185
1186 if (!$this->continuousBuffer) {
1187 @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
1188 }
1189
1190 return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1191 }
1192
1193 if ($this->changed) {
1194 $this->_setup();
1195 $this->changed = false;
1196 }
1197 if ($this->use_inline_crypt) {
1198 $inline = $this->inline_crypt;
1199 return $inline('decrypt', $this, $ciphertext);
1200 }
1201
1202 $block_size = $this->block_size;
1203
1204 $buffer = &$this->debuffer;
1205 $plaintext = '';
1206 switch ($this->mode) {
1207 case CRYPT_MODE_ECB:
1208 for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1209 $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
1210 }
1211 break;
1212 case CRYPT_MODE_CBC:
1213 $xor = $this->decryptIV;
1214 for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1215 $block = substr($ciphertext, $i, $block_size);
1216 $plaintext.= $this->_decryptBlock($block) ^ $xor;
1217 $xor = $block;
1218 }
1219 if ($this->continuousBuffer) {
1220 $this->decryptIV = $xor;
1221 }
1222 break;
1223 case CRYPT_MODE_CTR:
1224 $xor = $this->decryptIV;
1225 if (strlen($buffer['ciphertext'])) {
1226 for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1227 $block = substr($ciphertext, $i, $block_size);
1228 if (strlen($block) > strlen($buffer['ciphertext'])) {
1229 $buffer['ciphertext'].= $this->_encryptBlock($xor);
1230 $this->_increment_str($xor);
1231 }
1232 $key = $this->_string_shift($buffer['ciphertext'], $block_size);
1233 $plaintext.= $block ^ $key;
1234 }
1235 } else {
1236 for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1237 $block = substr($ciphertext, $i, $block_size);
1238 $key = $this->_encryptBlock($xor);
1239 $this->_increment_str($xor);
1240 $plaintext.= $block ^ $key;
1241 }
1242 }
1243 if ($this->continuousBuffer) {
1244 $this->decryptIV = $xor;
1245 if ($start = strlen($ciphertext) % $block_size) {
1246 $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1247 }
1248 }
1249 break;
1250 case CRYPT_MODE_CFB:
1251 if ($this->continuousBuffer) {
1252 $iv = &$this->decryptIV;
1253 $pos = &$buffer['pos'];
1254 } else {
1255 $iv = $this->decryptIV;
1256 $pos = 0;
1257 }
1258 $len = strlen($ciphertext);
1259 $i = 0;
1260 if ($pos) {
1261 $orig_pos = $pos;
1262 $max = $block_size - $pos;
1263 if ($len >= $max) {
1264 $i = $max;
1265 $len-= $max;
1266 $pos = 0;
1267 } else {
1268 $i = $len;
1269 $pos+= $len;
1270 $len = 0;
1271 }
1272 // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1273 $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1274 $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1275 }
1276 while ($len >= $block_size) {
1277 $iv = $this->_encryptBlock($iv);
1278 $cb = substr($ciphertext, $i, $block_size);
1279 $plaintext.= $iv ^ $cb;
1280 $iv = $cb;
1281 $len-= $block_size;
1282 $i+= $block_size;
1283 }
1284 if ($len) {
1285 $iv = $this->_encryptBlock($iv);
1286 $plaintext.= $iv ^ substr($ciphertext, $i);
1287 $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
1288 $pos = $len;
1289 }
1290 break;
1291 case CRYPT_MODE_OFB:
1292 $xor = $this->decryptIV;
1293 if (strlen($buffer['xor'])) {
1294 for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1295 $block = substr($ciphertext, $i, $block_size);
1296 if (strlen($block) > strlen($buffer['xor'])) {
1297 $xor = $this->_encryptBlock($xor);
1298 $buffer['xor'].= $xor;
1299 }
1300 $key = $this->_string_shift($buffer['xor'], $block_size);
1301 $plaintext.= $block ^ $key;
1302 }
1303 } else {
1304 for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1305 $xor = $this->_encryptBlock($xor);
1306 $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
1307 }
1308 $key = $xor;
1309 }
1310 if ($this->continuousBuffer) {
1311 $this->decryptIV = $xor;
1312 if ($start = strlen($ciphertext) % $block_size) {
1313 $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1314 }
1315 }
1316 break;
1317 case CRYPT_MODE_STREAM:
1318 $plaintext = $this->_decryptBlock($ciphertext);
1319 break;
1320 }
1321 return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1322 }
1323
1324 /**
1325 * OpenSSL CTR Processor
1326 *
1327 * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1328 * for CTR is the same for both encrypting and decrypting this function is re-used by both Crypt_Base::encrypt()
1329 * and Crypt_Base::decrypt(). Also, OpenSSL doesn't implement CTR for all of it's symmetric ciphers so this
1330 * function will emulate CTR with ECB when necessary.
1331 *
1332 * @see self::encrypt()
1333 * @see self::decrypt()
1334 * @param string $plaintext
1335 * @param string $encryptIV
1336 * @param array $buffer
1337 * @return string
1338 * @access private
1339 */
1340 function _openssl_ctr_process($plaintext, &$encryptIV, &$buffer)
1341 {
1342 $ciphertext = '';
1343
1344 $block_size = $this->block_size;
1345 $key = $this->key;
1346
1347 if ($this->openssl_emulate_ctr) {
1348 $xor = $encryptIV;
1349 if (strlen($buffer['ciphertext'])) {
1350 for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1351 $block = substr($plaintext, $i, $block_size);
1352 if (strlen($block) > strlen($buffer['ciphertext'])) {
1353 $result = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1354 $result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
1355 $buffer['ciphertext'].= $result;
1356 }
1357 $this->_increment_str($xor);
1358 $otp = $this->_string_shift($buffer['ciphertext'], $block_size);
1359 $ciphertext.= $block ^ $otp;
1360 }
1361 } else {
1362 for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1363 $block = substr($plaintext, $i, $block_size);
1364 $otp = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1365 $otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp;
1366 $this->_increment_str($xor);
1367 $ciphertext.= $block ^ $otp;
1368 }
1369 }
1370 if ($this->continuousBuffer) {
1371 $encryptIV = $xor;
1372 if ($start = strlen($plaintext) % $block_size) {
1373 $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1374 }
1375 }
1376
1377 return $ciphertext;
1378 }
1379
1380 if (strlen($buffer['ciphertext'])) {
1381 $ciphertext = $plaintext ^ $this->_string_shift($buffer['ciphertext'], strlen($plaintext));
1382 $plaintext = substr($plaintext, strlen($ciphertext));
1383
1384 if (!strlen($plaintext)) {
1385 return $ciphertext;
1386 }
1387 }
1388
1389 $overflow = strlen($plaintext) % $block_size;
1390 if ($overflow) {
1391 $plaintext2 = $this->_string_pop($plaintext, $overflow); // ie. trim $plaintext to a multiple of $block_size and put rest of $plaintext in $plaintext2
1392 $encrypted = openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1393 $temp = $this->_string_pop($encrypted, $block_size);
1394 $ciphertext.= $encrypted . ($plaintext2 ^ $temp);
1395 if ($this->continuousBuffer) {
1396 $buffer['ciphertext'] = substr($temp, $overflow);
1397 $encryptIV = $temp;
1398 }
1399 } elseif (!strlen($buffer['ciphertext'])) {
1400 $ciphertext.= openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1401 $temp = $this->_string_pop($ciphertext, $block_size);
1402 if ($this->continuousBuffer) {
1403 $encryptIV = $temp;
1404 }
1405 }
1406 if ($this->continuousBuffer) {
1407 if (!defined('OPENSSL_RAW_DATA')) {
1408 $encryptIV.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1409 }
1410 $encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1411 if ($overflow) {
1412 $this->_increment_str($encryptIV);
1413 }
1414 }
1415
1416 return $ciphertext;
1417 }
1418
1419 /**
1420 * OpenSSL OFB Processor
1421 *
1422 * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1423 * for OFB is the same for both encrypting and decrypting this function is re-used by both Crypt_Base::encrypt()
1424 * and Crypt_Base::decrypt().
1425 *
1426 * @see self::encrypt()
1427 * @see self::decrypt()
1428 * @param string $plaintext
1429 * @param string $encryptIV
1430 * @param array $buffer
1431 * @return string
1432 * @access private
1433 */
1434 function _openssl_ofb_process($plaintext, &$encryptIV, &$buffer)
1435 {
1436 if (strlen($buffer['xor'])) {
1437 $ciphertext = $plaintext ^ $buffer['xor'];
1438 $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
1439 $plaintext = substr($plaintext, strlen($ciphertext));
1440 } else {
1441 $ciphertext = '';
1442 }
1443
1444 $block_size = $this->block_size;
1445
1446 $len = strlen($plaintext);
1447 $key = $this->key;
1448 $overflow = $len % $block_size;
1449
1450 if (strlen($plaintext)) {
1451 if ($overflow) {
1452 $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1453 $xor = $this->_string_pop($ciphertext, $block_size);
1454 if ($this->continuousBuffer) {
1455 $encryptIV = $xor;
1456 }
1457 $ciphertext.= $this->_string_shift($xor, $overflow) ^ substr($plaintext, -$overflow);
1458 if ($this->continuousBuffer) {
1459 $buffer['xor'] = $xor;
1460 }
1461 } else {
1462 $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1463 if ($this->continuousBuffer) {
1464 $encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size);
1465 }
1466 }
1467 }
1468
1469 return $ciphertext;
1470 }
1471
1472 /**
1473 * phpseclib <-> OpenSSL Mode Mapper
1474 *
1475 * May need to be overwritten by classes extending this one in some cases
1476 *
1477 * @return int
1478 * @access private
1479 */
1480 function _openssl_translate_mode()
1481 {
1482 switch ($this->mode) {
1483 case CRYPT_MODE_ECB:
1484 return 'ecb';
1485 case CRYPT_MODE_CBC:
1486 return 'cbc';
1487 case CRYPT_MODE_CTR:
1488 return 'ctr';
1489 case CRYPT_MODE_CFB:
1490 return 'cfb';
1491 case CRYPT_MODE_OFB:
1492 return 'ofb';
1493 }
1494 }
1495
1496 /**
1497 * Pad "packets".
1498 *
1499 * Block ciphers working by encrypting between their specified [$this->]block_size at a time
1500 * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
1501 * pad the input so that it is of the proper length.
1502 *
1503 * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
1504 * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
1505 * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1506 * transmitted separately)
1507 *
1508 * @see self::disablePadding()
1509 * @access public
1510 */
1511 function enablePadding()
1512 {
1513 $this->padding = true;
1514 }
1515
1516 /**
1517 * Do not pad packets.
1518 *
1519 * @see self::enablePadding()
1520 * @access public
1521 */
1522 function disablePadding()
1523 {
1524 $this->padding = false;
1525 }
1526
1527 /**
1528 * Treat consecutive "packets" as if they are a continuous buffer.
1529 *
1530 * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
1531 * will yield different outputs:
1532 *
1533 * <code>
1534 * echo $rijndael->encrypt(substr($plaintext, 0, 16));
1535 * echo $rijndael->encrypt(substr($plaintext, 16, 16));
1536 * </code>
1537 * <code>
1538 * echo $rijndael->encrypt($plaintext);
1539 * </code>
1540 *
1541 * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
1542 * another, as demonstrated with the following:
1543 *
1544 * <code>
1545 * $rijndael->encrypt(substr($plaintext, 0, 16));
1546 * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1547 * </code>
1548 * <code>
1549 * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1550 * </code>
1551 *
1552 * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
1553 * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
1554 * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
1555 *
1556 * Put another way, when the continuous buffer is enabled, the state of the Crypt_*() object changes after each
1557 * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
1558 * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
1559 * however, they are also less intuitive and more likely to cause you problems.
1560 *
1561 * @see self::disableContinuousBuffer()
1562 * @access public
1563 * @internal Could, but not must, extend by the child Crypt_* class
1564 */
1565 function enableContinuousBuffer()
1566 {
1567 if ($this->mode == CRYPT_MODE_ECB) {
1568 return;
1569 }
1570
1571 $this->continuousBuffer = true;
1572
1573 $this->_setEngine();
1574 }
1575
1576 /**
1577 * Treat consecutive packets as if they are a discontinuous buffer.
1578 *
1579 * The default behavior.
1580 *
1581 * @see self::enableContinuousBuffer()
1582 * @access public
1583 * @internal Could, but not must, extend by the child Crypt_* class
1584 */
1585 function disableContinuousBuffer()
1586 {
1587 if ($this->mode == CRYPT_MODE_ECB) {
1588 return;
1589 }
1590 if (!$this->continuousBuffer) {
1591 return;
1592 }
1593
1594 $this->continuousBuffer = false;
1595 $this->changed = true;
1596
1597 $this->_setEngine();
1598 }
1599
1600 /**
1601 * Test for engine validity
1602 *
1603 * @see self::Crypt_Base()
1604 * @param int $engine
1605 * @access public
1606 * @return bool
1607 */
1608 function isValidEngine($engine)
1609 {
1610 switch ($engine) {
1611 case CRYPT_ENGINE_OPENSSL:
1612 if ($this->mode == CRYPT_MODE_STREAM && $this->continuousBuffer) {
1613 return false;
1614 }
1615 $this->openssl_emulate_ctr = false;
1616 $result = $this->cipher_name_openssl &&
1617 extension_loaded('openssl') &&
1618 // PHP 5.3.0 - 5.3.2 did not let you set IV's
1619 version_compare(PHP_VERSION, '5.3.3', '>=');
1620 if (!$result) {
1621 return false;
1622 }
1623
1624 // prior to PHP 5.4.0 OPENSSL_RAW_DATA and OPENSSL_ZERO_PADDING were not defined. instead of expecting an integer
1625 // $options openssl_encrypt expected a boolean $raw_data.
1626 if (!defined('OPENSSL_RAW_DATA')) {
1627 $this->openssl_options = true;
1628 } else {
1629 $this->openssl_options = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;
1630 }
1631
1632 $methods = openssl_get_cipher_methods();
1633 if (in_array($this->cipher_name_openssl, $methods)) {
1634 return true;
1635 }
1636 // not all of openssl's symmetric cipher's support ctr. for those
1637 // that don't we'll emulate it
1638 switch ($this->mode) {
1639 case CRYPT_MODE_CTR:
1640 if (in_array($this->cipher_name_openssl_ecb, $methods)) {
1641 $this->openssl_emulate_ctr = true;
1642 return true;
1643 }
1644 }
1645 return false;
1646 case CRYPT_ENGINE_MCRYPT:
1647 return $this->cipher_name_mcrypt &&
1648 extension_loaded('mcrypt') &&
1649 in_array($this->cipher_name_mcrypt, @mcrypt_list_algorithms());
1650 case CRYPT_ENGINE_INTERNAL:
1651 return true;
1652 }
1653
1654 return false;
1655 }
1656
1657 /**
1658 * Sets the preferred crypt engine
1659 *
1660 * Currently, $engine could be:
1661 *
1662 * - CRYPT_ENGINE_OPENSSL [very fast]
1663 *
1664 * - CRYPT_ENGINE_MCRYPT [fast]
1665 *
1666 * - CRYPT_ENGINE_INTERNAL [slow]
1667 *
1668 * If the preferred crypt engine is not available the fastest available one will be used
1669 *
1670 * @see self::Crypt_Base()
1671 * @param int $engine
1672 * @access public
1673 */
1674 function setPreferredEngine($engine)
1675 {
1676 switch ($engine) {
1677 //case CRYPT_ENGINE_OPENSSL:
1678 case CRYPT_ENGINE_MCRYPT:
1679 case CRYPT_ENGINE_INTERNAL:
1680 $this->preferredEngine = $engine;
1681 break;
1682 default:
1683 $this->preferredEngine = CRYPT_ENGINE_OPENSSL;
1684 }
1685
1686 $this->_setEngine();
1687 }
1688
1689 /**
1690 * Returns the engine currently being utilized
1691 *
1692 * @see self::_setEngine()
1693 * @access public
1694 */
1695 function getEngine()
1696 {
1697 return $this->engine;
1698 }
1699
1700 /**
1701 * Sets the engine as appropriate
1702 *
1703 * @see self::Crypt_Base()
1704 * @access private
1705 */
1706 function _setEngine()
1707 {
1708 $this->engine = null;
1709
1710 $candidateEngines = array(
1711 $this->preferredEngine,
1712 CRYPT_ENGINE_OPENSSL,
1713 CRYPT_ENGINE_MCRYPT
1714 );
1715 foreach ($candidateEngines as $engine) {
1716 if ($this->isValidEngine($engine)) {
1717 $this->engine = $engine;
1718 break;
1719 }
1720 }
1721 if (!$this->engine) {
1722 $this->engine = CRYPT_ENGINE_INTERNAL;
1723 }
1724
1725 if ($this->engine != CRYPT_ENGINE_MCRYPT && $this->enmcrypt) {
1726 // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed,
1727 // (re)open them with the module named in $this->cipher_name_mcrypt
1728 @mcrypt_module_close($this->enmcrypt);
1729 @mcrypt_module_close($this->demcrypt);
1730 $this->enmcrypt = null;
1731 $this->demcrypt = null;
1732
1733 if ($this->ecb) {
1734 @mcrypt_module_close($this->ecb);
1735 $this->ecb = null;
1736 }
1737 }
1738
1739 $this->changed = true;
1740 }
1741
1742 /**
1743 * Encrypts a block
1744 *
1745 * @access private
1746 * @param string $in
1747 * @return string
1748 * @internal Must be extended by the child Crypt_* class
1749 */
1750 function _encryptBlock($in)
1751 {
1752 user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1753 }
1754
1755 /**
1756 * Decrypts a block
1757 *
1758 * @access private
1759 * @param string $in
1760 * @return string
1761 * @internal Must be extended by the child Crypt_* class
1762 */
1763 function _decryptBlock($in)
1764 {
1765 user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1766 }
1767
1768 /**
1769 * Setup the key (expansion)
1770 *
1771 * Only used if $engine == CRYPT_ENGINE_INTERNAL
1772 *
1773 * @see self::_setup()
1774 * @access private
1775 * @internal Must be extended by the child Crypt_* class
1776 */
1777 function _setupKey()
1778 {
1779 user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1780 }
1781
1782 /**
1783 * Setup the CRYPT_ENGINE_INTERNAL $engine
1784 *
1785 * (re)init, if necessary, the internal cipher $engine and flush all $buffers
1786 * Used (only) if $engine == CRYPT_ENGINE_INTERNAL
1787 *
1788 * _setup() will be called each time if $changed === true
1789 * typically this happens when using one or more of following public methods:
1790 *
1791 * - setKey()
1792 *
1793 * - setIV()
1794 *
1795 * - disableContinuousBuffer()
1796 *
1797 * - First run of encrypt() / decrypt() with no init-settings
1798 *
1799 * @see self::setKey()
1800 * @see self::setIV()
1801 * @see self::disableContinuousBuffer()
1802 * @access private
1803 * @internal _setup() is always called before en/decryption.
1804 * @internal Could, but not must, extend by the child Crypt_* class
1805 */
1806 function _setup()
1807 {
1808 $this->_clearBuffers();
1809 $this->_setupKey();
1810
1811 if ($this->use_inline_crypt) {
1812 $this->_setupInlineCrypt();
1813 }
1814 }
1815
1816 /**
1817 * Setup the CRYPT_ENGINE_MCRYPT $engine
1818 *
1819 * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers
1820 * Used (only) if $engine = CRYPT_ENGINE_MCRYPT
1821 *
1822 * _setupMcrypt() will be called each time if $changed === true
1823 * typically this happens when using one or more of following public methods:
1824 *
1825 * - setKey()
1826 *
1827 * - setIV()
1828 *
1829 * - disableContinuousBuffer()
1830 *
1831 * - First run of encrypt() / decrypt()
1832 *
1833 * @see self::setKey()
1834 * @see self::setIV()
1835 * @see self::disableContinuousBuffer()
1836 * @access private
1837 * @internal Could, but not must, extend by the child Crypt_* class
1838 */
1839 function _setupMcrypt()
1840 {
1841 $this->_clearBuffers();
1842 $this->enchanged = $this->dechanged = true;
1843
1844 if (!isset($this->enmcrypt)) {
1845 static $mcrypt_modes = array(
1846 CRYPT_MODE_CTR => 'ctr',
1847 CRYPT_MODE_ECB => MCRYPT_MODE_ECB,
1848 CRYPT_MODE_CBC => MCRYPT_MODE_CBC,
1849 CRYPT_MODE_CFB => 'ncfb',
1850 CRYPT_MODE_OFB => MCRYPT_MODE_NOFB,
1851 CRYPT_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 == CRYPT_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 == CRYPT_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 == CRYPT_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 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 Crypt_Base() 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 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 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 CRYPT_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 CRYPT_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 CRYPT_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 CRYPT_MODE_OFB:
2425 $encrypt = $init_encrypt . '
2426 $_ciphertext = "";
2427 $_plaintext_len = strlen($_text);
2428 $_xor = $self->encryptIV;
2429 $_buffer = &$self->enbuffer;
2430
2431 if (strlen($_buffer["xor"])) {
2432 for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2433 $_block = substr($_text, $_i, '.$block_size.');
2434 if (strlen($_block) > strlen($_buffer["xor"])) {
2435 $in = $_xor;
2436 '.$encrypt_block.'
2437 $_xor = $in;
2438 $_buffer["xor"].= $_xor;
2439 }
2440 $_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
2441 $_ciphertext.= $_block ^ $_key;
2442 }
2443 } else {
2444 for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2445 $in = $_xor;
2446 '.$encrypt_block.'
2447 $_xor = $in;
2448 $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
2449 }
2450 $_key = $_xor;
2451 }
2452 if ($self->continuousBuffer) {
2453 $self->encryptIV = $_xor;
2454 if ($_start = $_plaintext_len % '.$block_size.') {
2455 $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
2456 }
2457 }
2458 return $_ciphertext;
2459 ';
2460
2461 $decrypt = $init_encrypt . '
2462 $_plaintext = "";
2463 $_ciphertext_len = strlen($_text);
2464 $_xor = $self->decryptIV;
2465 $_buffer = &$self->debuffer;
2466
2467 if (strlen($_buffer["xor"])) {
2468 for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2469 $_block = substr($_text, $_i, '.$block_size.');
2470 if (strlen($_block) > strlen($_buffer["xor"])) {
2471 $in = $_xor;
2472 '.$encrypt_block.'
2473 $_xor = $in;
2474 $_buffer["xor"].= $_xor;
2475 }
2476 $_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
2477 $_plaintext.= $_block ^ $_key;
2478 }
2479 } else {
2480 for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2481 $in = $_xor;
2482 '.$encrypt_block.'
2483 $_xor = $in;
2484 $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
2485 }
2486 $_key = $_xor;
2487 }
2488 if ($self->continuousBuffer) {
2489 $self->decryptIV = $_xor;
2490 if ($_start = $_ciphertext_len % '.$block_size.') {
2491 $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
2492 }
2493 }
2494 return $_plaintext;
2495 ';
2496 break;
2497 case CRYPT_MODE_STREAM:
2498 $encrypt = $init_encrypt . '
2499 $_ciphertext = "";
2500 '.$encrypt_block.'
2501 return $_ciphertext;
2502 ';
2503 $decrypt = $init_decrypt . '
2504 $_plaintext = "";
2505 '.$decrypt_block.'
2506 return $_plaintext;
2507 ';
2508 break;
2509 // case CRYPT_MODE_CBC:
2510 default:
2511 $encrypt = $init_encrypt . '
2512 $_ciphertext = "";
2513 $_plaintext_len = strlen($_text);
2514
2515 $in = $self->encryptIV;
2516
2517 for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2518 $in = substr($_text, $_i, '.$block_size.') ^ $in;
2519 '.$encrypt_block.'
2520 $_ciphertext.= $in;
2521 }
2522
2523 if ($self->continuousBuffer) {
2524 $self->encryptIV = $in;
2525 }
2526
2527 return $_ciphertext;
2528 ';
2529
2530 $decrypt = $init_decrypt . '
2531 $_plaintext = "";
2532 $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
2533 $_ciphertext_len = strlen($_text);
2534
2535 $_iv = $self->decryptIV;
2536
2537 for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2538 $in = $_block = substr($_text, $_i, '.$block_size.');
2539 '.$decrypt_block.'
2540 $_plaintext.= $in ^ $_iv;
2541 $_iv = $_block;
2542 }
2543
2544 if ($self->continuousBuffer) {
2545 $self->decryptIV = $_iv;
2546 }
2547
2548 return $self->_unpad($_plaintext);
2549 ';
2550 break;
2551 }
2552
2553 // Create the $inline function and return its name as string. Ready to run!
2554 if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
2555 eval('$func = function ($_action, &$self, $_text) { ' . $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' } };');
2556 return $func;
2557 }
2558
2559 return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }');
2560 }
2561
2562 /**
2563 * Holds the lambda_functions table (classwide)
2564 *
2565 * Each name of the lambda function, created from
2566 * _setupInlineCrypt() && _createInlineCryptFunction()
2567 * is stored, classwide (!), here for reusing.
2568 *
2569 * The string-based index of $function is a classwide
2570 * unique value representing, at least, the $mode of
2571 * operation (or more... depends of the optimizing level)
2572 * for which $mode the lambda function was created.
2573 *
2574 * @access private
2575 * @return array &$functions
2576 */
2577 function &_getLambdaFunctions()
2578 {
2579 static $functions = array();
2580 return $functions;
2581 }
2582
2583 /**
2584 * Generates a digest from $bytes
2585 *
2586 * @see self::_setupInlineCrypt()
2587 * @access private
2588 * @param $bytes
2589 * @return string
2590 */
2591 function _hashInlineCryptFunction($bytes)
2592 {
2593 if (!defined('CRYPT_BASE_WHIRLPOOL_AVAILABLE')) {
2594 define('CRYPT_BASE_WHIRLPOOL_AVAILABLE', (bool)(extension_loaded('hash') && in_array('whirlpool', hash_algos())));
2595 }
2596
2597 $result = '';
2598 $hash = $bytes;
2599
2600 switch (true) {
2601 case CRYPT_BASE_WHIRLPOOL_AVAILABLE:
2602 foreach (str_split($bytes, 64) as $t) {
2603 $hash = hash('whirlpool', $hash, true);
2604 $result .= $t ^ $hash;
2605 }
2606 return $result . hash('whirlpool', $hash, true);
2607 default:
2608 $len = strlen($bytes);
2609 for ($i = 0; $i < $len; $i+=20) {
2610 $t = substr($bytes, $i, 20);
2611 $hash = pack('H*', sha1($hash));
2612 $result .= $t ^ $hash;
2613 }
2614 return $result . pack('H*', sha1($hash));
2615 }
2616 }
2617
2618 /**
2619 * Convert float to int
2620 *
2621 * On 32-bit Linux installs running PHP < 5.3 converting floats to ints doesn't always work
2622 *
2623 * @access private
2624 * @param string $x
2625 * @return int
2626 */
2627 function safe_intval($x)
2628 {
2629 switch (true) {
2630 case is_int($x):
2631 // PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding"
2632 case version_compare(PHP_VERSION, '5.3.0') >= 0 && (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
2633 // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
2634 case (PHP_OS & "\xDF\xDF\xDF") === 'WIN':
2635 return $x;
2636 }
2637 return (fmod($x, 0x80000000) & 0x7FFFFFFF) |
2638 ((fmod(floor($x / 0x80000000), 2) & 1) << 31);
2639 }
2640
2641 /**
2642 * eval()'able string for in-line float to int
2643 *
2644 * @access private
2645 * @return string
2646 */
2647 function safe_intval_inline()
2648 {
2649 // on 32-bit linux systems with PHP < 5.3 float to integer conversion is bad
2650 switch (true) {
2651 case defined('PHP_INT_SIZE') && PHP_INT_SIZE == 8:
2652 case version_compare(PHP_VERSION, '5.3.0') >= 0 && (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
2653 case (PHP_OS & "\xDF\xDF\xDF") === 'WIN':
2654 return '%s';
2655 break;
2656 default:
2657 $safeint = '(is_int($temp = %s) ? $temp : (fmod($temp, 0x80000000) & 0x7FFFFFFF) | ';
2658 return $safeint . '((fmod(floor($temp / 0x80000000), 2) & 1) << 31))';
2659 }
2660 }
2661 }
2662