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