xref: /dokuwiki/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.php (revision b2c5d21049ac0969066d59237f16a2a155c53677)
1<?php
2
3/**
4 * Base Class for all \phpseclib3\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 \phpseclib3\Crypt\* cipher class should extend \phpseclib3\Crypt\Common\SymmetricKey
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 \phpseclib3\Crypt\Common\SymmetricKey
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 * @author    Jim Wigginton <terrafrost@php.net>
29 * @author    Hans-Juergen Petrich <petrich@tronic-media.com>
30 * @copyright 2007 Jim Wigginton
31 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
32 * @link      http://phpseclib.sourceforge.net
33 */
34
35namespace phpseclib3\Crypt\Common;
36
37use phpseclib3\Common\Functions\Strings;
38use phpseclib3\Crypt\Blowfish;
39use phpseclib3\Crypt\Hash;
40use phpseclib3\Exception\BadDecryptionException;
41use phpseclib3\Exception\BadModeException;
42use phpseclib3\Exception\InconsistentSetupException;
43use phpseclib3\Exception\InsufficientSetupException;
44use phpseclib3\Exception\UnsupportedAlgorithmException;
45use phpseclib3\Math\BigInteger;
46use phpseclib3\Math\BinaryField;
47use phpseclib3\Math\PrimeField;
48
49/**
50 * Base Class for all \phpseclib3\Crypt\* cipher classes
51 *
52 * @author  Jim Wigginton <terrafrost@php.net>
53 * @author  Hans-Juergen Petrich <petrich@tronic-media.com>
54 */
55abstract class SymmetricKey
56{
57    /**
58     * Encrypt / decrypt using the Counter mode.
59     *
60     * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
61     *
62     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
63     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
64     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
65     */
66    const MODE_CTR = -1;
67    /**
68     * Encrypt / decrypt using the Electronic Code Book mode.
69     *
70     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
71     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
72     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
73     */
74    const MODE_ECB = 1;
75    /**
76     * Encrypt / decrypt using the Code Book Chaining mode.
77     *
78     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
79     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
80     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
81     */
82    const MODE_CBC = 2;
83    /**
84     * Encrypt / decrypt using the Cipher Feedback mode.
85     *
86     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
87     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
88     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
89     */
90    const MODE_CFB = 3;
91    /**
92     * Encrypt / decrypt using the Cipher Feedback mode (8bit)
93     *
94     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
95     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
96     */
97    const MODE_CFB8 = 7;
98    /**
99     * Encrypt / decrypt using the Output Feedback mode (8bit)
100     *
101     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
102     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
103     */
104    const MODE_OFB8 = 8;
105    /**
106     * Encrypt / decrypt using the Output Feedback mode.
107     *
108     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
109     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
110     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
111     */
112    const MODE_OFB = 4;
113    /**
114     * Encrypt / decrypt using Galois/Counter mode.
115     *
116     * @link https://en.wikipedia.org/wiki/Galois/Counter_Mode
117     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
118     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
119     */
120    const MODE_GCM = 5;
121    /**
122     * Encrypt / decrypt using streaming mode.
123     *
124     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
125     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
126     */
127    const MODE_STREAM = 6;
128
129    /**
130     * Mode Map
131     *
132     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
133     */
134    const MODE_MAP = [
135        'ctr'    => self::MODE_CTR,
136        'ecb'    => self::MODE_ECB,
137        'cbc'    => self::MODE_CBC,
138        'cfb'    => self::MODE_CFB,
139        'cfb8'   => self::MODE_CFB8,
140        'ofb'    => self::MODE_OFB,
141        'ofb8'   => self::MODE_OFB8,
142        'gcm'    => self::MODE_GCM,
143        'stream' => self::MODE_STREAM
144    ];
145
146    /**
147     * Base value for the internal implementation $engine switch
148     *
149     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
150     */
151    const ENGINE_INTERNAL = 1;
152    /**
153     * Base value for the eval() implementation $engine switch
154     *
155     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
156     */
157    const ENGINE_EVAL = 2;
158    /**
159     * Base value for the mcrypt implementation $engine switch
160     *
161     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
162     */
163    const ENGINE_MCRYPT = 3;
164    /**
165     * Base value for the openssl implementation $engine switch
166     *
167     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
168     */
169    const ENGINE_OPENSSL = 4;
170    /**
171     * Base value for the libsodium implementation $engine switch
172     *
173     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
174     */
175    const ENGINE_LIBSODIUM = 5;
176    /**
177     * Base value for the openssl / gcm implementation $engine switch
178     *
179     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
180     */
181    const ENGINE_OPENSSL_GCM = 6;
182
183    /**
184     * Engine Reverse Map
185     *
186     * @see \phpseclib3\Crypt\Common\SymmetricKey::getEngine()
187     */
188    const ENGINE_MAP = [
189        self::ENGINE_INTERNAL    => 'PHP',
190        self::ENGINE_EVAL        => 'Eval',
191        self::ENGINE_MCRYPT      => 'mcrypt',
192        self::ENGINE_OPENSSL     => 'OpenSSL',
193        self::ENGINE_LIBSODIUM   => 'libsodium',
194        self::ENGINE_OPENSSL_GCM => 'OpenSSL (GCM)'
195    ];
196
197    /**
198     * The Encryption Mode
199     *
200     * @see self::__construct()
201     * @var int
202     */
203    protected $mode;
204
205    /**
206     * The Block Length of the block cipher
207     *
208     * @var int
209     */
210    protected $block_size = 16;
211
212    /**
213     * The Key
214     *
215     * @see self::setKey()
216     * @var string
217     */
218    protected $key = false;
219
220    /**
221     * HMAC Key
222     *
223     * @see self::setupGCM()
224     * @var ?string
225     */
226    protected $hKey = false;
227
228    /**
229     * The Initialization Vector
230     *
231     * @see self::setIV()
232     * @var string
233     */
234    protected $iv = false;
235
236    /**
237     * A "sliding" Initialization Vector
238     *
239     * @see self::enableContinuousBuffer()
240     * @see self::clearBuffers()
241     * @var string
242     */
243    protected $encryptIV;
244
245    /**
246     * A "sliding" Initialization Vector
247     *
248     * @see self::enableContinuousBuffer()
249     * @see self::clearBuffers()
250     * @var string
251     */
252    protected $decryptIV;
253
254    /**
255     * Continuous Buffer status
256     *
257     * @see self::enableContinuousBuffer()
258     * @var bool
259     */
260    protected $continuousBuffer = false;
261
262    /**
263     * Encryption buffer for CTR, OFB and CFB modes
264     *
265     * @see self::encrypt()
266     * @see self::clearBuffers()
267     * @var array
268     */
269    protected $enbuffer;
270
271    /**
272     * Decryption buffer for CTR, OFB and CFB modes
273     *
274     * @see self::decrypt()
275     * @see self::clearBuffers()
276     * @var array
277     */
278    protected $debuffer;
279
280    /**
281     * mcrypt resource for encryption
282     *
283     * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
284     * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
285     *
286     * @see self::encrypt()
287     * @var resource
288     */
289    private $enmcrypt;
290
291    /**
292     * mcrypt resource for decryption
293     *
294     * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
295     * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
296     *
297     * @see self::decrypt()
298     * @var resource
299     */
300    private $demcrypt;
301
302    /**
303     * Does the enmcrypt resource need to be (re)initialized?
304     *
305     * @see \phpseclib3\Crypt\Twofish::setKey()
306     * @see \phpseclib3\Crypt\Twofish::setIV()
307     * @var bool
308     */
309    private $enchanged = true;
310
311    /**
312     * Does the demcrypt resource need to be (re)initialized?
313     *
314     * @see \phpseclib3\Crypt\Twofish::setKey()
315     * @see \phpseclib3\Crypt\Twofish::setIV()
316     * @var bool
317     */
318    private $dechanged = true;
319
320    /**
321     * mcrypt resource for CFB mode
322     *
323     * mcrypt's CFB mode, in (and only in) buffered context,
324     * is broken, so phpseclib implements the CFB mode by it self,
325     * even when the mcrypt php extension is available.
326     *
327     * In order to do the CFB-mode work (fast) phpseclib
328     * use a separate ECB-mode mcrypt resource.
329     *
330     * @link http://phpseclib.sourceforge.net/cfb-demo.phps
331     * @see self::encrypt()
332     * @see self::decrypt()
333     * @see self::setupMcrypt()
334     * @var resource
335     */
336    private $ecb;
337
338    /**
339     * Optimizing value while CFB-encrypting
340     *
341     * Only relevant if $continuousBuffer enabled
342     * and $engine == self::ENGINE_MCRYPT
343     *
344     * It's faster to re-init $enmcrypt if
345     * $buffer bytes > $cfb_init_len than
346     * using the $ecb resource furthermore.
347     *
348     * This value depends of the chosen cipher
349     * and the time it would be needed for it's
350     * initialization [by mcrypt_generic_init()]
351     * which, typically, depends on the complexity
352     * on its internaly Key-expanding algorithm.
353     *
354     * @see self::encrypt()
355     * @var int
356     */
357    protected $cfb_init_len = 600;
358
359    /**
360     * Does internal cipher state need to be (re)initialized?
361     *
362     * @see self::setKey()
363     * @see self::setIV()
364     * @see self::disableContinuousBuffer()
365     * @var bool
366     */
367    protected $changed = true;
368
369    /**
370     * Does Eval engie need to be (re)initialized?
371     *
372     * @see self::setup()
373     * @var bool
374     */
375    protected $nonIVChanged = true;
376
377    /**
378     * Padding status
379     *
380     * @see self::enablePadding()
381     * @var bool
382     */
383    private $padding = true;
384
385    /**
386     * Is the mode one that is paddable?
387     *
388     * @see self::__construct()
389     * @var bool
390     */
391    private $paddable = false;
392
393    /**
394     * Holds which crypt engine internaly should be use,
395     * which will be determined automatically on __construct()
396     *
397     * Currently available $engines are:
398     * - self::ENGINE_LIBSODIUM   (very fast, php-extension: libsodium, extension_loaded('libsodium') required)
399     * - self::ENGINE_OPENSSL_GCM (very fast, php-extension: openssl, extension_loaded('openssl') required)
400     * - self::ENGINE_OPENSSL     (very fast, php-extension: openssl, extension_loaded('openssl') required)
401     * - self::ENGINE_MCRYPT      (fast, php-extension: mcrypt, extension_loaded('mcrypt') required)
402     * - self::ENGINE_EVAL        (medium, pure php-engine, no php-extension required)
403     * - self::ENGINE_INTERNAL    (slower, pure php-engine, no php-extension required)
404     *
405     * @see self::setEngine()
406     * @see self::encrypt()
407     * @see self::decrypt()
408     * @var int
409     */
410    protected $engine;
411
412    /**
413     * Holds the preferred crypt engine
414     *
415     * @see self::setEngine()
416     * @see self::setPreferredEngine()
417     * @var int
418     */
419    private $preferredEngine;
420
421    /**
422     * The mcrypt specific name of the cipher
423     *
424     * Only used if $engine == self::ENGINE_MCRYPT
425     *
426     * @link http://www.php.net/mcrypt_module_open
427     * @link http://www.php.net/mcrypt_list_algorithms
428     * @see self::setupMcrypt()
429     * @var string
430     */
431    protected $cipher_name_mcrypt;
432
433    /**
434     * The openssl specific name of the cipher
435     *
436     * Only used if $engine == self::ENGINE_OPENSSL
437     *
438     * @link http://www.php.net/openssl-get-cipher-methods
439     * @var string
440     */
441    protected $cipher_name_openssl;
442
443    /**
444     * The openssl specific name of the cipher in ECB mode
445     *
446     * If OpenSSL does not support the mode we're trying to use (CTR)
447     * it can still be emulated with ECB mode.
448     *
449     * @link http://www.php.net/openssl-get-cipher-methods
450     * @var string
451     */
452    protected $cipher_name_openssl_ecb;
453
454    /**
455     * The default salt used by setPassword()
456     *
457     * @see self::setPassword()
458     * @var string
459     */
460    private $password_default_salt = 'phpseclib/salt';
461
462    /**
463     * The name of the performance-optimized callback function
464     *
465     * Used by encrypt() / decrypt()
466     * only if $engine == self::ENGINE_INTERNAL
467     *
468     * @see self::encrypt()
469     * @see self::decrypt()
470     * @see self::setupInlineCrypt()
471     * @var Callback
472     */
473    protected $inline_crypt;
474
475    /**
476     * If OpenSSL can be used in ECB but not in CTR we can emulate CTR
477     *
478     * @see self::openssl_ctr_process()
479     * @var bool
480     */
481    private $openssl_emulate_ctr = false;
482
483    /**
484     * Don't truncate / null pad key
485     *
486     * @see self::clearBuffers()
487     * @var bool
488     */
489    private $skip_key_adjustment = false;
490
491    /**
492     * Has the key length explicitly been set or should it be derived from the key, itself?
493     *
494     * @see self::setKeyLength()
495     * @var bool
496     */
497    protected $explicit_key_length = false;
498
499    /**
500     * Hash subkey for GHASH
501     *
502     * @see self::setupGCM()
503     * @see self::ghash()
504     * @var BinaryField\Integer
505     */
506    private $h;
507
508    /**
509     * Additional authenticated data
510     *
511     * @var string
512     */
513    protected $aad = '';
514
515    /**
516     * Authentication Tag produced after a round of encryption
517     *
518     * @var string
519     */
520    protected $newtag = false;
521
522    /**
523     * Authentication Tag to be verified during decryption
524     *
525     * @var string
526     */
527    protected $oldtag = false;
528
529    /**
530     * GCM Binary Field
531     *
532     * @see self::__construct()
533     * @see self::ghash()
534     * @var BinaryField
535     */
536    private static $gcmField;
537
538    /**
539     * Poly1305 Prime Field
540     *
541     * @see self::enablePoly1305()
542     * @see self::poly1305()
543     * @var PrimeField
544     */
545    private static $poly1305Field;
546
547    /**
548     * Flag for using regular vs "safe" intval
549     *
550     * @see self::initialize_static_variables()
551     * @var boolean
552     */
553    protected static $use_reg_intval;
554
555    /**
556     * Poly1305 Key
557     *
558     * @see self::setPoly1305Key()
559     * @see self::poly1305()
560     * @var string
561     */
562    protected $poly1305Key;
563
564    /**
565     * Poly1305 Flag
566     *
567     * @see self::setPoly1305Key()
568     * @see self::enablePoly1305()
569     * @var boolean
570     */
571    protected $usePoly1305 = false;
572
573    /**
574     * The Original Initialization Vector
575     *
576     * GCM uses the nonce to build the IV but we want to be able to distinguish between nonce-derived
577     * IV's and user-set IV's
578     *
579     * @see self::setIV()
580     * @var string
581     */
582    private $origIV = false;
583
584    /**
585     * Nonce
586     *
587     * Only used with GCM. We could re-use setIV() but nonce's can be of a different length and
588     * toggling between GCM and other modes could be more complicated if we re-used setIV()
589     *
590     * @see self::setNonce()
591     * @var string
592     */
593    protected $nonce = false;
594
595    /**
596     * Default Constructor.
597     *
598     * $mode could be:
599     *
600     * - ecb
601     *
602     * - cbc
603     *
604     * - ctr
605     *
606     * - cfb
607     *
608     * - cfb8
609     *
610     * - ofb
611     *
612     * - ofb8
613     *
614     * - gcm
615     *
616     * @param string $mode
617     * @throws BadModeException if an invalid / unsupported mode is provided
618     */
619    public function __construct($mode)
620    {
621        $mode = strtolower($mode);
622        // necessary because of 5.6 compatibility; we can't do isset(self::MODE_MAP[$mode]) in 5.6
623        $map = self::MODE_MAP;
624        if (!isset($map[$mode])) {
625            throw new BadModeException('No valid mode has been specified');
626        }
627
628        $mode = self::MODE_MAP[$mode];
629
630        // $mode dependent settings
631        switch ($mode) {
632            case self::MODE_ECB:
633            case self::MODE_CBC:
634                $this->paddable = true;
635                break;
636            case self::MODE_CTR:
637            case self::MODE_CFB:
638            case self::MODE_CFB8:
639            case self::MODE_OFB:
640            case self::MODE_OFB8:
641            case self::MODE_STREAM:
642                $this->paddable = false;
643                break;
644            case self::MODE_GCM:
645                if ($this->block_size != 16) {
646                    throw new BadModeException('GCM is only valid for block ciphers with a block size of 128 bits');
647                }
648                if (!isset(self::$gcmField)) {
649                    self::$gcmField = new BinaryField(128, 7, 2, 1, 0);
650                }
651                $this->paddable = false;
652                break;
653            default:
654                throw new BadModeException('No valid mode has been specified');
655        }
656
657        $this->mode = $mode;
658
659        static::initialize_static_variables();
660    }
661
662    /**
663     * Initialize static variables
664     */
665    protected static function initialize_static_variables()
666    {
667        if (!isset(self::$use_reg_intval)) {
668            switch (true) {
669                // PHP 8.5, per https://www.php.net/manual/en/migration85.incompatible.php, now emits a warning
670                // "when casting floats (or strings that look like floats) to int if they cannot be represented as one"
671                case PHP_VERSION_ID >= 80500 && PHP_INT_SIZE == 4:
672                    self::$use_reg_intval = false;
673                    break;
674                // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
675                case (PHP_OS & "\xDF\xDF\xDF") === 'WIN':
676                case !function_exists('php_uname'):
677                case !is_string(php_uname('m')):
678                case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
679                case defined('PHP_INT_SIZE') && PHP_INT_SIZE == 8:
680                    self::$use_reg_intval = true;
681                    break;
682                case (php_uname('m') & "\xDF\xDF\xDF") == 'ARM':
683                    switch (true) {
684                        /* PHP 7.0.0 introduced a bug that affected 32-bit ARM processors:
685
686                           https://github.com/php/php-src/commit/716da71446ebbd40fa6cf2cea8a4b70f504cc3cd
687
688                           altho the changelogs make no mention of it, this bug was fixed with this commit:
689
690                           https://github.com/php/php-src/commit/c1729272b17a1fe893d1a54e423d3b71470f3ee8
691
692                           affected versions of PHP are: 7.0.x, 7.1.0 - 7.1.23 and 7.2.0 - 7.2.11 */
693                        case PHP_VERSION_ID >= 70000 && PHP_VERSION_ID <= 70123:
694                        case PHP_VERSION_ID >= 70200 && PHP_VERSION_ID <= 70211:
695                            self::$use_reg_intval = false;
696                            break;
697                        default:
698                            self::$use_reg_intval = true;
699                    }
700            }
701        }
702    }
703
704    /**
705     * Sets the initialization vector.
706     *
707     * setIV() is not required when ecb or gcm modes are being used.
708     *
709     * {@internal Can be overwritten by a sub class, but does not have to be}
710     *
711     * @param string $iv
712     * @throws \LengthException if the IV length isn't equal to the block size
713     * @throws \BadMethodCallException if an IV is provided when one shouldn't be
714     */
715    public function setIV($iv)
716    {
717        if ($this->mode == self::MODE_ECB) {
718            throw new \BadMethodCallException('This mode does not require an IV.');
719        }
720
721        if ($this->mode == self::MODE_GCM) {
722            throw new \BadMethodCallException('Use setNonce instead');
723        }
724
725        if (!$this->usesIV()) {
726            throw new \BadMethodCallException('This algorithm does not use an IV.');
727        }
728
729        if (strlen($iv) != $this->block_size) {
730            throw new \LengthException('Received initialization vector of size ' . strlen($iv) . ', but size ' . $this->block_size . ' is required');
731        }
732
733        $this->iv = $this->origIV = $iv;
734        $this->changed = true;
735    }
736
737    /**
738     * Enables Poly1305 mode.
739     *
740     * Once enabled Poly1305 cannot be disabled.
741     *
742     * @throws \BadMethodCallException if Poly1305 is enabled whilst in GCM mode
743     */
744    public function enablePoly1305()
745    {
746        if ($this->mode == self::MODE_GCM) {
747            throw new \BadMethodCallException('Poly1305 cannot be used in GCM mode');
748        }
749
750        $this->usePoly1305 = true;
751    }
752
753    /**
754     * Enables Poly1305 mode.
755     *
756     * Once enabled Poly1305 cannot be disabled. If $key is not passed then an attempt to call createPoly1305Key
757     * will be made.
758     *
759     * @param string $key optional
760     * @throws \LengthException if the key isn't long enough
761     * @throws \BadMethodCallException if Poly1305 is enabled whilst in GCM mode
762     */
763    public function setPoly1305Key($key = null)
764    {
765        if ($this->mode == self::MODE_GCM) {
766            throw new \BadMethodCallException('Poly1305 cannot be used in GCM mode');
767        }
768
769        if (!is_string($key) || strlen($key) != 32) {
770            throw new \LengthException('The Poly1305 key must be 32 bytes long (256 bits)');
771        }
772
773        if (!isset(self::$poly1305Field)) {
774            // 2^130-5
775            self::$poly1305Field = new PrimeField(new BigInteger('3fffffffffffffffffffffffffffffffb', 16));
776        }
777
778        $this->poly1305Key = $key;
779        $this->usePoly1305 = true;
780    }
781
782    /**
783     * Sets the nonce.
784     *
785     * setNonce() is only required when gcm is used
786     *
787     * @param string $nonce
788     * @throws \BadMethodCallException if an nonce is provided when one shouldn't be
789     */
790    public function setNonce($nonce)
791    {
792        if ($this->mode != self::MODE_GCM) {
793            throw new \BadMethodCallException('Nonces are only used in GCM mode.');
794        }
795
796        $this->nonce = $nonce;
797        $this->setEngine();
798    }
799
800    /**
801     * Sets additional authenticated data
802     *
803     * setAAD() is only used by gcm or in poly1305 mode
804     *
805     * @param string $aad
806     * @throws \BadMethodCallException if mode isn't GCM or if poly1305 isn't being utilized
807     */
808    public function setAAD($aad)
809    {
810        if ($this->mode != self::MODE_GCM && !$this->usePoly1305) {
811            throw new \BadMethodCallException('Additional authenticated data is only utilized in GCM mode or with Poly1305');
812        }
813
814        $this->aad = $aad;
815    }
816
817    /**
818     * Returns whether or not the algorithm uses an IV
819     *
820     * @return bool
821     */
822    public function usesIV()
823    {
824        return $this->mode != self::MODE_GCM && $this->mode != self::MODE_ECB;
825    }
826
827    /**
828     * Returns whether or not the algorithm uses a nonce
829     *
830     * @return bool
831     */
832    public function usesNonce()
833    {
834        return $this->mode == self::MODE_GCM;
835    }
836
837    /**
838     * Returns the current key length in bits
839     *
840     * @return int
841     */
842    public function getKeyLength()
843    {
844        return $this->key_length << 3;
845    }
846
847    /**
848     * Returns the current block length in bits
849     *
850     * @return int
851     */
852    public function getBlockLength()
853    {
854        return $this->block_size << 3;
855    }
856
857    /**
858     * Returns the current block length in bytes
859     *
860     * @return int
861     */
862    public function getBlockLengthInBytes()
863    {
864        return $this->block_size;
865    }
866
867    /**
868     * Sets the key length.
869     *
870     * Keys with explicitly set lengths need to be treated accordingly
871     *
872     * @param int $length
873     */
874    public function setKeyLength($length)
875    {
876        $this->explicit_key_length = $length >> 3;
877
878        if (is_string($this->key) && strlen($this->key) != $this->explicit_key_length) {
879            $this->key = false;
880            throw new InconsistentSetupException('Key has already been set and is not ' . $this->explicit_key_length . ' bytes long');
881        }
882    }
883
884    /**
885     * Sets the key.
886     *
887     * The min/max length(s) of the key depends on the cipher which is used.
888     * If the key not fits the length(s) of the cipher it will paded with null bytes
889     * up to the closest valid key length.  If the key is more than max length,
890     * we trim the excess bits.
891     *
892     * If the key is not explicitly set, it'll be assumed to be all null bytes.
893     *
894     * {@internal Could, but not must, extend by the child Crypt_* class}
895     *
896     * @param string $key
897     */
898    public function setKey($key)
899    {
900        if ($this->explicit_key_length !== false && strlen($key) != $this->explicit_key_length) {
901            throw new InconsistentSetupException('Key length has already been set to ' . $this->explicit_key_length . ' bytes and this key is ' . strlen($key) . ' bytes');
902        }
903
904        $this->key = $key;
905        $this->key_length = strlen($key);
906        $this->setEngine();
907    }
908
909    /**
910     * Sets the password.
911     *
912     * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
913     *     {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
914     *         $hash, $salt, $count, $dkLen
915     *
916     *         Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
917     *     {@link https://en.wikipedia.org/wiki/Bcrypt bcypt}:
918     *         $salt, $rounds, $keylen
919     *
920     *         This is a modified version of bcrypt used by OpenSSH.
921     *
922     * {@internal Could, but not must, extend by the child Crypt_* class}
923     *
924     * @see Crypt/Hash.php
925     * @param string $password
926     * @param string $method
927     * @param int|string ...$func_args
928     * @throws \LengthException if pbkdf1 is being used and the derived key length exceeds the hash length
929     * @throws \RuntimeException if bcrypt is being used and a salt isn't provided
930     * @return bool
931     */
932    public function setPassword($password, $method = 'pbkdf2', ...$func_args)
933    {
934        $key = '';
935
936        $method = strtolower($method);
937        switch ($method) {
938            case 'bcrypt':
939                if (!isset($func_args[2])) {
940                    throw new \RuntimeException('A salt must be provided for bcrypt to work');
941                }
942
943                $salt = $func_args[0];
944
945                $rounds = isset($func_args[1]) ? $func_args[1] : 16;
946                $keylen = isset($func_args[2]) ? $func_args[2] : $this->key_length;
947
948                $key = Blowfish::bcrypt_pbkdf($password, $salt, $keylen + $this->block_size, $rounds);
949
950                $this->setKey(substr($key, 0, $keylen));
951                $this->setIV(substr($key, $keylen));
952
953                return true;
954            case 'pkcs12': // from https://tools.ietf.org/html/rfc7292#appendix-B.2
955            case 'pbkdf1':
956            case 'pbkdf2':
957                // Hash function
958                $hash = isset($func_args[0]) ? strtolower($func_args[0]) : 'sha1';
959                $hashObj = new Hash();
960                $hashObj->setHash($hash);
961
962                // WPA and WPA2 use the SSID as the salt
963                $salt = isset($func_args[1]) ? $func_args[1] : $this->password_default_salt;
964
965                // RFC2898#section-4.2 uses 1,000 iterations by default
966                // WPA and WPA2 use 4,096.
967                $count = isset($func_args[2]) ? $func_args[2] : 1000;
968
969                // Keylength
970                if (isset($func_args[3])) {
971                    if ($func_args[3] <= 0) {
972                        throw new \LengthException('Derived key length cannot be longer 0 or less');
973                    }
974                    $dkLen = $func_args[3];
975                } else {
976                    $key_length = $this->explicit_key_length !== false ? $this->explicit_key_length : $this->key_length;
977                    $dkLen = $method == 'pbkdf1' ? 2 * $key_length : $key_length;
978                }
979
980                switch (true) {
981                    case $method == 'pkcs12':
982                        /*
983                         In this specification, however, all passwords are created from
984                         BMPStrings with a NULL terminator.  This means that each character in
985                         the original BMPString is encoded in 2 bytes in big-endian format
986                         (most-significant byte first).  There are no Unicode byte order
987                         marks.  The 2 bytes produced from the last character in the BMPString
988                         are followed by 2 additional bytes with the value 0x00.
989
990                         -- https://tools.ietf.org/html/rfc7292#appendix-B.1
991                         */
992                        $password = "\0" . chunk_split($password, 1, "\0") . "\0";
993
994                        /*
995                         This standard specifies 3 different values for the ID byte mentioned
996                         above:
997
998                         1.  If ID=1, then the pseudorandom bits being produced are to be used
999                             as key material for performing encryption or decryption.
1000
1001                         2.  If ID=2, then the pseudorandom bits being produced are to be used
1002                             as an IV (Initial Value) for encryption or decryption.
1003
1004                         3.  If ID=3, then the pseudorandom bits being produced are to be used
1005                             as an integrity key for MACing.
1006                         */
1007                        // Construct a string, D (the "diversifier"), by concatenating v/8
1008                        // copies of ID.
1009                        $blockLength = $hashObj->getBlockLengthInBytes();
1010                        $d1 = str_repeat(chr(1), $blockLength);
1011                        $d2 = str_repeat(chr(2), $blockLength);
1012                        $s = '';
1013                        if (strlen($salt)) {
1014                            while (strlen($s) < $blockLength) {
1015                                $s .= $salt;
1016                            }
1017                        }
1018                        $s = substr($s, 0, $blockLength);
1019
1020                        $p = '';
1021                        if (strlen($password)) {
1022                            while (strlen($p) < $blockLength) {
1023                                $p .= $password;
1024                            }
1025                        }
1026                        $p = substr($p, 0, $blockLength);
1027
1028                        $i = $s . $p;
1029
1030                        $this->setKey(self::pkcs12helper($dkLen, $hashObj, $i, $d1, $count));
1031                        if ($this->usesIV()) {
1032                            $this->setIV(self::pkcs12helper($this->block_size, $hashObj, $i, $d2, $count));
1033                        }
1034
1035                        return true;
1036                    case $method == 'pbkdf1':
1037                        if ($dkLen > $hashObj->getLengthInBytes()) {
1038                            throw new \LengthException('Derived key length cannot be longer than the hash length');
1039                        }
1040                        $t = $password . $salt;
1041                        for ($i = 0; $i < $count; ++$i) {
1042                            $t = $hashObj->hash($t);
1043                        }
1044                        $key = substr($t, 0, $dkLen);
1045
1046                        $this->setKey(substr($key, 0, $dkLen >> 1));
1047                        if ($this->usesIV()) {
1048                            $this->setIV(substr($key, $dkLen >> 1));
1049                        }
1050
1051                        return true;
1052                    case !in_array($hash, hash_algos()):
1053                        $i = 1;
1054                        $hashObj->setKey($password);
1055                        while (strlen($key) < $dkLen) {
1056                            $f = $u = $hashObj->hash($salt . pack('N', $i++));
1057                            for ($j = 2; $j <= $count; ++$j) {
1058                                $u = $hashObj->hash($u);
1059                                $f ^= $u;
1060                            }
1061                            $key .= $f;
1062                        }
1063                        $key = substr($key, 0, $dkLen);
1064                        break;
1065                    default:
1066                        $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
1067                }
1068                break;
1069            default:
1070                throw new UnsupportedAlgorithmException($method . ' is not a supported password hashing method');
1071        }
1072
1073        $this->setKey($key);
1074
1075        return true;
1076    }
1077
1078    /**
1079     * PKCS#12 KDF Helper Function
1080     *
1081     * As discussed here:
1082     *
1083     * {@link https://tools.ietf.org/html/rfc7292#appendix-B}
1084     *
1085     * @see self::setPassword()
1086     * @param int $n
1087     * @param Hash $hashObj
1088     * @param string $i
1089     * @param string $d
1090     * @param int $count
1091     * @return string $a
1092     */
1093    private static function pkcs12helper($n, $hashObj, $i, $d, $count)
1094    {
1095        static $one;
1096        if (!isset($one)) {
1097            $one = new BigInteger(1);
1098        }
1099
1100        $blockLength = $hashObj->getBlockLength() >> 3;
1101
1102        $c = ceil($n / $hashObj->getLengthInBytes());
1103        $a = '';
1104        for ($j = 1; $j <= $c; $j++) {
1105            $ai = $d . $i;
1106            for ($k = 0; $k < $count; $k++) {
1107                $ai = $hashObj->hash($ai);
1108            }
1109            $b = '';
1110            while (strlen($b) < $blockLength) {
1111                $b .= $ai;
1112            }
1113            $b = substr($b, 0, $blockLength);
1114            $b = new BigInteger($b, 256);
1115            $newi = '';
1116            for ($k = 0; $k < strlen($i); $k += $blockLength) {
1117                $temp = substr($i, $k, $blockLength);
1118                $temp = new BigInteger($temp, 256);
1119                $temp->setPrecision($blockLength << 3);
1120                $temp = $temp->add($b);
1121                $temp = $temp->add($one);
1122                $newi .= $temp->toBytes(false);
1123            }
1124            $i = $newi;
1125            $a .= $ai;
1126        }
1127
1128        return substr($a, 0, $n);
1129    }
1130
1131    /**
1132     * Encrypts a message.
1133     *
1134     * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher
1135     * implementations may or may not pad in the same manner.  Other common approaches to padding and the reasons why it's
1136     * necessary are discussed in the following
1137     * URL:
1138     *
1139     * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
1140     *
1141     * An alternative to padding is to, separately, send the length of the file.  This is what SSH, in fact, does.
1142     * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that
1143     * length.
1144     *
1145     * {@internal Could, but not must, extend by the child Crypt_* class}
1146     *
1147     * @see self::decrypt()
1148     * @param string $plaintext
1149     * @return string $ciphertext
1150     */
1151    public function encrypt($plaintext)
1152    {
1153        if ($this->paddable) {
1154            $plaintext = $this->pad($plaintext);
1155        }
1156
1157        $this->setup();
1158
1159        if ($this->mode == self::MODE_GCM) {
1160            $oldIV = $this->iv;
1161            Strings::increment_str($this->iv);
1162            $cipher = new static('ctr');
1163            $cipher->setKey($this->key);
1164            $cipher->setIV($this->iv);
1165            $ciphertext = $cipher->encrypt($plaintext);
1166
1167            $s = $this->ghash(
1168                self::nullPad128($this->aad) .
1169                self::nullPad128($ciphertext) .
1170                self::len64($this->aad) .
1171                self::len64($ciphertext)
1172            );
1173            $cipher->encryptIV = $this->iv = $this->encryptIV = $this->decryptIV = $oldIV;
1174            $this->newtag = $cipher->encrypt($s);
1175            return $ciphertext;
1176        }
1177
1178        if (isset($this->poly1305Key)) {
1179            $cipher = clone $this;
1180            unset($cipher->poly1305Key);
1181            $this->usePoly1305 = false;
1182            $ciphertext = $cipher->encrypt($plaintext);
1183            $this->newtag = $this->poly1305($ciphertext);
1184            return $ciphertext;
1185        }
1186
1187        if ($this->engine === self::ENGINE_OPENSSL) {
1188            switch ($this->mode) {
1189                case self::MODE_STREAM:
1190                    return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
1191                case self::MODE_ECB:
1192                    return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
1193                case self::MODE_CBC:
1194                    $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->encryptIV);
1195                    if ($this->continuousBuffer) {
1196                        $this->encryptIV = substr($result, -$this->block_size);
1197                    }
1198                    return $result;
1199                case self::MODE_CTR:
1200                    return $this->openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer);
1201                case self::MODE_CFB:
1202                    // cfb loosely routines inspired by openssl's:
1203                    // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
1204                    $ciphertext = '';
1205                    if ($this->continuousBuffer) {
1206                        $iv = &$this->encryptIV;
1207                        $pos = &$this->enbuffer['pos'];
1208                    } else {
1209                        $iv = $this->encryptIV;
1210                        $pos = 0;
1211                    }
1212                    $len = strlen($plaintext);
1213                    $i = 0;
1214                    if ($pos) {
1215                        $orig_pos = $pos;
1216                        $max = $this->block_size - $pos;
1217                        if ($len >= $max) {
1218                            $i = $max;
1219                            $len -= $max;
1220                            $pos = 0;
1221                        } else {
1222                            $i = $len;
1223                            $pos += $len;
1224                            $len = 0;
1225                        }
1226                        // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1227                        $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
1228                        $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
1229                        $plaintext = substr($plaintext, $i);
1230                    }
1231
1232                    $overflow = $len % $this->block_size;
1233
1234                    if ($overflow) {
1235                        $ciphertext .= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
1236                        $iv = Strings::pop($ciphertext, $this->block_size);
1237
1238                        $size = $len - $overflow;
1239                        $block = $iv ^ substr($plaintext, -$overflow);
1240                        $iv = substr_replace($iv, $block, 0, $overflow);
1241                        $ciphertext .= $block;
1242                        $pos = $overflow;
1243                    } elseif ($len) {
1244                        $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
1245                        $iv = substr($ciphertext, -$this->block_size);
1246                    }
1247
1248                    return $ciphertext;
1249                case self::MODE_CFB8:
1250                    $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->encryptIV);
1251                    if ($this->continuousBuffer) {
1252                        if (($len = strlen($ciphertext)) >= $this->block_size) {
1253                            $this->encryptIV = substr($ciphertext, -$this->block_size);
1254                        } else {
1255                            $this->encryptIV = substr($this->encryptIV, $len - $this->block_size) . substr($ciphertext, -$len);
1256                        }
1257                    }
1258                    return $ciphertext;
1259                case self::MODE_OFB8:
1260                    $ciphertext = '';
1261                    $len = strlen($plaintext);
1262                    $iv = $this->encryptIV;
1263
1264                    for ($i = 0; $i < $len; ++$i) {
1265                        $xor = openssl_encrypt($iv, $this->cipher_name_openssl_ecb, $this->key, $this->openssl_options, $this->decryptIV);
1266                        $ciphertext .= $plaintext[$i] ^ $xor;
1267                        $iv = substr($iv, 1) . $xor[0];
1268                    }
1269
1270                    if ($this->continuousBuffer) {
1271                        $this->encryptIV = $iv;
1272                    }
1273                    break;
1274                case self::MODE_OFB:
1275                    return $this->openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
1276            }
1277        }
1278
1279        if ($this->engine === self::ENGINE_MCRYPT) {
1280            set_error_handler(function () {
1281            });
1282            if ($this->enchanged) {
1283                mcrypt_generic_init($this->enmcrypt, $this->key, $this->getIV($this->encryptIV));
1284                $this->enchanged = false;
1285            }
1286
1287            // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
1288            // using mcrypt's default handing of CFB the above would output two different things.  using phpseclib's
1289            // rewritten CFB implementation the above outputs the same thing twice.
1290            if ($this->mode == self::MODE_CFB && $this->continuousBuffer) {
1291                $block_size = $this->block_size;
1292                $iv = &$this->encryptIV;
1293                $pos = &$this->enbuffer['pos'];
1294                $len = strlen($plaintext);
1295                $ciphertext = '';
1296                $i = 0;
1297                if ($pos) {
1298                    $orig_pos = $pos;
1299                    $max = $block_size - $pos;
1300                    if ($len >= $max) {
1301                        $i = $max;
1302                        $len -= $max;
1303                        $pos = 0;
1304                    } else {
1305                        $i = $len;
1306                        $pos += $len;
1307                        $len = 0;
1308                    }
1309                    $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
1310                    $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
1311                    $this->enbuffer['enmcrypt_init'] = true;
1312                }
1313                if ($len >= $block_size) {
1314                    if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) {
1315                        if ($this->enbuffer['enmcrypt_init'] === true) {
1316                            mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
1317                            $this->enbuffer['enmcrypt_init'] = false;
1318                        }
1319                        $ciphertext .= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
1320                        $iv = substr($ciphertext, -$block_size);
1321                        $len %= $block_size;
1322                    } else {
1323                        while ($len >= $block_size) {
1324                            $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
1325                            $ciphertext .= $iv;
1326                            $len -= $block_size;
1327                            $i += $block_size;
1328                        }
1329                    }
1330                }
1331
1332                if ($len) {
1333                    $iv = mcrypt_generic($this->ecb, $iv);
1334                    $block = $iv ^ substr($plaintext, -$len);
1335                    $iv = substr_replace($iv, $block, 0, $len);
1336                    $ciphertext .= $block;
1337                    $pos = $len;
1338                }
1339
1340                restore_error_handler();
1341
1342                return $ciphertext;
1343            }
1344
1345            $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
1346
1347            if (!$this->continuousBuffer) {
1348                mcrypt_generic_init($this->enmcrypt, $this->key, $this->getIV($this->encryptIV));
1349            }
1350
1351            restore_error_handler();
1352
1353            return $ciphertext;
1354        }
1355
1356        if ($this->engine === self::ENGINE_EVAL) {
1357            $inline = $this->inline_crypt;
1358            return $inline('encrypt', $plaintext);
1359        }
1360
1361        $buffer = &$this->enbuffer;
1362        $block_size = $this->block_size;
1363        $ciphertext = '';
1364        switch ($this->mode) {
1365            case self::MODE_ECB:
1366                for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
1367                    $ciphertext .= $this->encryptBlock(substr($plaintext, $i, $block_size));
1368                }
1369                break;
1370            case self::MODE_CBC:
1371                $xor = $this->encryptIV;
1372                for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
1373                    $block = substr($plaintext, $i, $block_size);
1374                    $block = $this->encryptBlock($block ^ $xor);
1375                    $xor = $block;
1376                    $ciphertext .= $block;
1377                }
1378                if ($this->continuousBuffer) {
1379                    $this->encryptIV = $xor;
1380                }
1381                break;
1382            case self::MODE_CTR:
1383                $xor = $this->encryptIV;
1384                if (strlen($buffer['ciphertext'])) {
1385                    for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
1386                        $block = substr($plaintext, $i, $block_size);
1387                        if (strlen($block) > strlen($buffer['ciphertext'])) {
1388                            $buffer['ciphertext'] .= $this->encryptBlock($xor);
1389                            Strings::increment_str($xor);
1390                        }
1391                        $key = Strings::shift($buffer['ciphertext'], $block_size);
1392                        $ciphertext .= $block ^ $key;
1393                    }
1394                } else {
1395                    for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
1396                        $block = substr($plaintext, $i, $block_size);
1397                        $key = $this->encryptBlock($xor);
1398                        Strings::increment_str($xor);
1399                        $ciphertext .= $block ^ $key;
1400                    }
1401                }
1402                if ($this->continuousBuffer) {
1403                    $this->encryptIV = $xor;
1404                    if ($start = strlen($plaintext) % $block_size) {
1405                        $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1406                    }
1407                }
1408                break;
1409            case self::MODE_CFB:
1410                // cfb loosely routines inspired by openssl's:
1411                // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
1412                if ($this->continuousBuffer) {
1413                    $iv = &$this->encryptIV;
1414                    $pos = &$buffer['pos'];
1415                } else {
1416                    $iv = $this->encryptIV;
1417                    $pos = 0;
1418                }
1419                $len = strlen($plaintext);
1420                $i = 0;
1421                if ($pos) {
1422                    $orig_pos = $pos;
1423                    $max = $block_size - $pos;
1424                    if ($len >= $max) {
1425                        $i = $max;
1426                        $len -= $max;
1427                        $pos = 0;
1428                    } else {
1429                        $i = $len;
1430                        $pos += $len;
1431                        $len = 0;
1432                    }
1433                    // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1434                    $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
1435                    $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
1436                }
1437                while ($len >= $block_size) {
1438                    $iv = $this->encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
1439                    $ciphertext .= $iv;
1440                    $len -= $block_size;
1441                    $i += $block_size;
1442                }
1443                if ($len) {
1444                    $iv = $this->encryptBlock($iv);
1445                    $block = $iv ^ substr($plaintext, $i);
1446                    $iv = substr_replace($iv, $block, 0, $len);
1447                    $ciphertext .= $block;
1448                    $pos = $len;
1449                }
1450                break;
1451            case self::MODE_CFB8:
1452                $ciphertext = '';
1453                $len = strlen($plaintext);
1454                $iv = $this->encryptIV;
1455
1456                for ($i = 0; $i < $len; ++$i) {
1457                    $ciphertext .= ($c = $plaintext[$i] ^ $this->encryptBlock($iv));
1458                    $iv = substr($iv, 1) . $c;
1459                }
1460
1461                if ($this->continuousBuffer) {
1462                    if ($len >= $block_size) {
1463                        $this->encryptIV = substr($ciphertext, -$block_size);
1464                    } else {
1465                        $this->encryptIV = substr($this->encryptIV, $len - $block_size) . substr($ciphertext, -$len);
1466                    }
1467                }
1468                break;
1469            case self::MODE_OFB8:
1470                $ciphertext = '';
1471                $len = strlen($plaintext);
1472                $iv = $this->encryptIV;
1473
1474                for ($i = 0; $i < $len; ++$i) {
1475                    $xor = $this->encryptBlock($iv);
1476                    $ciphertext .= $plaintext[$i] ^ $xor;
1477                    $iv = substr($iv, 1) . $xor[0];
1478                }
1479
1480                if ($this->continuousBuffer) {
1481                    $this->encryptIV = $iv;
1482                }
1483                break;
1484            case self::MODE_OFB:
1485                $xor = $this->encryptIV;
1486                if (strlen($buffer['xor'])) {
1487                    for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
1488                        $block = substr($plaintext, $i, $block_size);
1489                        if (strlen($block) > strlen($buffer['xor'])) {
1490                            $xor = $this->encryptBlock($xor);
1491                            $buffer['xor'] .= $xor;
1492                        }
1493                        $key = Strings::shift($buffer['xor'], $block_size);
1494                        $ciphertext .= $block ^ $key;
1495                    }
1496                } else {
1497                    for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
1498                        $xor = $this->encryptBlock($xor);
1499                        $ciphertext .= substr($plaintext, $i, $block_size) ^ $xor;
1500                    }
1501                    $key = $xor;
1502                }
1503                if ($this->continuousBuffer) {
1504                    $this->encryptIV = $xor;
1505                    if ($start = strlen($plaintext) % $block_size) {
1506                        $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1507                    }
1508                }
1509                break;
1510            case self::MODE_STREAM:
1511                $ciphertext = $this->encryptBlock($plaintext);
1512                break;
1513        }
1514
1515        return $ciphertext;
1516    }
1517
1518    /**
1519     * Decrypts a message.
1520     *
1521     * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
1522     * it is.
1523     *
1524     * {@internal Could, but not must, extend by the child Crypt_* class}
1525     *
1526     * @see self::encrypt()
1527     * @param string $ciphertext
1528     * @return string $plaintext
1529     * @throws \LengthException if we're inside a block cipher and the ciphertext length is not a multiple of the block size
1530     */
1531    public function decrypt($ciphertext)
1532    {
1533        if ($this->paddable && strlen($ciphertext) % $this->block_size) {
1534            throw new \LengthException('The ciphertext length (' . strlen($ciphertext) . ') needs to be a multiple of the block size (' . $this->block_size . ')');
1535        }
1536        $this->setup();
1537
1538        if ($this->mode == self::MODE_GCM || isset($this->poly1305Key)) {
1539            if ($this->oldtag === false) {
1540                throw new InsufficientSetupException('Authentication Tag has not been set');
1541            }
1542
1543            if (isset($this->poly1305Key)) {
1544                $newtag = $this->poly1305($ciphertext);
1545            } else {
1546                $oldIV = $this->iv;
1547                Strings::increment_str($this->iv);
1548                $cipher = new static('ctr');
1549                $cipher->setKey($this->key);
1550                $cipher->setIV($this->iv);
1551                $plaintext = $cipher->decrypt($ciphertext);
1552
1553                $s = $this->ghash(
1554                    self::nullPad128($this->aad) .
1555                    self::nullPad128($ciphertext) .
1556                    self::len64($this->aad) .
1557                    self::len64($ciphertext)
1558                );
1559                $cipher->encryptIV = $this->iv = $this->encryptIV = $this->decryptIV = $oldIV;
1560                $newtag = $cipher->encrypt($s);
1561            }
1562            if ($this->oldtag != substr($newtag, 0, strlen($newtag))) {
1563                $cipher = clone $this;
1564                unset($cipher->poly1305Key);
1565                $this->usePoly1305 = false;
1566                $plaintext = $cipher->decrypt($ciphertext);
1567                $this->oldtag = false;
1568                throw new BadDecryptionException('Derived authentication tag and supplied authentication tag do not match');
1569            }
1570            $this->oldtag = false;
1571            return $plaintext;
1572        }
1573
1574        if ($this->engine === self::ENGINE_OPENSSL) {
1575            switch ($this->mode) {
1576                case self::MODE_STREAM:
1577                    $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
1578                    break;
1579                case self::MODE_ECB:
1580                    $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
1581                    break;
1582                case self::MODE_CBC:
1583                    $offset = $this->block_size;
1584                    $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->decryptIV);
1585                    if ($this->continuousBuffer) {
1586                        $this->decryptIV = substr($ciphertext, -$offset, $this->block_size);
1587                    }
1588                    break;
1589                case self::MODE_CTR:
1590                    $plaintext = $this->openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer);
1591                    break;
1592                case self::MODE_CFB:
1593                    // cfb loosely routines inspired by openssl's:
1594                    // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
1595                    $plaintext = '';
1596                    if ($this->continuousBuffer) {
1597                        $iv = &$this->decryptIV;
1598                        $pos = &$this->debuffer['pos'];
1599                    } else {
1600                        $iv = $this->decryptIV;
1601                        $pos = 0;
1602                    }
1603                    $len = strlen($ciphertext);
1604                    $i = 0;
1605                    if ($pos) {
1606                        $orig_pos = $pos;
1607                        $max = $this->block_size - $pos;
1608                        if ($len >= $max) {
1609                            $i = $max;
1610                            $len -= $max;
1611                            $pos = 0;
1612                        } else {
1613                            $i = $len;
1614                            $pos += $len;
1615                            $len = 0;
1616                        }
1617                        // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $this->blocksize
1618                        $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1619                        $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1620                        $ciphertext = substr($ciphertext, $i);
1621                    }
1622                    $overflow = $len % $this->block_size;
1623                    if ($overflow) {
1624                        $plaintext .= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
1625                        if ($len - $overflow) {
1626                            $iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow);
1627                        }
1628                        $iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
1629                        $plaintext .= $iv ^ substr($ciphertext, -$overflow);
1630                        $iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow);
1631                        $pos = $overflow;
1632                    } elseif ($len) {
1633                        $plaintext .= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
1634                        $iv = substr($ciphertext, -$this->block_size);
1635                    }
1636                    break;
1637                case self::MODE_CFB8:
1638                    $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->decryptIV);
1639                    if ($this->continuousBuffer) {
1640                        if (($len = strlen($ciphertext)) >= $this->block_size) {
1641                            $this->decryptIV = substr($ciphertext, -$this->block_size);
1642                        } else {
1643                            $this->decryptIV = substr($this->decryptIV, $len - $this->block_size) . substr($ciphertext, -$len);
1644                        }
1645                    }
1646                    break;
1647                case self::MODE_OFB8:
1648                    $plaintext = '';
1649                    $len = strlen($ciphertext);
1650                    $iv = $this->decryptIV;
1651
1652                    for ($i = 0; $i < $len; ++$i) {
1653                        $xor = openssl_encrypt($iv, $this->cipher_name_openssl_ecb, $this->key, $this->openssl_options, $this->decryptIV);
1654                        $plaintext .= $ciphertext[$i] ^ $xor;
1655                        $iv = substr($iv, 1) . $xor[0];
1656                    }
1657
1658                    if ($this->continuousBuffer) {
1659                        $this->decryptIV = $iv;
1660                    }
1661                    break;
1662                case self::MODE_OFB:
1663                    $plaintext = $this->openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
1664            }
1665
1666            return $this->paddable ? $this->unpad($plaintext) : $plaintext;
1667        }
1668
1669        if ($this->engine === self::ENGINE_MCRYPT) {
1670            set_error_handler(function () {
1671            });
1672            $block_size = $this->block_size;
1673            if ($this->dechanged) {
1674                mcrypt_generic_init($this->demcrypt, $this->key, $this->getIV($this->decryptIV));
1675                $this->dechanged = false;
1676            }
1677
1678            if ($this->mode == self::MODE_CFB && $this->continuousBuffer) {
1679                $iv = &$this->decryptIV;
1680                $pos = &$this->debuffer['pos'];
1681                $len = strlen($ciphertext);
1682                $plaintext = '';
1683                $i = 0;
1684                if ($pos) {
1685                    $orig_pos = $pos;
1686                    $max = $block_size - $pos;
1687                    if ($len >= $max) {
1688                        $i = $max;
1689                        $len -= $max;
1690                        $pos = 0;
1691                    } else {
1692                        $i = $len;
1693                        $pos += $len;
1694                        $len = 0;
1695                    }
1696                    // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1697                    $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1698                    $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1699                }
1700                if ($len >= $block_size) {
1701                    $cb = substr($ciphertext, $i, $len - $len % $block_size);
1702                    $plaintext .= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
1703                    $iv = substr($cb, -$block_size);
1704                    $len %= $block_size;
1705                }
1706                if ($len) {
1707                    $iv = mcrypt_generic($this->ecb, $iv);
1708                    $plaintext .= $iv ^ substr($ciphertext, -$len);
1709                    $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
1710                    $pos = $len;
1711                }
1712
1713                restore_error_handler();
1714
1715                return $plaintext;
1716            }
1717
1718            $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
1719
1720            if (!$this->continuousBuffer) {
1721                mcrypt_generic_init($this->demcrypt, $this->key, $this->getIV($this->decryptIV));
1722            }
1723
1724            restore_error_handler();
1725
1726            return $this->paddable ? $this->unpad($plaintext) : $plaintext;
1727        }
1728
1729        if ($this->engine === self::ENGINE_EVAL) {
1730            $inline = $this->inline_crypt;
1731            return $inline('decrypt', $ciphertext);
1732        }
1733
1734        $block_size = $this->block_size;
1735
1736        $buffer = &$this->debuffer;
1737        $plaintext = '';
1738        switch ($this->mode) {
1739            case self::MODE_ECB:
1740                for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
1741                    $plaintext .= $this->decryptBlock(substr($ciphertext, $i, $block_size));
1742                }
1743                break;
1744            case self::MODE_CBC:
1745                $xor = $this->decryptIV;
1746                for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
1747                    $block = substr($ciphertext, $i, $block_size);
1748                    $plaintext .= $this->decryptBlock($block) ^ $xor;
1749                    $xor = $block;
1750                }
1751                if ($this->continuousBuffer) {
1752                    $this->decryptIV = $xor;
1753                }
1754                break;
1755            case self::MODE_CTR:
1756                $xor = $this->decryptIV;
1757                if (strlen($buffer['ciphertext'])) {
1758                    for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
1759                        $block = substr($ciphertext, $i, $block_size);
1760                        if (strlen($block) > strlen($buffer['ciphertext'])) {
1761                            $buffer['ciphertext'] .= $this->encryptBlock($xor);
1762                            Strings::increment_str($xor);
1763                        }
1764                        $key = Strings::shift($buffer['ciphertext'], $block_size);
1765                        $plaintext .= $block ^ $key;
1766                    }
1767                } else {
1768                    for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
1769                        $block = substr($ciphertext, $i, $block_size);
1770                        $key = $this->encryptBlock($xor);
1771                        Strings::increment_str($xor);
1772                        $plaintext .= $block ^ $key;
1773                    }
1774                }
1775                if ($this->continuousBuffer) {
1776                    $this->decryptIV = $xor;
1777                    if ($start = strlen($ciphertext) % $block_size) {
1778                        $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1779                    }
1780                }
1781                break;
1782            case self::MODE_CFB:
1783                if ($this->continuousBuffer) {
1784                    $iv = &$this->decryptIV;
1785                    $pos = &$buffer['pos'];
1786                } else {
1787                    $iv = $this->decryptIV;
1788                    $pos = 0;
1789                }
1790                $len = strlen($ciphertext);
1791                $i = 0;
1792                if ($pos) {
1793                    $orig_pos = $pos;
1794                    $max = $block_size - $pos;
1795                    if ($len >= $max) {
1796                        $i = $max;
1797                        $len -= $max;
1798                        $pos = 0;
1799                    } else {
1800                        $i = $len;
1801                        $pos += $len;
1802                        $len = 0;
1803                    }
1804                    // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1805                    $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1806                    $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1807                }
1808                while ($len >= $block_size) {
1809                    $iv = $this->encryptBlock($iv);
1810                    $cb = substr($ciphertext, $i, $block_size);
1811                    $plaintext .= $iv ^ $cb;
1812                    $iv = $cb;
1813                    $len -= $block_size;
1814                    $i += $block_size;
1815                }
1816                if ($len) {
1817                    $iv = $this->encryptBlock($iv);
1818                    $plaintext .= $iv ^ substr($ciphertext, $i);
1819                    $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
1820                    $pos = $len;
1821                }
1822                break;
1823            case self::MODE_CFB8:
1824                $plaintext = '';
1825                $len = strlen($ciphertext);
1826                $iv = $this->decryptIV;
1827
1828                for ($i = 0; $i < $len; ++$i) {
1829                    $plaintext .= $ciphertext[$i] ^ $this->encryptBlock($iv);
1830                    $iv = substr($iv, 1) . $ciphertext[$i];
1831                }
1832
1833                if ($this->continuousBuffer) {
1834                    if ($len >= $block_size) {
1835                        $this->decryptIV = substr($ciphertext, -$block_size);
1836                    } else {
1837                        $this->decryptIV = substr($this->decryptIV, $len - $block_size) . substr($ciphertext, -$len);
1838                    }
1839                }
1840                break;
1841            case self::MODE_OFB8:
1842                $plaintext = '';
1843                $len = strlen($ciphertext);
1844                $iv = $this->decryptIV;
1845
1846                for ($i = 0; $i < $len; ++$i) {
1847                    $xor = $this->encryptBlock($iv);
1848                    $plaintext .= $ciphertext[$i] ^ $xor;
1849                    $iv = substr($iv, 1) . $xor[0];
1850                }
1851
1852                if ($this->continuousBuffer) {
1853                    $this->decryptIV = $iv;
1854                }
1855                break;
1856            case self::MODE_OFB:
1857                $xor = $this->decryptIV;
1858                if (strlen($buffer['xor'])) {
1859                    for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
1860                        $block = substr($ciphertext, $i, $block_size);
1861                        if (strlen($block) > strlen($buffer['xor'])) {
1862                            $xor = $this->encryptBlock($xor);
1863                            $buffer['xor'] .= $xor;
1864                        }
1865                        $key = Strings::shift($buffer['xor'], $block_size);
1866                        $plaintext .= $block ^ $key;
1867                    }
1868                } else {
1869                    for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
1870                        $xor = $this->encryptBlock($xor);
1871                        $plaintext .= substr($ciphertext, $i, $block_size) ^ $xor;
1872                    }
1873                    $key = $xor;
1874                }
1875                if ($this->continuousBuffer) {
1876                    $this->decryptIV = $xor;
1877                    if ($start = strlen($ciphertext) % $block_size) {
1878                        $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1879                    }
1880                }
1881                break;
1882            case self::MODE_STREAM:
1883                $plaintext = $this->decryptBlock($ciphertext);
1884                break;
1885        }
1886        return $this->paddable ? $this->unpad($plaintext) : $plaintext;
1887    }
1888
1889    /**
1890     * Get the authentication tag
1891     *
1892     * Only used in GCM or Poly1305 mode
1893     *
1894     * @see self::encrypt()
1895     * @param int $length optional
1896     * @return string
1897     * @throws \LengthException if $length isn't of a sufficient length
1898     * @throws \RuntimeException if GCM mode isn't being used
1899     */
1900    public function getTag($length = 16)
1901    {
1902        if ($this->mode != self::MODE_GCM && !$this->usePoly1305) {
1903            throw new \BadMethodCallException('Authentication tags are only utilized in GCM mode or with Poly1305');
1904        }
1905
1906        if ($this->newtag === false) {
1907            throw new \BadMethodCallException('A tag can only be returned after a round of encryption has been performed');
1908        }
1909
1910        // the tag is 128-bits. it can't be greater than 16 bytes because that's bigger than the tag is. if it
1911        // were 0 you might as well be doing CTR and less than 4 provides minimal security that could be trivially
1912        // easily brute forced.
1913        // see https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf#page=36
1914        // for more info
1915        if ($length < 4 || $length > 16) {
1916            throw new \LengthException('The authentication tag must be between 4 and 16 bytes long');
1917        }
1918
1919        return $length == 16 ?
1920            $this->newtag :
1921            substr($this->newtag, 0, $length);
1922    }
1923
1924    /**
1925     * Sets the authentication tag
1926     *
1927     * Only used in GCM mode
1928     *
1929     * @see self::decrypt()
1930     * @param string $tag
1931     * @throws \LengthException if $length isn't of a sufficient length
1932     * @throws \RuntimeException if GCM mode isn't being used
1933     */
1934    public function setTag($tag)
1935    {
1936        if ($this->usePoly1305 && !isset($this->poly1305Key) && method_exists($this, 'createPoly1305Key')) {
1937            $this->createPoly1305Key();
1938        }
1939
1940        if ($this->mode != self::MODE_GCM && !$this->usePoly1305) {
1941            throw new \BadMethodCallException('Authentication tags are only utilized in GCM mode or with Poly1305');
1942        }
1943
1944        $length = strlen($tag);
1945        if ($length < 4 || $length > 16) {
1946            throw new \LengthException('The authentication tag must be between 4 and 16 bytes long');
1947        }
1948        $this->oldtag = $tag;
1949    }
1950
1951    /**
1952     * Get the IV
1953     *
1954     * mcrypt requires an IV even if ECB is used
1955     *
1956     * @see self::encrypt()
1957     * @see self::decrypt()
1958     * @param string $iv
1959     * @return string
1960     */
1961    protected function getIV($iv)
1962    {
1963        return $this->mode == self::MODE_ECB ? str_repeat("\0", $this->block_size) : $iv;
1964    }
1965
1966    /**
1967     * OpenSSL CTR Processor
1968     *
1969     * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1970     * for CTR is the same for both encrypting and decrypting this function is re-used by both SymmetricKey::encrypt()
1971     * and SymmetricKey::decrypt(). Also, OpenSSL doesn't implement CTR for all of it's symmetric ciphers so this
1972     * function will emulate CTR with ECB when necessary.
1973     *
1974     * @see self::encrypt()
1975     * @see self::decrypt()
1976     * @param string $plaintext
1977     * @param string $encryptIV
1978     * @param array $buffer
1979     * @return string
1980     */
1981    private function openssl_ctr_process($plaintext, &$encryptIV, &$buffer)
1982    {
1983        $ciphertext = '';
1984
1985        $block_size = $this->block_size;
1986        $key = $this->key;
1987
1988        if ($this->openssl_emulate_ctr) {
1989            $xor = $encryptIV;
1990            if (strlen($buffer['ciphertext'])) {
1991                for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
1992                    $block = substr($plaintext, $i, $block_size);
1993                    if (strlen($block) > strlen($buffer['ciphertext'])) {
1994                        $buffer['ciphertext'] .= openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
1995                    }
1996                    Strings::increment_str($xor);
1997                    $otp = Strings::shift($buffer['ciphertext'], $block_size);
1998                    $ciphertext .= $block ^ $otp;
1999                }
2000            } else {
2001                for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
2002                    $block = substr($plaintext, $i, $block_size);
2003                    $otp = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
2004                    Strings::increment_str($xor);
2005                    $ciphertext .= $block ^ $otp;
2006                }
2007            }
2008            if ($this->continuousBuffer) {
2009                $encryptIV = $xor;
2010                if ($start = strlen($plaintext) % $block_size) {
2011                    $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
2012                }
2013            }
2014
2015            return $ciphertext;
2016        }
2017
2018        if (strlen($buffer['ciphertext'])) {
2019            $ciphertext = $plaintext ^ Strings::shift($buffer['ciphertext'], strlen($plaintext));
2020            $plaintext = substr($plaintext, strlen($ciphertext));
2021
2022            if (!strlen($plaintext)) {
2023                return $ciphertext;
2024            }
2025        }
2026
2027        $overflow = strlen($plaintext) % $block_size;
2028        if ($overflow) {
2029            $plaintext2 = Strings::pop($plaintext, $overflow); // ie. trim $plaintext to a multiple of $block_size and put rest of $plaintext in $plaintext2
2030            $encrypted = openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV);
2031            $temp = Strings::pop($encrypted, $block_size);
2032            $ciphertext .= $encrypted . ($plaintext2 ^ $temp);
2033            if ($this->continuousBuffer) {
2034                $buffer['ciphertext'] = substr($temp, $overflow);
2035                $encryptIV = $temp;
2036            }
2037        } elseif (!strlen($buffer['ciphertext'])) {
2038            $ciphertext .= openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV);
2039            $temp = Strings::pop($ciphertext, $block_size);
2040            if ($this->continuousBuffer) {
2041                $encryptIV = $temp;
2042            }
2043        }
2044        if ($this->continuousBuffer) {
2045            $encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
2046            if ($overflow) {
2047                Strings::increment_str($encryptIV);
2048            }
2049        }
2050
2051        return $ciphertext;
2052    }
2053
2054    /**
2055     * OpenSSL OFB Processor
2056     *
2057     * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
2058     * for OFB is the same for both encrypting and decrypting this function is re-used by both SymmetricKey::encrypt()
2059     * and SymmetricKey::decrypt().
2060     *
2061     * @see self::encrypt()
2062     * @see self::decrypt()
2063     * @param string $plaintext
2064     * @param string $encryptIV
2065     * @param array $buffer
2066     * @return string
2067     */
2068    private function openssl_ofb_process($plaintext, &$encryptIV, &$buffer)
2069    {
2070        if (strlen($buffer['xor'])) {
2071            $ciphertext = $plaintext ^ $buffer['xor'];
2072            $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
2073            $plaintext = substr($plaintext, strlen($ciphertext));
2074        } else {
2075            $ciphertext = '';
2076        }
2077
2078        $block_size = $this->block_size;
2079
2080        $len = strlen($plaintext);
2081        $key = $this->key;
2082        $overflow = $len % $block_size;
2083
2084        if (strlen($plaintext)) {
2085            if ($overflow) {
2086                $ciphertext .= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV);
2087                $xor = Strings::pop($ciphertext, $block_size);
2088                if ($this->continuousBuffer) {
2089                    $encryptIV = $xor;
2090                }
2091                $ciphertext .= Strings::shift($xor, $overflow) ^ substr($plaintext, -$overflow);
2092                if ($this->continuousBuffer) {
2093                    $buffer['xor'] = $xor;
2094                }
2095            } else {
2096                $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV);
2097                if ($this->continuousBuffer) {
2098                    $encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size);
2099                }
2100            }
2101        }
2102
2103        return $ciphertext;
2104    }
2105
2106    /**
2107     * phpseclib <-> OpenSSL Mode Mapper
2108     *
2109     * May need to be overwritten by classes extending this one in some cases
2110     *
2111     * @return string
2112     */
2113    protected function openssl_translate_mode()
2114    {
2115        switch ($this->mode) {
2116            case self::MODE_ECB:
2117                return 'ecb';
2118            case self::MODE_CBC:
2119                return 'cbc';
2120            case self::MODE_CTR:
2121            case self::MODE_GCM:
2122                return 'ctr';
2123            case self::MODE_CFB:
2124                return 'cfb';
2125            case self::MODE_CFB8:
2126                return 'cfb8';
2127            case self::MODE_OFB:
2128                return 'ofb';
2129        }
2130    }
2131
2132    /**
2133     * Pad "packets".
2134     *
2135     * Block ciphers working by encrypting between their specified [$this->]block_size at a time
2136     * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
2137     * pad the input so that it is of the proper length.
2138     *
2139     * Padding is enabled by default.  Sometimes, however, it is undesirable to pad strings.  Such is the case in SSH,
2140     * where "packets" are padded with random bytes before being encrypted.  Unpad these packets and you risk stripping
2141     * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
2142     * transmitted separately)
2143     *
2144     * @see self::disablePadding()
2145     */
2146    public function enablePadding()
2147    {
2148        $this->padding = true;
2149    }
2150
2151    /**
2152     * Do not pad packets.
2153     *
2154     * @see self::enablePadding()
2155     */
2156    public function disablePadding()
2157    {
2158        $this->padding = false;
2159    }
2160
2161    /**
2162     * Treat consecutive "packets" as if they are a continuous buffer.
2163     *
2164     * Say you have a 32-byte plaintext $plaintext.  Using the default behavior, the two following code snippets
2165     * will yield different outputs:
2166     *
2167     * <code>
2168     *    echo $rijndael->encrypt(substr($plaintext,  0, 16));
2169     *    echo $rijndael->encrypt(substr($plaintext, 16, 16));
2170     * </code>
2171     * <code>
2172     *    echo $rijndael->encrypt($plaintext);
2173     * </code>
2174     *
2175     * The solution is to enable the continuous buffer.  Although this will resolve the above discrepancy, it creates
2176     * another, as demonstrated with the following:
2177     *
2178     * <code>
2179     *    $rijndael->encrypt(substr($plaintext, 0, 16));
2180     *    echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
2181     * </code>
2182     * <code>
2183     *    echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
2184     * </code>
2185     *
2186     * With the continuous buffer disabled, these would yield the same output.  With it enabled, they yield different
2187     * outputs.  The reason is due to the fact that the initialization vector's change after every encryption /
2188     * decryption round when the continuous buffer is enabled.  When it's disabled, they remain constant.
2189     *
2190     * Put another way, when the continuous buffer is enabled, the state of the \phpseclib3\Crypt\*() object changes after each
2191     * encryption / decryption round, whereas otherwise, it'd remain constant.  For this reason, it's recommended that
2192     * continuous buffers not be used.  They do offer better security and are, in fact, sometimes required (SSH uses them),
2193     * however, they are also less intuitive and more likely to cause you problems.
2194     *
2195     * {@internal Could, but not must, extend by the child Crypt_* class}
2196     *
2197     * @see self::disableContinuousBuffer()
2198     */
2199    public function enableContinuousBuffer()
2200    {
2201        if ($this->mode == self::MODE_ECB) {
2202            return;
2203        }
2204
2205        if ($this->mode == self::MODE_GCM) {
2206            throw new \BadMethodCallException('This mode does not run in continuous mode');
2207        }
2208
2209        $this->continuousBuffer = true;
2210
2211        $this->setEngine();
2212    }
2213
2214    /**
2215     * Treat consecutive packets as if they are a discontinuous buffer.
2216     *
2217     * The default behavior.
2218     *
2219     * {@internal Could, but not must, extend by the child Crypt_* class}
2220     *
2221     * @see self::enableContinuousBuffer()
2222     */
2223    public function disableContinuousBuffer()
2224    {
2225        if ($this->mode == self::MODE_ECB) {
2226            return;
2227        }
2228        if (!$this->continuousBuffer) {
2229            return;
2230        }
2231
2232        $this->continuousBuffer = false;
2233
2234        $this->setEngine();
2235    }
2236
2237    /**
2238     * Test for engine validity
2239     *
2240     * @see self::__construct()
2241     * @param int $engine
2242     * @return bool
2243     */
2244    protected function isValidEngineHelper($engine)
2245    {
2246        switch ($engine) {
2247            case self::ENGINE_OPENSSL:
2248                $this->openssl_emulate_ctr = false;
2249                $result = $this->cipher_name_openssl &&
2250                          extension_loaded('openssl');
2251                if (!$result) {
2252                    return false;
2253                }
2254
2255                $methods = openssl_get_cipher_methods();
2256                if (in_array($this->cipher_name_openssl, $methods)) {
2257                    return true;
2258                }
2259                // not all of openssl's symmetric cipher's support ctr. for those
2260                // that don't we'll emulate it
2261                switch ($this->mode) {
2262                    case self::MODE_CTR:
2263                        if (in_array($this->cipher_name_openssl_ecb, $methods)) {
2264                            $this->openssl_emulate_ctr = true;
2265                            return true;
2266                        }
2267                }
2268                return false;
2269            case self::ENGINE_MCRYPT:
2270                set_error_handler(function () {
2271                });
2272                $result = $this->cipher_name_mcrypt &&
2273                          extension_loaded('mcrypt') &&
2274                          in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms());
2275                restore_error_handler();
2276                return $result;
2277            case self::ENGINE_EVAL:
2278                return method_exists($this, 'setupInlineCrypt');
2279            case self::ENGINE_INTERNAL:
2280                return true;
2281        }
2282
2283        return false;
2284    }
2285
2286    /**
2287     * Test for engine validity
2288     *
2289     * @see self::__construct()
2290     * @param string $engine
2291     * @return bool
2292     */
2293    public function isValidEngine($engine)
2294    {
2295        static $reverseMap;
2296        if (!isset($reverseMap)) {
2297            $reverseMap = array_map('strtolower', self::ENGINE_MAP);
2298            $reverseMap = array_flip($reverseMap);
2299        }
2300        $engine = strtolower($engine);
2301        if (!isset($reverseMap[$engine])) {
2302            return false;
2303        }
2304
2305        return $this->isValidEngineHelper($reverseMap[$engine]);
2306    }
2307
2308    /**
2309     * Sets the preferred crypt engine
2310     *
2311     * Currently, $engine could be:
2312     *
2313     * - libsodium[very fast]
2314     *
2315     * - OpenSSL  [very fast]
2316     *
2317     * - mcrypt   [fast]
2318     *
2319     * - Eval     [slow]
2320     *
2321     * - PHP      [slowest]
2322     *
2323     * If the preferred crypt engine is not available the fastest available one will be used
2324     *
2325     * @see self::__construct()
2326     * @param string $engine
2327     */
2328    public function setPreferredEngine($engine)
2329    {
2330        static $reverseMap;
2331        if (!isset($reverseMap)) {
2332            $reverseMap = array_map('strtolower', self::ENGINE_MAP);
2333            $reverseMap = array_flip($reverseMap);
2334        }
2335        $engine = is_string($engine) ? strtolower($engine) : '';
2336        $this->preferredEngine = isset($reverseMap[$engine]) ? $reverseMap[$engine] : self::ENGINE_LIBSODIUM;
2337
2338        $this->setEngine();
2339    }
2340
2341    /**
2342     * Returns the engine currently being utilized
2343     *
2344     * @see self::setEngine()
2345     */
2346    public function getEngine()
2347    {
2348        return self::ENGINE_MAP[$this->engine];
2349    }
2350
2351    /**
2352     * Sets the engine as appropriate
2353     *
2354     * @see self::__construct()
2355     */
2356    protected function setEngine()
2357    {
2358        $this->engine = null;
2359
2360        $candidateEngines = [
2361            self::ENGINE_LIBSODIUM,
2362            self::ENGINE_OPENSSL_GCM,
2363            self::ENGINE_OPENSSL,
2364            self::ENGINE_MCRYPT,
2365            self::ENGINE_EVAL
2366        ];
2367        if (isset($this->preferredEngine)) {
2368            $temp = [$this->preferredEngine];
2369            $candidateEngines = array_merge(
2370                $temp,
2371                array_diff($candidateEngines, $temp)
2372            );
2373        }
2374        foreach ($candidateEngines as $engine) {
2375            if ($this->isValidEngineHelper($engine)) {
2376                $this->engine = $engine;
2377                break;
2378            }
2379        }
2380        if (!$this->engine) {
2381            $this->engine = self::ENGINE_INTERNAL;
2382        }
2383
2384        if ($this->engine != self::ENGINE_MCRYPT && $this->enmcrypt) {
2385            set_error_handler(function () {
2386            });
2387            // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed,
2388            // (re)open them with the module named in $this->cipher_name_mcrypt
2389            mcrypt_module_close($this->enmcrypt);
2390            mcrypt_module_close($this->demcrypt);
2391            $this->enmcrypt = null;
2392            $this->demcrypt = null;
2393
2394            if ($this->ecb) {
2395                mcrypt_module_close($this->ecb);
2396                $this->ecb = null;
2397            }
2398            restore_error_handler();
2399        }
2400
2401        $this->changed = $this->nonIVChanged = true;
2402    }
2403
2404    /**
2405     * Encrypts a block
2406     *
2407     * Note: Must be extended by the child \phpseclib3\Crypt\* class
2408     *
2409     * @param string $in
2410     * @return string
2411     */
2412    abstract protected function encryptBlock($in);
2413
2414    /**
2415     * Decrypts a block
2416     *
2417     * Note: Must be extended by the child \phpseclib3\Crypt\* class
2418     *
2419     * @param string $in
2420     * @return string
2421     */
2422    abstract protected function decryptBlock($in);
2423
2424    /**
2425     * Setup the key (expansion)
2426     *
2427     * Only used if $engine == self::ENGINE_INTERNAL
2428     *
2429     * Note: Must extend by the child \phpseclib3\Crypt\* class
2430     *
2431     * @see self::setup()
2432     */
2433    abstract protected function setupKey();
2434
2435    /**
2436     * Setup the self::ENGINE_INTERNAL $engine
2437     *
2438     * (re)init, if necessary, the internal cipher $engine and flush all $buffers
2439     * Used (only) if $engine == self::ENGINE_INTERNAL
2440     *
2441     * _setup() will be called each time if $changed === true
2442     * typically this happens when using one or more of following public methods:
2443     *
2444     * - setKey()
2445     *
2446     * - setIV()
2447     *
2448     * - disableContinuousBuffer()
2449     *
2450     * - First run of encrypt() / decrypt() with no init-settings
2451     *
2452     * {@internal setup() is always called before en/decryption.}
2453     *
2454     * {@internal Could, but not must, extend by the child Crypt_* class}
2455     *
2456     * @see self::setKey()
2457     * @see self::setIV()
2458     * @see self::disableContinuousBuffer()
2459     */
2460    protected function setup()
2461    {
2462        if (!$this->changed) {
2463            return;
2464        }
2465
2466        $this->changed = false;
2467
2468        if ($this->usePoly1305 && !isset($this->poly1305Key) && method_exists($this, 'createPoly1305Key')) {
2469            $this->createPoly1305Key();
2470        }
2471
2472        $this->enbuffer = $this->debuffer = ['ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true];
2473        //$this->newtag = $this->oldtag = false;
2474
2475        if ($this->usesNonce()) {
2476            if ($this->nonce === false) {
2477                throw new InsufficientSetupException('No nonce has been defined');
2478            }
2479            if ($this->mode == self::MODE_GCM && !in_array($this->engine, [self::ENGINE_LIBSODIUM, self::ENGINE_OPENSSL_GCM])) {
2480                $this->setupGCM();
2481            }
2482        } else {
2483            $this->iv = $this->origIV;
2484        }
2485
2486        if ($this->iv === false && !in_array($this->mode, [self::MODE_STREAM, self::MODE_ECB])) {
2487            if ($this->mode != self::MODE_GCM || !in_array($this->engine, [self::ENGINE_LIBSODIUM, self::ENGINE_OPENSSL_GCM])) {
2488                throw new InsufficientSetupException('No IV has been defined');
2489            }
2490        }
2491
2492        if ($this->key === false) {
2493            throw new InsufficientSetupException('No key has been defined');
2494        }
2495
2496        $this->encryptIV = $this->decryptIV = $this->iv;
2497
2498        switch ($this->engine) {
2499            case self::ENGINE_MCRYPT:
2500                $this->enchanged = $this->dechanged = true;
2501
2502                set_error_handler(function () {
2503                });
2504
2505                if (!isset($this->enmcrypt)) {
2506                    static $mcrypt_modes = [
2507                        self::MODE_CTR    => 'ctr',
2508                        self::MODE_ECB    => MCRYPT_MODE_ECB,
2509                        self::MODE_CBC    => MCRYPT_MODE_CBC,
2510                        self::MODE_CFB    => 'ncfb',
2511                        self::MODE_CFB8   => MCRYPT_MODE_CFB,
2512                        self::MODE_OFB    => MCRYPT_MODE_NOFB,
2513                        self::MODE_OFB8   => MCRYPT_MODE_OFB,
2514                        self::MODE_STREAM => MCRYPT_MODE_STREAM,
2515                    ];
2516
2517                    $this->demcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
2518                    $this->enmcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
2519
2520                    // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer()
2521                    // to workaround mcrypt's broken ncfb implementation in buffered mode
2522                    // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
2523                    if ($this->mode == self::MODE_CFB) {
2524                        $this->ecb = mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
2525                    }
2526                } // else should mcrypt_generic_deinit be called?
2527
2528                if ($this->mode == self::MODE_CFB) {
2529                    mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
2530                }
2531
2532                restore_error_handler();
2533
2534                break;
2535            case self::ENGINE_INTERNAL:
2536                $this->setupKey();
2537                break;
2538            case self::ENGINE_EVAL:
2539                if ($this->nonIVChanged) {
2540                    $this->setupKey();
2541                    $this->setupInlineCrypt();
2542                }
2543        }
2544
2545        $this->nonIVChanged = false;
2546    }
2547
2548    /**
2549     * Pads a string
2550     *
2551     * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
2552     * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to
2553     * chr($this->block_size - (strlen($text) % $this->block_size)
2554     *
2555     * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
2556     * and padding will, hence forth, be enabled.
2557     *
2558     * @see self::unpad()
2559     * @param string $text
2560     * @throws \LengthException if padding is disabled and the plaintext's length is not a multiple of the block size
2561     * @return string
2562     */
2563    protected function pad($text)
2564    {
2565        $length = strlen($text);
2566
2567        if (!$this->padding) {
2568            if ($length % $this->block_size == 0) {
2569                return $text;
2570            } else {
2571                throw new \LengthException("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size}). Try enabling padding.");
2572            }
2573        }
2574
2575        $pad = $this->block_size - ($length % $this->block_size);
2576
2577        return str_pad($text, $length + $pad, chr($pad));
2578    }
2579
2580    /**
2581     * Unpads a string.
2582     *
2583     * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
2584     * and false will be returned.
2585     *
2586     * @see self::pad()
2587     * @param string $text
2588     * @throws \LengthException if the ciphertext's length is not a multiple of the block size
2589     * @return string
2590     */
2591    protected function unpad($text)
2592    {
2593        if (!$this->padding) {
2594            return $text;
2595        }
2596
2597        $length = ord($text[strlen($text) - 1]);
2598
2599        if (!$length | ($length > $this->block_size)) {
2600            throw new BadDecryptionException("The ciphertext has an invalid padding length ($length) compared to the block size ({$this->block_size})");
2601        }
2602
2603        return substr($text, 0, -$length);
2604    }
2605
2606    /**
2607     * Setup the performance-optimized function for de/encrypt()
2608     *
2609     * Stores the created (or existing) callback function-name
2610     * in $this->inline_crypt
2611     *
2612     * Internally for phpseclib developers:
2613     *
2614     *     _setupInlineCrypt() would be called only if:
2615     *
2616     *     - $this->engine === self::ENGINE_EVAL
2617     *
2618     *     - each time on _setup(), after(!) _setupKey()
2619     *
2620     *
2621     *     This ensures that _setupInlineCrypt() has always a
2622     *     full ready2go initializated internal cipher $engine state
2623     *     where, for example, the keys already expanded,
2624     *     keys/block_size calculated and such.
2625     *
2626     *     It is, each time if called, the responsibility of _setupInlineCrypt():
2627     *
2628     *     - to set $this->inline_crypt to a valid and fully working callback function
2629     *       as a (faster) replacement for encrypt() / decrypt()
2630     *
2631     *     - NOT to create unlimited callback functions (for memory reasons!)
2632     *       no matter how often _setupInlineCrypt() would be called. At some
2633     *       point of amount they must be generic re-useable.
2634     *
2635     *     - the code of _setupInlineCrypt() it self,
2636     *       and the generated callback code,
2637     *       must be, in following order:
2638     *       - 100% safe
2639     *       - 100% compatible to encrypt()/decrypt()
2640     *       - using only php5+ features/lang-constructs/php-extensions if
2641     *         compatibility (down to php4) or fallback is provided
2642     *       - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-)
2643     *       - >= 10% faster than encrypt()/decrypt() [which is, by the way,
2644     *         the reason for the existence of _setupInlineCrypt() :-)]
2645     *       - memory-nice
2646     *       - short (as good as possible)
2647     *
2648     * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code.
2649     *       - In case of using inline crypting, _setupInlineCrypt() must extend by the child \phpseclib3\Crypt\* class.
2650     *       - The following variable names are reserved:
2651     *         - $_*  (all variable names prefixed with an underscore)
2652     *         - $self (object reference to it self. Do not use $this, but $self instead)
2653     *         - $in (the content of $in has to en/decrypt by the generated code)
2654     *       - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only
2655     *
2656     * {@internal If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt()}
2657     *
2658     * @see self::setup()
2659     * @see self::createInlineCryptFunction()
2660     * @see self::encrypt()
2661     * @see self::decrypt()
2662     */
2663    //protected function setupInlineCrypt();
2664
2665    /**
2666     * Creates the performance-optimized function for en/decrypt()
2667     *
2668     * Internally for phpseclib developers:
2669     *
2670     *    _createInlineCryptFunction():
2671     *
2672     *    - merge the $cipher_code [setup'ed by _setupInlineCrypt()]
2673     *      with the current [$this->]mode of operation code
2674     *
2675     *    - create the $inline function, which called by encrypt() / decrypt()
2676     *      as its replacement to speed up the en/decryption operations.
2677     *
2678     *    - return the name of the created $inline callback function
2679     *
2680     *    - used to speed up en/decryption
2681     *
2682     *
2683     *
2684     *    The main reason why can speed up things [up to 50%] this way are:
2685     *
2686     *    - using variables more effective then regular.
2687     *      (ie no use of expensive arrays but integers $k_0, $k_1 ...
2688     *      or even, for example, the pure $key[] values hardcoded)
2689     *
2690     *    - avoiding 1000's of function calls of ie _encryptBlock()
2691     *      but inlining the crypt operations.
2692     *      in the mode of operation for() loop.
2693     *
2694     *    - full loop unroll the (sometimes key-dependent) rounds
2695     *      avoiding this way ++$i counters and runtime-if's etc...
2696     *
2697     *    The basic code architectur of the generated $inline en/decrypt()
2698     *    lambda function, in pseudo php, is:
2699     *
2700     *    <code>
2701     *    +----------------------------------------------------------------------------------------------+
2702     *    | callback $inline = create_function:                                                          |
2703     *    | lambda_function_0001_crypt_ECB($action, $text)                                               |
2704     *    | {                                                                                            |
2705     *    |     INSERT PHP CODE OF:                                                                      |
2706     *    |     $cipher_code['init_crypt'];                  // general init code.                       |
2707     *    |                                                  // ie: $sbox'es declarations used for       |
2708     *    |                                                  //     encrypt and decrypt'ing.             |
2709     *    |                                                                                              |
2710     *    |     switch ($action) {                                                                       |
2711     *    |         case 'encrypt':                                                                      |
2712     *    |             INSERT PHP CODE OF:                                                              |
2713     *    |             $cipher_code['init_encrypt'];       // encrypt sepcific init code.               |
2714     *    |                                                    ie: specified $key or $box                |
2715     *    |                                                        declarations for encrypt'ing.         |
2716     *    |                                                                                              |
2717     *    |             foreach ($ciphertext) {                                                          |
2718     *    |                 $in = $block_size of $ciphertext;                                            |
2719     *    |                                                                                              |
2720     *    |                 INSERT PHP CODE OF:                                                          |
2721     *    |                 $cipher_code['encrypt_block'];  // encrypt's (string) $in, which is always:  |
2722     *    |                                                 // strlen($in) == $this->block_size          |
2723     *    |                                                 // here comes the cipher algorithm in action |
2724     *    |                                                 // for encryption.                           |
2725     *    |                                                 // $cipher_code['encrypt_block'] has to      |
2726     *    |                                                 // encrypt the content of the $in variable   |
2727     *    |                                                                                              |
2728     *    |                 $plaintext .= $in;                                                           |
2729     *    |             }                                                                                |
2730     *    |             return $plaintext;                                                               |
2731     *    |                                                                                              |
2732     *    |         case 'decrypt':                                                                      |
2733     *    |             INSERT PHP CODE OF:                                                              |
2734     *    |             $cipher_code['init_decrypt'];       // decrypt sepcific init code                |
2735     *    |                                                    ie: specified $key or $box                |
2736     *    |                                                        declarations for decrypt'ing.         |
2737     *    |             foreach ($plaintext) {                                                           |
2738     *    |                 $in = $block_size of $plaintext;                                             |
2739     *    |                                                                                              |
2740     *    |                 INSERT PHP CODE OF:                                                          |
2741     *    |                 $cipher_code['decrypt_block'];  // decrypt's (string) $in, which is always   |
2742     *    |                                                 // strlen($in) == $this->block_size          |
2743     *    |                                                 // here comes the cipher algorithm in action |
2744     *    |                                                 // for decryption.                           |
2745     *    |                                                 // $cipher_code['decrypt_block'] has to      |
2746     *    |                                                 // decrypt the content of the $in variable   |
2747     *    |                 $ciphertext .= $in;                                                          |
2748     *    |             }                                                                                |
2749     *    |             return $ciphertext;                                                              |
2750     *    |     }                                                                                        |
2751     *    | }                                                                                            |
2752     *    +----------------------------------------------------------------------------------------------+
2753     *    </code>
2754     *
2755     *    See also the \phpseclib3\Crypt\*::_setupInlineCrypt()'s for
2756     *    productive inline $cipher_code's how they works.
2757     *
2758     *    Structure of:
2759     *    <code>
2760     *    $cipher_code = [
2761     *        'init_crypt'    => (string) '', // optional
2762     *        'init_encrypt'  => (string) '', // optional
2763     *        'init_decrypt'  => (string) '', // optional
2764     *        'encrypt_block' => (string) '', // required
2765     *        'decrypt_block' => (string) ''  // required
2766     *    ];
2767     *    </code>
2768     *
2769     * @see self::setupInlineCrypt()
2770     * @see self::encrypt()
2771     * @see self::decrypt()
2772     * @param array $cipher_code
2773     * @return string (the name of the created callback function)
2774     */
2775    protected function createInlineCryptFunction($cipher_code)
2776    {
2777        $block_size = $this->block_size;
2778
2779        // optional
2780        $init_crypt    = isset($cipher_code['init_crypt'])    ? $cipher_code['init_crypt']    : '';
2781        $init_encrypt  = isset($cipher_code['init_encrypt'])  ? $cipher_code['init_encrypt']  : '';
2782        $init_decrypt  = isset($cipher_code['init_decrypt'])  ? $cipher_code['init_decrypt']  : '';
2783        // required
2784        $encrypt_block = $cipher_code['encrypt_block'];
2785        $decrypt_block = $cipher_code['decrypt_block'];
2786
2787        // Generating mode of operation inline code,
2788        // merged with the $cipher_code algorithm
2789        // for encrypt- and decryption.
2790        switch ($this->mode) {
2791            case self::MODE_ECB:
2792                $encrypt = $init_encrypt . '
2793                    $_ciphertext = "";
2794                    $_plaintext_len = strlen($_text);
2795
2796                    for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
2797                        $in = substr($_text, $_i, ' . $block_size . ');
2798                        ' . $encrypt_block . '
2799                        $_ciphertext.= $in;
2800                    }
2801
2802                    return $_ciphertext;
2803                    ';
2804
2805                $decrypt = $init_decrypt . '
2806                    $_plaintext = "";
2807                    $_text = str_pad($_text, strlen($_text) + (' . $block_size . ' - strlen($_text) % ' . $block_size . ') % ' . $block_size . ', chr(0));
2808                    $_ciphertext_len = strlen($_text);
2809
2810                    for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
2811                        $in = substr($_text, $_i, ' . $block_size . ');
2812                        ' . $decrypt_block . '
2813                        $_plaintext.= $in;
2814                    }
2815
2816                    return $this->unpad($_plaintext);
2817                    ';
2818                break;
2819            case self::MODE_CTR:
2820                $encrypt = $init_encrypt . '
2821                    $_ciphertext = "";
2822                    $_plaintext_len = strlen($_text);
2823                    $_xor = $this->encryptIV;
2824                    $_buffer = &$this->enbuffer;
2825                    if (strlen($_buffer["ciphertext"])) {
2826                        for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
2827                            $_block = substr($_text, $_i, ' . $block_size . ');
2828                            if (strlen($_block) > strlen($_buffer["ciphertext"])) {
2829                                $in = $_xor;
2830                                ' . $encrypt_block . '
2831                                \phpseclib3\Common\Functions\Strings::increment_str($_xor);
2832                                $_buffer["ciphertext"].= $in;
2833                            }
2834                            $_key = \phpseclib3\Common\Functions\Strings::shift($_buffer["ciphertext"], ' . $block_size . ');
2835                            $_ciphertext.= $_block ^ $_key;
2836                        }
2837                    } else {
2838                        for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
2839                            $_block = substr($_text, $_i, ' . $block_size . ');
2840                            $in = $_xor;
2841                            ' . $encrypt_block . '
2842                            \phpseclib3\Common\Functions\Strings::increment_str($_xor);
2843                            $_key = $in;
2844                            $_ciphertext.= $_block ^ $_key;
2845                        }
2846                    }
2847                    if ($this->continuousBuffer) {
2848                        $this->encryptIV = $_xor;
2849                        if ($_start = $_plaintext_len % ' . $block_size . ') {
2850                            $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
2851                        }
2852                    }
2853
2854                    return $_ciphertext;
2855                ';
2856
2857                $decrypt = $init_encrypt . '
2858                    $_plaintext = "";
2859                    $_ciphertext_len = strlen($_text);
2860                    $_xor = $this->decryptIV;
2861                    $_buffer = &$this->debuffer;
2862
2863                    if (strlen($_buffer["ciphertext"])) {
2864                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
2865                            $_block = substr($_text, $_i, ' . $block_size . ');
2866                            if (strlen($_block) > strlen($_buffer["ciphertext"])) {
2867                                $in = $_xor;
2868                                ' . $encrypt_block . '
2869                                \phpseclib3\Common\Functions\Strings::increment_str($_xor);
2870                                $_buffer["ciphertext"].= $in;
2871                            }
2872                            $_key = \phpseclib3\Common\Functions\Strings::shift($_buffer["ciphertext"], ' . $block_size . ');
2873                            $_plaintext.= $_block ^ $_key;
2874                        }
2875                    } else {
2876                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
2877                            $_block = substr($_text, $_i, ' . $block_size . ');
2878                            $in = $_xor;
2879                            ' . $encrypt_block . '
2880                            \phpseclib3\Common\Functions\Strings::increment_str($_xor);
2881                            $_key = $in;
2882                            $_plaintext.= $_block ^ $_key;
2883                        }
2884                    }
2885                    if ($this->continuousBuffer) {
2886                        $this->decryptIV = $_xor;
2887                        if ($_start = $_ciphertext_len % ' . $block_size . ') {
2888                            $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
2889                        }
2890                    }
2891
2892                    return $_plaintext;
2893                    ';
2894                break;
2895            case self::MODE_CFB:
2896                $encrypt = $init_encrypt . '
2897                    $_ciphertext = "";
2898                    $_buffer = &$this->enbuffer;
2899
2900                    if ($this->continuousBuffer) {
2901                        $_iv = &$this->encryptIV;
2902                        $_pos = &$_buffer["pos"];
2903                    } else {
2904                        $_iv = $this->encryptIV;
2905                        $_pos = 0;
2906                    }
2907                    $_len = strlen($_text);
2908                    $_i = 0;
2909                    if ($_pos) {
2910                        $_orig_pos = $_pos;
2911                        $_max = ' . $block_size . ' - $_pos;
2912                        if ($_len >= $_max) {
2913                            $_i = $_max;
2914                            $_len-= $_max;
2915                            $_pos = 0;
2916                        } else {
2917                            $_i = $_len;
2918                            $_pos+= $_len;
2919                            $_len = 0;
2920                        }
2921                        $_ciphertext = substr($_iv, $_orig_pos) ^ $_text;
2922                        $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i);
2923                    }
2924                    while ($_len >= ' . $block_size . ') {
2925                        $in = $_iv;
2926                        ' . $encrypt_block . ';
2927                        $_iv = $in ^ substr($_text, $_i, ' . $block_size . ');
2928                        $_ciphertext.= $_iv;
2929                        $_len-= ' . $block_size . ';
2930                        $_i+= ' . $block_size . ';
2931                    }
2932                    if ($_len) {
2933                        $in = $_iv;
2934                        ' . $encrypt_block . '
2935                        $_iv = $in;
2936                        $_block = $_iv ^ substr($_text, $_i);
2937                        $_iv = substr_replace($_iv, $_block, 0, $_len);
2938                        $_ciphertext.= $_block;
2939                        $_pos = $_len;
2940                    }
2941                    return $_ciphertext;
2942                ';
2943
2944                $decrypt = $init_encrypt . '
2945                    $_plaintext = "";
2946                    $_buffer = &$this->debuffer;
2947
2948                    if ($this->continuousBuffer) {
2949                        $_iv = &$this->decryptIV;
2950                        $_pos = &$_buffer["pos"];
2951                    } else {
2952                        $_iv = $this->decryptIV;
2953                        $_pos = 0;
2954                    }
2955                    $_len = strlen($_text);
2956                    $_i = 0;
2957                    if ($_pos) {
2958                        $_orig_pos = $_pos;
2959                        $_max = ' . $block_size . ' - $_pos;
2960                        if ($_len >= $_max) {
2961                            $_i = $_max;
2962                            $_len-= $_max;
2963                            $_pos = 0;
2964                        } else {
2965                            $_i = $_len;
2966                            $_pos+= $_len;
2967                            $_len = 0;
2968                        }
2969                        $_plaintext = substr($_iv, $_orig_pos) ^ $_text;
2970                        $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i);
2971                    }
2972                    while ($_len >= ' . $block_size . ') {
2973                        $in = $_iv;
2974                        ' . $encrypt_block . '
2975                        $_iv = $in;
2976                        $cb = substr($_text, $_i, ' . $block_size . ');
2977                        $_plaintext.= $_iv ^ $cb;
2978                        $_iv = $cb;
2979                        $_len-= ' . $block_size . ';
2980                        $_i+= ' . $block_size . ';
2981                    }
2982                    if ($_len) {
2983                        $in = $_iv;
2984                        ' . $encrypt_block . '
2985                        $_iv = $in;
2986                        $_plaintext.= $_iv ^ substr($_text, $_i);
2987                        $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len);
2988                        $_pos = $_len;
2989                    }
2990
2991                    return $_plaintext;
2992                    ';
2993                break;
2994            case self::MODE_CFB8:
2995                $encrypt = $init_encrypt . '
2996                    $_ciphertext = "";
2997                    $_len = strlen($_text);
2998                    $_iv = $this->encryptIV;
2999
3000                    for ($_i = 0; $_i < $_len; ++$_i) {
3001                        $in = $_iv;
3002                        ' . $encrypt_block . '
3003                        $_ciphertext .= ($_c = $_text[$_i] ^ $in);
3004                        $_iv = substr($_iv, 1) . $_c;
3005                    }
3006
3007                    if ($this->continuousBuffer) {
3008                        if ($_len >= ' . $block_size . ') {
3009                            $this->encryptIV = substr($_ciphertext, -' . $block_size . ');
3010                        } else {
3011                            $this->encryptIV = substr($this->encryptIV, $_len - ' . $block_size . ') . substr($_ciphertext, -$_len);
3012                        }
3013                    }
3014
3015                    return $_ciphertext;
3016                    ';
3017                $decrypt = $init_encrypt . '
3018                    $_plaintext = "";
3019                    $_len = strlen($_text);
3020                    $_iv = $this->decryptIV;
3021
3022                    for ($_i = 0; $_i < $_len; ++$_i) {
3023                        $in = $_iv;
3024                        ' . $encrypt_block . '
3025                        $_plaintext .= $_text[$_i] ^ $in;
3026                        $_iv = substr($_iv, 1) . $_text[$_i];
3027                    }
3028
3029                    if ($this->continuousBuffer) {
3030                        if ($_len >= ' . $block_size . ') {
3031                            $this->decryptIV = substr($_text, -' . $block_size . ');
3032                        } else {
3033                            $this->decryptIV = substr($this->decryptIV, $_len - ' . $block_size . ') . substr($_text, -$_len);
3034                        }
3035                    }
3036
3037                    return $_plaintext;
3038                    ';
3039                break;
3040            case self::MODE_OFB8:
3041                $encrypt = $init_encrypt . '
3042                    $_ciphertext = "";
3043                    $_len = strlen($_text);
3044                    $_iv = $this->encryptIV;
3045
3046                    for ($_i = 0; $_i < $_len; ++$_i) {
3047                        $in = $_iv;
3048                        ' . $encrypt_block . '
3049                        $_ciphertext.= $_text[$_i] ^ $in;
3050                        $_iv = substr($_iv, 1) . $in[0];
3051                    }
3052
3053                    if ($this->continuousBuffer) {
3054                        $this->encryptIV = $_iv;
3055                    }
3056
3057                    return $_ciphertext;
3058                    ';
3059                $decrypt = $init_encrypt . '
3060                    $_plaintext = "";
3061                    $_len = strlen($_text);
3062                    $_iv = $this->decryptIV;
3063
3064                    for ($_i = 0; $_i < $_len; ++$_i) {
3065                        $in = $_iv;
3066                        ' . $encrypt_block . '
3067                        $_plaintext.= $_text[$_i] ^ $in;
3068                        $_iv = substr($_iv, 1) . $in[0];
3069                    }
3070
3071                    if ($this->continuousBuffer) {
3072                        $this->decryptIV = $_iv;
3073                    }
3074
3075                    return $_plaintext;
3076                    ';
3077                break;
3078            case self::MODE_OFB:
3079                $encrypt = $init_encrypt . '
3080                    $_ciphertext = "";
3081                    $_plaintext_len = strlen($_text);
3082                    $_xor = $this->encryptIV;
3083                    $_buffer = &$this->enbuffer;
3084
3085                    if (strlen($_buffer["xor"])) {
3086                        for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
3087                            $_block = substr($_text, $_i, ' . $block_size . ');
3088                            if (strlen($_block) > strlen($_buffer["xor"])) {
3089                                $in = $_xor;
3090                                ' . $encrypt_block . '
3091                                $_xor = $in;
3092                                $_buffer["xor"].= $_xor;
3093                            }
3094                            $_key = \phpseclib3\Common\Functions\Strings::shift($_buffer["xor"], ' . $block_size . ');
3095                            $_ciphertext.= $_block ^ $_key;
3096                        }
3097                    } else {
3098                        for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
3099                            $in = $_xor;
3100                            ' . $encrypt_block . '
3101                            $_xor = $in;
3102                            $_ciphertext.= substr($_text, $_i, ' . $block_size . ') ^ $_xor;
3103                        }
3104                        $_key = $_xor;
3105                    }
3106                    if ($this->continuousBuffer) {
3107                        $this->encryptIV = $_xor;
3108                        if ($_start = $_plaintext_len % ' . $block_size . ') {
3109                             $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
3110                        }
3111                    }
3112                    return $_ciphertext;
3113                    ';
3114
3115                $decrypt = $init_encrypt . '
3116                    $_plaintext = "";
3117                    $_ciphertext_len = strlen($_text);
3118                    $_xor = $this->decryptIV;
3119                    $_buffer = &$this->debuffer;
3120
3121                    if (strlen($_buffer["xor"])) {
3122                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
3123                            $_block = substr($_text, $_i, ' . $block_size . ');
3124                            if (strlen($_block) > strlen($_buffer["xor"])) {
3125                                $in = $_xor;
3126                                ' . $encrypt_block . '
3127                                $_xor = $in;
3128                                $_buffer["xor"].= $_xor;
3129                            }
3130                            $_key = \phpseclib3\Common\Functions\Strings::shift($_buffer["xor"], ' . $block_size . ');
3131                            $_plaintext.= $_block ^ $_key;
3132                        }
3133                    } else {
3134                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
3135                            $in = $_xor;
3136                            ' . $encrypt_block . '
3137                            $_xor = $in;
3138                            $_plaintext.= substr($_text, $_i, ' . $block_size . ') ^ $_xor;
3139                        }
3140                        $_key = $_xor;
3141                    }
3142                    if ($this->continuousBuffer) {
3143                        $this->decryptIV = $_xor;
3144                        if ($_start = $_ciphertext_len % ' . $block_size . ') {
3145                             $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
3146                        }
3147                    }
3148                    return $_plaintext;
3149                    ';
3150                break;
3151            case self::MODE_STREAM:
3152                $encrypt = $init_encrypt . '
3153                    $_ciphertext = "";
3154                    ' . $encrypt_block . '
3155                    return $_ciphertext;
3156                    ';
3157                $decrypt = $init_decrypt . '
3158                    $_plaintext = "";
3159                    ' . $decrypt_block . '
3160                    return $_plaintext;
3161                    ';
3162                break;
3163            // case self::MODE_CBC:
3164            default:
3165                $encrypt = $init_encrypt . '
3166                    $_ciphertext = "";
3167                    $_plaintext_len = strlen($_text);
3168
3169                    $in = $this->encryptIV;
3170
3171                    for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
3172                        $in = substr($_text, $_i, ' . $block_size . ') ^ $in;
3173                        ' . $encrypt_block . '
3174                        $_ciphertext.= $in;
3175                    }
3176
3177                    if ($this->continuousBuffer) {
3178                        $this->encryptIV = $in;
3179                    }
3180
3181                    return $_ciphertext;
3182                    ';
3183
3184                $decrypt = $init_decrypt . '
3185                    $_plaintext = "";
3186                    $_text = str_pad($_text, strlen($_text) + (' . $block_size . ' - strlen($_text) % ' . $block_size . ') % ' . $block_size . ', chr(0));
3187                    $_ciphertext_len = strlen($_text);
3188
3189                    $_iv = $this->decryptIV;
3190
3191                    for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
3192                        $in = $_block = substr($_text, $_i, ' . $block_size . ');
3193                        ' . $decrypt_block . '
3194                        $_plaintext.= $in ^ $_iv;
3195                        $_iv = $_block;
3196                    }
3197
3198                    if ($this->continuousBuffer) {
3199                        $this->decryptIV = $_iv;
3200                    }
3201
3202                    return $this->unpad($_plaintext);
3203                    ';
3204                break;
3205        }
3206
3207        // Before discrediting this, please read the following:
3208        // @see https://github.com/phpseclib/phpseclib/issues/1293
3209        // @see https://github.com/phpseclib/phpseclib/pull/1143
3210        eval('$func = function ($_action, $_text) { ' . $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }};');
3211
3212        return \Closure::bind($func, $this, static::class);
3213    }
3214
3215    /**
3216     * Convert float to int
3217     *
3218     * On ARM CPUs converting floats to ints doesn't always work
3219     *
3220     * @param string $x
3221     * @return int
3222     */
3223    protected static function safe_intval($x)
3224    {
3225        if (is_int($x)) {
3226            return $x;
3227        }
3228
3229        if (self::$use_reg_intval) {
3230            return PHP_INT_SIZE == 4 && PHP_VERSION_ID >= 80100 ? intval($x) : $x;
3231        }
3232
3233        return (fmod($x, 0x80000000) & 0x7FFFFFFF) |
3234            ((fmod(floor($x / 0x80000000), 2) & 1) << 31);
3235    }
3236
3237    /**
3238     * eval()'able string for in-line float to int
3239     *
3240     * @return string
3241     */
3242    protected static function safe_intval_inline()
3243    {
3244        if (self::$use_reg_intval) {
3245            return PHP_INT_SIZE == 4 && PHP_VERSION_ID >= 80100 ? 'intval(%s)' : '%s';
3246        }
3247
3248        $safeint = '(is_int($temp = %s) ? $temp : (fmod($temp, 0x80000000) & 0x7FFFFFFF) | ';
3249        return $safeint . '((fmod(floor($temp / 0x80000000), 2) & 1) << 31))';
3250    }
3251
3252    /**
3253     * Sets up GCM parameters
3254     *
3255     * See steps 1-2 of https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf#page=23
3256     * for more info
3257     *
3258     */
3259    private function setupGCM()
3260    {
3261        // don't keep on re-calculating $this->h
3262        if (!$this->h || $this->hKey != $this->key) {
3263            $cipher = new static('ecb');
3264            $cipher->setKey($this->key);
3265            $cipher->disablePadding();
3266
3267            $this->h = self::$gcmField->newInteger(
3268                Strings::switchEndianness($cipher->encrypt("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"))
3269            );
3270            $this->hKey = $this->key;
3271        }
3272
3273        if (strlen($this->nonce) == 12) {
3274            $this->iv = $this->nonce . "\0\0\0\1";
3275        } else {
3276            $this->iv = $this->ghash(
3277                self::nullPad128($this->nonce) . str_repeat("\0", 8) . self::len64($this->nonce)
3278            );
3279        }
3280    }
3281
3282    /**
3283     * Performs GHASH operation
3284     *
3285     * See https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf#page=20
3286     * for more info
3287     *
3288     * @see self::decrypt()
3289     * @see self::encrypt()
3290     * @param string $x
3291     * @return string
3292     */
3293    private function ghash($x)
3294    {
3295        $h = $this->h;
3296        $y = ["\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"];
3297        $x = str_split($x, 16);
3298        $n = 0;
3299        // the switchEndianness calls are necessary because the multiplication algorithm in BinaryField/Integer
3300        // interprets strings as polynomials in big endian order whereas in GCM they're interpreted in little
3301        // endian order per https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf#page=19.
3302        // big endian order is what binary field elliptic curves use per http://www.secg.org/sec1-v2.pdf#page=18.
3303
3304        // we could switchEndianness here instead of in the while loop but doing so in the while loop seems like it
3305        // might be slightly more performant
3306        //$x = Strings::switchEndianness($x);
3307        foreach ($x as $xn) {
3308            $xn = Strings::switchEndianness($xn);
3309            $t = $y[$n] ^ $xn;
3310            $temp = self::$gcmField->newInteger($t);
3311            $y[++$n] = $temp->multiply($h)->toBytes();
3312            $y[$n] = substr($y[$n], 1);
3313        }
3314        $y[$n] = Strings::switchEndianness($y[$n]);
3315        return $y[$n];
3316    }
3317
3318    /**
3319     * Returns the bit length of a string in a packed format
3320     *
3321     * @see self::decrypt()
3322     * @see self::encrypt()
3323     * @see self::setupGCM()
3324     * @param string $str
3325     * @return string
3326     */
3327    private static function len64($str)
3328    {
3329        return "\0\0\0\0" . pack('N', 8 * strlen($str));
3330    }
3331
3332    /**
3333     * NULL pads a string to be a multiple of 128
3334     *
3335     * @see self::decrypt()
3336     * @see self::encrypt()
3337     * @see self::setupGCM()
3338     * @param string $str
3339     * @return string
3340     */
3341    protected static function nullPad128($str)
3342    {
3343        $len = strlen($str);
3344        return $str . str_repeat("\0", 16 * ceil($len / 16) - $len);
3345    }
3346
3347    /**
3348     * Calculates Poly1305 MAC
3349     *
3350     * On my system ChaCha20, with libsodium, takes 0.5s. With this custom Poly1305 implementation
3351     * it takes 1.2s.
3352     *
3353     * @see self::decrypt()
3354     * @see self::encrypt()
3355     * @param string $text
3356     * @return string
3357     */
3358    protected function poly1305($text)
3359    {
3360        $s = $this->poly1305Key; // strlen($this->poly1305Key) == 32
3361        $r = Strings::shift($s, 16);
3362        $r = strrev($r);
3363        $r &= "\x0f\xff\xff\xfc\x0f\xff\xff\xfc\x0f\xff\xff\xfc\x0f\xff\xff\xff";
3364        $s = strrev($s);
3365
3366        $r = self::$poly1305Field->newInteger(new BigInteger($r, 256));
3367        $s = self::$poly1305Field->newInteger(new BigInteger($s, 256));
3368        $a = self::$poly1305Field->newInteger(new BigInteger());
3369
3370        $blocks = str_split($text, 16);
3371        foreach ($blocks as $block) {
3372            $n = strrev($block . chr(1));
3373            $n = self::$poly1305Field->newInteger(new BigInteger($n, 256));
3374            $a = $a->add($n);
3375            $a = $a->multiply($r);
3376        }
3377        $r = $a->toBigInteger()->add($s->toBigInteger());
3378        $mask = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
3379        return strrev($r->toBytes()) & $mask;
3380    }
3381
3382    /**
3383     * Return the mode
3384     *
3385     * You can do $obj instanceof AES or whatever to get the cipher but you can't do that to get the mode
3386     *
3387     * @return string
3388     */
3389    public function getMode()
3390    {
3391        return array_flip(self::MODE_MAP)[$this->mode];
3392    }
3393
3394    /**
3395     * Is the continuous buffer enabled?
3396     *
3397     * @return boolean
3398     */
3399    public function continuousBufferEnabled()
3400    {
3401        return $this->continuousBuffer;
3402    }
3403}
3404