Issues (365)

src/Library/libraries/phpseclib/Crypt/Base.php (27 issues)

1
<?php
2
3
/**
4
 * Base Class for all \phpseclib\Crypt\* cipher classes
5
 *
6
 * PHP version 5
7
 *
8
 * Internally for phpseclib developers:
9
 *  If you plan to add a new cipher class, please note following rules:
10
 *
11
 *  - The new \phpseclib\Crypt\* cipher class should extend \phpseclib\Crypt\Base
12
 *
13
 *  - Following methods are then required to be overridden/overloaded:
14
 *
15
 *    - _encryptBlock()
16
 *
17
 *    - _decryptBlock()
18
 *
19
 *    - _setupKey()
20
 *
21
 *  - All other methods are optional to be overridden/overloaded
22
 *
23
 *  - Look at the source code of the current ciphers how they extend \phpseclib\Crypt\Base
24
 *    and take one of them as a start up for the new cipher class.
25
 *
26
 *  - Please read all the other comments/notes/hints here also for each class var/method
27
 *
28
 * @category  Crypt
29
 * @package   Base
30
 * @author    Jim Wigginton <[email protected]>
31
 * @author    Hans-Juergen Petrich <[email protected]>
32
 * @copyright 2007 Jim Wigginton
33
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
34
 * @link      http://phpseclib.sourceforge.net
35
 */
36
37
namespace phpseclib\Crypt;
38
39
/**
40
 * Base Class for all \phpseclib\Crypt\* cipher classes
41
 *
42
 * @package Base
43
 * @author  Jim Wigginton <[email protected]>
44
 * @author  Hans-Juergen Petrich <[email protected]>
45
 */
46
abstract class Base
47
{
48
    /**#@+
49
     * @access public
50
     * @see \phpseclib\Crypt\Base::encrypt()
51
     * @see \phpseclib\Crypt\Base::decrypt()
52
     */
53
    /**
54
     * Encrypt / decrypt using the Counter mode.
55
     *
56
     * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
57
     *
58
     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
59
     */
60
    public const MODE_CTR = -1;
61
    /**
62
     * Encrypt / decrypt using the Electronic Code Book mode.
63
     *
64
     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
65
     */
66
    public const MODE_ECB = 1;
67
    /**
68
     * Encrypt / decrypt using the Code Book Chaining mode.
69
     *
70
     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
71
     */
72
    public const MODE_CBC = 2;
73
    /**
74
     * Encrypt / decrypt using the Cipher Feedback mode.
75
     *
76
     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
77
     */
78
    public const MODE_CFB = 3;
79
    /**
80
     * Encrypt / decrypt using the Output Feedback mode.
81
     *
82
     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
83
     */
84
    public const MODE_OFB = 4;
85
    /**
86
     * Encrypt / decrypt using streaming mode.
87
     */
88
    public const MODE_STREAM = 5;
89
    /**#@-*/
90
91
    /**
92
     * Whirlpool available flag
93
     *
94
     * @see \phpseclib\Crypt\Base::_hashInlineCryptFunction()
95
     * @var bool
96
     * @access private
97
     */
98
    public static $WHIRLPOOL_AVAILABLE;
99
100
    /**#@+
101
     * @access private
102
     * @see \phpseclib\Crypt\Base::__construct()
103
     */
104
    /**
105
     * Base value for the internal implementation $engine switch
106
     */
107
    public const ENGINE_INTERNAL = 1;
108
    /**
109
     * Base value for the mcrypt implementation $engine switch
110
     */
111
    public const ENGINE_MCRYPT = 2;
112
    /**
113
     * Base value for the mcrypt implementation $engine switch
114
     */
115
    public const ENGINE_OPENSSL = 3;
116
    /**#@-*/
117
118
    /**
119
     * The Encryption Mode
120
     *
121
     * @see self::__construct()
122
     * @var int
123
     * @access private
124
     */
125
    public $mode;
126
127
    /**
128
     * The Block Length of the block cipher
129
     *
130
     * @var int
131
     * @access private
132
     */
133
    public $block_size = 16;
134
135
    /**
136
     * The Key
137
     *
138
     * @see self::setKey()
139
     * @var string
140
     * @access private
141
     */
142
    public $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
143
144
    /**
145
     * The Initialization Vector
146
     *
147
     * @see self::setIV()
148
     * @var string
149
     * @access private
150
     */
151
    public $iv;
152
153
    /**
154
     * A "sliding" Initialization Vector
155
     *
156
     * @see self::enableContinuousBuffer()
157
     * @see self::_clearBuffers()
158
     * @var string
159
     * @access private
160
     */
161
    public $encryptIV;
162
163
    /**
164
     * A "sliding" Initialization Vector
165
     *
166
     * @see self::enableContinuousBuffer()
167
     * @see self::_clearBuffers()
168
     * @var string
169
     * @access private
170
     */
171
    public $decryptIV;
172
173
    /**
174
     * Continuous Buffer status
175
     *
176
     * @see self::enableContinuousBuffer()
177
     * @var bool
178
     * @access private
179
     */
180
    public $continuousBuffer = false;
181
182
    /**
183
     * Encryption buffer for CTR, OFB and CFB modes
184
     *
185
     * @see self::encrypt()
186
     * @see self::_clearBuffers()
187
     * @var array
188
     * @access private
189
     */
190
    public $enbuffer;
191
192
    /**
193
     * Decryption buffer for CTR, OFB and CFB modes
194
     *
195
     * @see self::decrypt()
196
     * @see self::_clearBuffers()
197
     * @var array
198
     * @access private
199
     */
200
    public $debuffer;
201
202
    /**
203
     * mcrypt resource for encryption
204
     *
205
     * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
206
     * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
207
     *
208
     * @see self::encrypt()
209
     * @var resource
210
     * @access private
211
     */
212
    public $enmcrypt;
213
214
    /**
215
     * mcrypt resource for decryption
216
     *
217
     * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
218
     * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
219
     *
220
     * @see self::decrypt()
221
     * @var resource
222
     * @access private
223
     */
224
    public $demcrypt;
225
226
    /**
227
     * Does the enmcrypt resource need to be (re)initialized?
228
     *
229
     * @see \phpseclib\Crypt\Twofish::setKey()
230
     * @see \phpseclib\Crypt\Twofish::setIV()
231
     * @var bool
232
     * @access private
233
     */
234
    public $enchanged = true;
235
236
    /**
237
     * Does the demcrypt resource need to be (re)initialized?
238
     *
239
     * @see \phpseclib\Crypt\Twofish::setKey()
240
     * @see \phpseclib\Crypt\Twofish::setIV()
241
     * @var bool
242
     * @access private
243
     */
244
    public $dechanged = true;
245
246
    /**
247
     * mcrypt resource for CFB mode
248
     *
249
     * mcrypt's CFB mode, in (and only in) buffered context,
250
     * is broken, so phpseclib implements the CFB mode by it self,
251
     * even when the mcrypt php extension is available.
252
     *
253
     * In order to do the CFB-mode work (fast) phpseclib
254
     * use a separate ECB-mode mcrypt resource.
255
     *
256
     * @link http://phpseclib.sourceforge.net/cfb-demo.phps
257
     * @see self::encrypt()
258
     * @see self::decrypt()
259
     * @see self::_setupMcrypt()
260
     * @var resource
261
     * @access private
262
     */
263
    public $ecb;
264
265
    /**
266
     * Optimizing value while CFB-encrypting
267
     *
268
     * Only relevant if $continuousBuffer enabled
269
     * and $engine == self::ENGINE_MCRYPT
270
     *
271
     * It's faster to re-init $enmcrypt if
272
     * $buffer bytes > $cfb_init_len than
273
     * using the $ecb resource furthermore.
274
     *
275
     * This value depends of the chosen cipher
276
     * and the time it would be needed for it's
277
     * initialization [by mcrypt_generic_init()]
278
     * which, typically, depends on the complexity
279
     * on its internaly Key-expanding algorithm.
280
     *
281
     * @see self::encrypt()
282
     * @var int
283
     * @access private
284
     */
285
    public $cfb_init_len = 600;
286
287
    /**
288
     * Does internal cipher state need to be (re)initialized?
289
     *
290
     * @see self::setKey()
291
     * @see self::setIV()
292
     * @see self::disableContinuousBuffer()
293
     * @var bool
294
     * @access private
295
     */
296
    public $changed = true;
297
298
    /**
299
     * Padding status
300
     *
301
     * @see self::enablePadding()
302
     * @var bool
303
     * @access private
304
     */
305
    public $padding = true;
306
307
    /**
308
     * Is the mode one that is paddable?
309
     *
310
     * @see self::__construct()
311
     * @var bool
312
     * @access private
313
     */
314
    public $paddable = false;
315
316
    /**
317
     * Holds which crypt engine internaly should be use,
318
     * which will be determined automatically on __construct()
319
     *
320
     * Currently available $engines are:
321
     * - self::ENGINE_OPENSSL  (very fast, php-extension: openssl, extension_loaded('openssl') required)
322
     * - self::ENGINE_MCRYPT   (fast, php-extension: mcrypt, extension_loaded('mcrypt') required)
323
     * - self::ENGINE_INTERNAL (slower, pure php-engine, no php-extension required)
324
     *
325
     * @see self::_setEngine()
326
     * @see self::encrypt()
327
     * @see self::decrypt()
328
     * @var int
329
     * @access private
330
     */
331
    public $engine;
332
333
    /**
334
     * Holds the preferred crypt engine
335
     *
336
     * @see self::_setEngine()
337
     * @see self::setPreferredEngine()
338
     * @var int
339
     * @access private
340
     */
341
    public $preferredEngine;
342
343
    /**
344
     * The mcrypt specific name of the cipher
345
     *
346
     * Only used if $engine == self::ENGINE_MCRYPT
347
     *
348
     * @link http://www.php.net/mcrypt_module_open
349
     * @link http://www.php.net/mcrypt_list_algorithms
350
     * @see self::_setupMcrypt()
351
     * @var string
352
     * @access private
353
     */
354
    public $cipher_name_mcrypt;
355
356
    /**
357
     * The openssl specific name of the cipher
358
     *
359
     * Only used if $engine == self::ENGINE_OPENSSL
360
     *
361
     * @link http://www.php.net/openssl-get-cipher-methods
362
     * @var string
363
     * @access private
364
     */
365
    public $cipher_name_openssl;
366
367
    /**
368
     * The openssl specific name of the cipher in ECB mode
369
     *
370
     * If OpenSSL does not support the mode we're trying to use (CTR)
371
     * it can still be emulated with ECB mode.
372
     *
373
     * @link http://www.php.net/openssl-get-cipher-methods
374
     * @var string
375
     * @access private
376
     */
377
    public $cipher_name_openssl_ecb;
378
379
    /**
380
     * The default salt used by setPassword()
381
     *
382
     * @see self::setPassword()
383
     * @var string
384
     * @access private
385
     */
386
    public $password_default_salt = 'phpseclib/salt';
387
388
    /**
389
     * The name of the performance-optimized callback function
390
     *
391
     * Used by encrypt() / decrypt()
392
     * only if $engine == self::ENGINE_INTERNAL
393
     *
394
     * @see self::encrypt()
395
     * @see self::decrypt()
396
     * @see self::_setupInlineCrypt()
397
     * @see self::$use_inline_crypt
398
     * @var Callback
399
     * @access private
400
     */
401
    public $inline_crypt;
402
403
    /**
404
     * Holds whether performance-optimized $inline_crypt() can/should be used.
405
     *
406
     * @see self::encrypt()
407
     * @see self::decrypt()
408
     * @see self::inline_crypt
409
     * @var mixed
410
     * @access private
411
     */
412
    public $use_inline_crypt;
413
414
    /**
415
     * If OpenSSL can be used in ECB but not in CTR we can emulate CTR
416
     *
417
     * @see self::_openssl_ctr_process()
418
     * @var bool
419
     * @access private
420
     */
421
    public $openssl_emulate_ctr = false;
422
423
    /**
424
     * Determines what options are passed to openssl_encrypt/decrypt
425
     *
426
     * @see self::isValidEngine()
427
     * @var mixed
428
     * @access private
429
     */
430
    public $openssl_options;
431
432
    /**
433
     * Has the key length explicitly been set or should it be derived from the key, itself?
434
     *
435
     * @see self::setKeyLength()
436
     * @var bool
437
     * @access private
438
     */
439
    public $explicit_key_length = false;
440
441
    /**
442
     * Don't truncate / null pad key
443
     *
444
     * @see self::_clearBuffers()
445
     * @var bool
446
     * @access private
447
     */
448
    public $skip_key_adjustment = false;
449
450
    /**
451
     * Default Constructor.
452
     *
453
     * Determines whether or not the mcrypt extension should be used.
454
     *
455
     * $mode could be:
456
     *
457
     * - self::MODE_ECB
458
     *
459
     * - self::MODE_CBC
460
     *
461
     * - self::MODE_CTR
462
     *
463
     * - self::MODE_CFB
464
     *
465
     * - self::MODE_OFB
466
     *
467
     * If not explicitly set, self::MODE_CBC will be used.
468
     *
469
     * @param int $mode
470
     * @access public
471
     */
472
    public function __construct($mode = self::MODE_CBC)
473
    {
474
        // $mode dependent settings
475
        switch ($mode) {
476
            case self::MODE_ECB:
477
                $this->paddable = true;
478
                $this->mode = self::MODE_ECB;
479
                break;
480
            case self::MODE_CTR:
481
            case self::MODE_CFB:
482
            case self::MODE_OFB:
483
            case self::MODE_STREAM:
484
                $this->mode = $mode;
485
                break;
486
            case self::MODE_CBC:
487
            default:
488
                $this->paddable = true;
489
                $this->mode = self::MODE_CBC;
490
        }
491
492
        $this->_setEngine();
493
494
        // Determining whether inline crypting can be used by the cipher
495
        if ($this->use_inline_crypt !== false && function_exists('create_function')) {
496
            $this->use_inline_crypt = true;
497
        }
498
    }
499
500
    /**
501
     * Sets the initialization vector. (optional)
502
     *
503
     * SetIV is not required when self::MODE_ECB (or ie for AES: \phpseclib\Crypt\AES::MODE_ECB) is being used.  If not explicitly set, it'll be assumed
504
     * to be all zero's.
505
     *
506
     * @access public
507
     * @param string $iv
508
     * @internal Can be overwritten by a sub class, but does not have to be
509
     */
510
    public function setIV($iv)
511
    {
512
        if ($this->mode == self::MODE_ECB) {
513
            return;
514
        }
515
516
        $this->iv = $iv;
517
        $this->changed = true;
518
    }
519
520
    /**
521
     * Sets the key length.
522
     *
523
     * Keys with explicitly set lengths need to be treated accordingly
524
     *
525
     * @access public
526
     * @param int $length
527
     */
528
    public function setKeyLength($length)
0 ignored issues
show
The parameter $length is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

528
    public function setKeyLength(/** @scrutinizer ignore-unused */ $length)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
529
    {
530
        $this->explicit_key_length = true;
531
        $this->changed = true;
532
        $this->_setEngine();
533
    }
534
535
    /**
536
     * Returns the current key length in bits
537
     *
538
     * @access public
539
     * @return int
540
     */
541
    public function getKeyLength()
542
    {
543
        return $this->key_length << 3;
544
    }
545
546
    /**
547
     * Returns the current block length in bits
548
     *
549
     * @access public
550
     * @return int
551
     */
552
    public function getBlockLength()
553
    {
554
        return $this->block_size << 3;
555
    }
556
557
    /**
558
     * Sets the key.
559
     *
560
     * The min/max length(s) of the key depends on the cipher which is used.
561
     * If the key not fits the length(s) of the cipher it will paded with null bytes
562
     * up to the closest valid key length.  If the key is more than max length,
563
     * we trim the excess bits.
564
     *
565
     * If the key is not explicitly set, it'll be assumed to be all null bytes.
566
     *
567
     * @access public
568
     * @param string $key
569
     * @internal Could, but not must, extend by the child Crypt_* class
570
     */
571
    public function setKey($key)
572
    {
573
        if (!$this->explicit_key_length) {
574
            $this->setKeyLength(strlen($key) << 3);
575
            $this->explicit_key_length = false;
576
        }
577
578
        $this->key = $key;
579
        $this->changed = true;
580
        $this->_setEngine();
581
    }
582
583
    /**
584
     * Sets the password.
585
     *
586
     * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
587
     *     {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
588
     *         $hash, $salt, $count, $dkLen
589
     *
590
     *         Where $hash (default = sha256) currently supports the following hashes: see: Crypt/Hash.php
591
     *
592
     * @see Crypt/Hash.php
593
     * @param string $password
594
     * @param string $method
595
     * @return bool
596
     * @access public
597
     * @internal Could, but not must, extend by the child Crypt_* class
598
     */
599
    public function setPassword($password, $method = 'pbkdf2')
600
    {
601
        $key = '';
602
603
        switch ($method) {
604
            default: // 'pbkdf2' or 'pbkdf1'
605
                $func_args = func_get_args();
606
607
                // Hash function
608
                $hash = isset($func_args[2]) ? $func_args[2] : 'sha256';
609
610
                // WPA and WPA2 use the SSID as the salt
611
                $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;
612
613
                // RFC2898#section-4.2 uses 1,000 iterations by default
614
                // WPA and WPA2 use 4,096.
615
                $count = isset($func_args[4]) ? $func_args[4] : 1000;
616
617
                // Keylength
618
                if (isset($func_args[5])) {
619
                    $dkLen = $func_args[5];
620
                } else {
621
                    $dkLen = $method == 'pbkdf1' ? 2 * $this->key_length : $this->key_length;
622
                }
623
624
                switch (true) {
625
                    case $method == 'pbkdf1':
626
                        $hashObj = new Hash();
627
                        $hashObj->setHash($hash);
628
                        if ($dkLen > $hashObj->getLength()) {
629
                            user_error('Derived key too long');
630
                            return false;
631
                        }
632
                        $t = $password . $salt;
633
                        for ($i = 0; $i < $count; ++$i) {
634
                            $t = $hashObj->hash($t);
635
                        }
636
                        $key = substr($t, 0, $dkLen);
637
638
                        $this->setKey(substr($key, 0, $dkLen >> 1));
639
                        $this->setIV(substr($key, $dkLen >> 1));
640
641
                        return true;
642
                    // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
643
                    case !function_exists('hash_pbkdf2'):
644
                    case !function_exists('hash_algos'):
645
                    case !in_array($hash, hash_algos()):
646
                        $i = 1;
647
                        while (strlen($key) < $dkLen) {
648
                            $hmac = new Hash();
649
                            $hmac->setHash($hash);
650
                            $hmac->setKey($password);
651
                            $f = $u = $hmac->hash($salt . pack('N', $i++));
652
                            for ($j = 2; $j <= $count; ++$j) {
653
                                $u = $hmac->hash($u);
654
                                $f^= $u;
655
                            }
656
                            $key.= $f;
657
                        }
658
                        $key = substr($key, 0, $dkLen);
659
                        break;
660
                    default:
661
                        $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
662
                }
663
        }
664
665
        $this->setKey($key);
666
667
        return true;
668
    }
669
670
    /**
671
     * Encrypts a message.
672
     *
673
     * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher
674
     * implementations may or may not pad in the same manner.  Other common approaches to padding and the reasons why it's
675
     * necessary are discussed in the following
676
     * URL:
677
     *
678
     * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
679
     *
680
     * An alternative to padding is to, separately, send the length of the file.  This is what SSH, in fact, does.
681
     * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that
682
     * length.
683
     *
684
     * @see self::decrypt()
685
     * @access public
686
     * @param string $plaintext
687
     * @return string $ciphertext
688
     * @internal Could, but not must, extend by the child Crypt_* class
689
     */
690
    public function encrypt($plaintext)
691
    {
692
        if ($this->paddable) {
693
            $plaintext = $this->_pad($plaintext);
694
        }
695
696
        if ($this->engine === self::ENGINE_OPENSSL) {
697
            if ($this->changed) {
698
                $this->_clearBuffers();
699
                $this->changed = false;
700
            }
701
            switch ($this->mode) {
702
                case self::MODE_STREAM:
703
                    return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
704
                case self::MODE_ECB:
705
                    $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
706
                    return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
707
                case self::MODE_CBC:
708
                    $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
709
                    if (!defined('OPENSSL_RAW_DATA')) {
710
                        $result = substr($result, 0, -$this->block_size);
711
                    }
712
                    if ($this->continuousBuffer) {
713
                        $this->encryptIV = substr($result, -$this->block_size);
714
                    }
715
                    return $result;
716
                case self::MODE_CTR:
717
                    return $this->_openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer);
718
                case self::MODE_CFB:
719
                    // cfb loosely routines inspired by openssl's:
720
                    // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
721
                    $ciphertext = '';
722
                    if ($this->continuousBuffer) {
723
                        $iv = &$this->encryptIV;
724
                        $pos = &$this->enbuffer['pos'];
725
                    } else {
726
                        $iv = $this->encryptIV;
727
                        $pos = 0;
728
                    }
729
                    $len = strlen($plaintext);
730
                    $i = 0;
731
                    if ($pos) {
732
                        $orig_pos = $pos;
733
                        $max = $this->block_size - $pos;
734
                        if ($len >= $max) {
735
                            $i = $max;
736
                            $len-= $max;
737
                            $pos = 0;
738
                        } else {
739
                            $i = $len;
740
                            $pos+= $len;
741
                            $len = 0;
742
                        }
743
                        // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
744
                        $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
745
                        $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
746
                        $plaintext = substr($plaintext, $i);
747
                    }
748
749
                    $overflow = $len % $this->block_size;
750
751
                    if ($overflow) {
752
                        $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
753
                        $iv = $this->_string_pop($ciphertext, $this->block_size);
754
755
                        $size = $len - $overflow;
0 ignored issues
show
The assignment to $size is dead and can be removed.
Loading history...
756
                        $block = $iv ^ substr($plaintext, -$overflow);
757
                        $iv = substr_replace($iv, $block, 0, $overflow);
758
                        $ciphertext.= $block;
759
                        $pos = $overflow;
760
                    } elseif ($len) {
761
                        $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
762
                        $iv = substr($ciphertext, -$this->block_size);
763
                    }
764
765
                    return $ciphertext;
766
                case self::MODE_OFB:
767
                    return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
768
            }
769
        }
770
771
        if ($this->engine === self::ENGINE_MCRYPT) {
772
            if ($this->changed) {
773
                $this->_setupMcrypt();
774
                $this->changed = false;
775
            }
776
            if ($this->enchanged) {
777
                @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_generic_init() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

777
                @/** @scrutinizer ignore-deprecated */ mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
778
                $this->enchanged = false;
779
            }
780
781
            // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
782
            // using mcrypt's default handing of CFB the above would output two different things.  using phpseclib's
783
            // rewritten CFB implementation the above outputs the same thing twice.
784
            if ($this->mode == self::MODE_CFB && $this->continuousBuffer) {
785
                $block_size = $this->block_size;
786
                $iv = &$this->encryptIV;
787
                $pos = &$this->enbuffer['pos'];
788
                $len = strlen($plaintext);
789
                $ciphertext = '';
790
                $i = 0;
791
                if ($pos) {
792
                    $orig_pos = $pos;
793
                    $max = $block_size - $pos;
794
                    if ($len >= $max) {
795
                        $i = $max;
796
                        $len-= $max;
797
                        $pos = 0;
798
                    } else {
799
                        $i = $len;
800
                        $pos+= $len;
801
                        $len = 0;
802
                    }
803
                    $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
804
                    $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
805
                    $this->enbuffer['enmcrypt_init'] = true;
806
                }
807
                if ($len >= $block_size) {
808
                    if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) {
809
                        if ($this->enbuffer['enmcrypt_init'] === true) {
810
                            @mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_generic_init() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

810
                            @/** @scrutinizer ignore-deprecated */ mcrypt_generic_init($this->enmcrypt, $this->key, $iv);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
811
                            $this->enbuffer['enmcrypt_init'] = false;
812
                        }
813
                        $ciphertext.= @mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_generic() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

813
                        $ciphertext.= @/** @scrutinizer ignore-deprecated */ mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
814
                        $iv = substr($ciphertext, -$block_size);
815
                        $len%= $block_size;
816
                    } else {
817
                        while ($len >= $block_size) {
818
                            $iv = @mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_generic() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

818
                            $iv = @/** @scrutinizer ignore-deprecated */ mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
819
                            $ciphertext.= $iv;
820
                            $len-= $block_size;
821
                            $i+= $block_size;
822
                        }
823
                    }
824
                }
825
826
                if ($len) {
827
                    $iv = @mcrypt_generic($this->ecb, $iv);
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_generic() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

827
                    $iv = @/** @scrutinizer ignore-deprecated */ mcrypt_generic($this->ecb, $iv);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
828
                    $block = $iv ^ substr($plaintext, -$len);
829
                    $iv = substr_replace($iv, $block, 0, $len);
830
                    $ciphertext.= $block;
831
                    $pos = $len;
832
                }
833
834
                return $ciphertext;
835
            }
836
837
            $ciphertext = @mcrypt_generic($this->enmcrypt, $plaintext);
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_generic() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

837
            $ciphertext = @/** @scrutinizer ignore-deprecated */ mcrypt_generic($this->enmcrypt, $plaintext);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
838
839
            if (!$this->continuousBuffer) {
840
                @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_generic_init() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

840
                @/** @scrutinizer ignore-deprecated */ mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
841
            }
842
843
            return $ciphertext;
844
        }
845
846
        if ($this->changed) {
847
            $this->_setup();
848
            $this->changed = false;
849
        }
850
        if ($this->use_inline_crypt) {
851
            $inline = $this->inline_crypt;
852
            return $inline('encrypt', $this, $plaintext);
853
        }
854
855
        $buffer = &$this->enbuffer;
856
        $block_size = $this->block_size;
857
        $ciphertext = '';
858
        switch ($this->mode) {
859
            case self::MODE_ECB:
860
                for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
861
                    $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
862
                }
863
                break;
864
            case self::MODE_CBC:
865
                $xor = $this->encryptIV;
866
                for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
867
                    $block = substr($plaintext, $i, $block_size);
868
                    $block = $this->_encryptBlock($block ^ $xor);
869
                    $xor = $block;
870
                    $ciphertext.= $block;
871
                }
872
                if ($this->continuousBuffer) {
873
                    $this->encryptIV = $xor;
874
                }
875
                break;
876
            case self::MODE_CTR:
877
                $xor = $this->encryptIV;
878
                if (strlen($buffer['ciphertext'])) {
879
                    for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
880
                        $block = substr($plaintext, $i, $block_size);
881
                        if (strlen($block) > strlen($buffer['ciphertext'])) {
882
                            $buffer['ciphertext'].= $this->_encryptBlock($xor);
883
                        }
884
                        $this->_increment_str($xor);
885
                        $key = $this->_string_shift($buffer['ciphertext'], $block_size);
886
                        $ciphertext.= $block ^ $key;
887
                    }
888
                } else {
889
                    for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
890
                        $block = substr($plaintext, $i, $block_size);
891
                        $key = $this->_encryptBlock($xor);
892
                        $this->_increment_str($xor);
893
                        $ciphertext.= $block ^ $key;
894
                    }
895
                }
896
                if ($this->continuousBuffer) {
897
                    $this->encryptIV = $xor;
898
                    if ($start = strlen($plaintext) % $block_size) {
899
                        $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $key does not seem to be defined for all execution paths leading up to this point.
Loading history...
900
                    }
901
                }
902
                break;
903
            case self::MODE_CFB:
904
                // cfb loosely routines inspired by openssl's:
905
                // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
906
                if ($this->continuousBuffer) {
907
                    $iv = &$this->encryptIV;
908
                    $pos = &$buffer['pos'];
909
                } else {
910
                    $iv = $this->encryptIV;
911
                    $pos = 0;
912
                }
913
                $len = strlen($plaintext);
914
                $i = 0;
915
                if ($pos) {
916
                    $orig_pos = $pos;
917
                    $max = $block_size - $pos;
918
                    if ($len >= $max) {
919
                        $i = $max;
920
                        $len-= $max;
921
                        $pos = 0;
922
                    } else {
923
                        $i = $len;
924
                        $pos+= $len;
925
                        $len = 0;
926
                    }
927
                    // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
928
                    $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
929
                    $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
930
                }
931
                while ($len >= $block_size) {
932
                    $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
933
                    $ciphertext.= $iv;
934
                    $len-= $block_size;
935
                    $i+= $block_size;
936
                }
937
                if ($len) {
938
                    $iv = $this->_encryptBlock($iv);
939
                    $block = $iv ^ substr($plaintext, $i);
940
                    $iv = substr_replace($iv, $block, 0, $len);
941
                    $ciphertext.= $block;
942
                    $pos = $len;
943
                }
944
                break;
945
            case self::MODE_OFB:
946
                $xor = $this->encryptIV;
947
                if (strlen($buffer['xor'])) {
948
                    for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
949
                        $block = substr($plaintext, $i, $block_size);
950
                        if (strlen($block) > strlen($buffer['xor'])) {
951
                            $xor = $this->_encryptBlock($xor);
952
                            $buffer['xor'].= $xor;
953
                        }
954
                        $key = $this->_string_shift($buffer['xor'], $block_size);
955
                        $ciphertext.= $block ^ $key;
956
                    }
957
                } else {
958
                    for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
959
                        $xor = $this->_encryptBlock($xor);
960
                        $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
961
                    }
962
                    $key = $xor;
963
                }
964
                if ($this->continuousBuffer) {
965
                    $this->encryptIV = $xor;
966
                    if ($start = strlen($plaintext) % $block_size) {
967
                        $buffer['xor'] = substr($key, $start) . $buffer['xor'];
968
                    }
969
                }
970
                break;
971
            case self::MODE_STREAM:
972
                $ciphertext = $this->_encryptBlock($plaintext);
973
                break;
974
        }
975
976
        return $ciphertext;
977
    }
978
979
    /**
980
     * Decrypts a message.
981
     *
982
     * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
983
     * it is.
984
     *
985
     * @see self::encrypt()
986
     * @access public
987
     * @param string $ciphertext
988
     * @return string $plaintext
989
     * @internal Could, but not must, extend by the child Crypt_* class
990
     */
991
    public function decrypt($ciphertext)
992
    {
993
        if ($this->paddable) {
994
            // we pad with chr(0) since that's what mcrypt_generic does.  to quote from {@link http://www.php.net/function.mcrypt-generic}:
995
            // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
996
            $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
997
        }
998
999
        if ($this->engine === self::ENGINE_OPENSSL) {
1000
            if ($this->changed) {
1001
                $this->_clearBuffers();
1002
                $this->changed = false;
1003
            }
1004
            switch ($this->mode) {
1005
                case self::MODE_STREAM:
1006
                    $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1007
                    break;
1008
                case self::MODE_ECB:
1009
                    if (!defined('OPENSSL_RAW_DATA')) {
1010
                        $ciphertext.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true);
0 ignored issues
show
true of type true is incompatible with the type integer expected by parameter $options of openssl_encrypt(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1010
                        $ciphertext.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, /** @scrutinizer ignore-type */ true);
Loading history...
1011
                    }
1012
                    $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1013
                    break;
1014
                case self::MODE_CBC:
1015
                    if (!defined('OPENSSL_RAW_DATA')) {
1016
                        $padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size);
1017
                        $ciphertext.= substr(openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size);
1018
                        $offset = 2 * $this->block_size;
1019
                    } else {
1020
                        $offset = $this->block_size;
1021
                    }
1022
                    $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV);
1023
                    if ($this->continuousBuffer) {
1024
                        $this->decryptIV = substr($ciphertext, -$offset, $this->block_size);
1025
                    }
1026
                    break;
1027
                case self::MODE_CTR:
1028
                    $plaintext = $this->_openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer);
1029
                    break;
1030
                case self::MODE_CFB:
1031
                    // cfb loosely routines inspired by openssl's:
1032
                    // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
1033
                    $plaintext = '';
1034
                    if ($this->continuousBuffer) {
1035
                        $iv = &$this->decryptIV;
1036
                        $pos = &$this->buffer['pos'];
1037
                    } else {
1038
                        $iv = $this->decryptIV;
1039
                        $pos = 0;
1040
                    }
1041
                    $len = strlen($ciphertext);
1042
                    $i = 0;
1043
                    if ($pos) {
1044
                        $orig_pos = $pos;
1045
                        $max = $this->block_size - $pos;
1046
                        if ($len >= $max) {
1047
                            $i = $max;
1048
                            $len-= $max;
1049
                            $pos = 0;
1050
                        } else {
1051
                            $i = $len;
1052
                            $pos+= $len;
1053
                            $len = 0;
1054
                        }
1055
                        // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $this->blocksize
1056
                        $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1057
                        $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1058
                        $ciphertext = substr($ciphertext, $i);
1059
                    }
1060
                    $overflow = $len % $this->block_size;
1061
                    if ($overflow) {
1062
                        $plaintext.= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1063
                        if ($len - $overflow) {
1064
                            $iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow);
1065
                        }
1066
                        $iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1067
                        $plaintext.= $iv ^ substr($ciphertext, -$overflow);
1068
                        $iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow);
1069
                        $pos = $overflow;
1070
                    } elseif ($len) {
1071
                        $plaintext.= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1072
                        $iv = substr($ciphertext, -$this->block_size);
1073
                    }
1074
                    break;
1075
                case self::MODE_OFB:
1076
                    $plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
1077
            }
1078
1079
            return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $plaintext does not seem to be defined for all execution paths leading up to this point.
Loading history...
1080
        }
1081
1082
        if ($this->engine === self::ENGINE_MCRYPT) {
1083
            $block_size = $this->block_size;
1084
            if ($this->changed) {
1085
                $this->_setupMcrypt();
1086
                $this->changed = false;
1087
            }
1088
            if ($this->dechanged) {
1089
                @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_generic_init() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1089
                @/** @scrutinizer ignore-deprecated */ mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1090
                $this->dechanged = false;
1091
            }
1092
1093
            if ($this->mode == self::MODE_CFB && $this->continuousBuffer) {
1094
                $iv = &$this->decryptIV;
1095
                $pos = &$this->debuffer['pos'];
1096
                $len = strlen($ciphertext);
1097
                $plaintext = '';
1098
                $i = 0;
1099
                if ($pos) {
1100
                    $orig_pos = $pos;
1101
                    $max = $block_size - $pos;
1102
                    if ($len >= $max) {
1103
                        $i = $max;
1104
                        $len-= $max;
1105
                        $pos = 0;
1106
                    } else {
1107
                        $i = $len;
1108
                        $pos+= $len;
1109
                        $len = 0;
1110
                    }
1111
                    // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1112
                    $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1113
                    $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1114
                }
1115
                if ($len >= $block_size) {
1116
                    $cb = substr($ciphertext, $i, $len - $len % $block_size);
1117
                    $plaintext.= @mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_generic() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1117
                    $plaintext.= @/** @scrutinizer ignore-deprecated */ mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1118
                    $iv = substr($cb, -$block_size);
1119
                    $len%= $block_size;
1120
                }
1121
                if ($len) {
1122
                    $iv = @mcrypt_generic($this->ecb, $iv);
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_generic() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1122
                    $iv = @/** @scrutinizer ignore-deprecated */ mcrypt_generic($this->ecb, $iv);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1123
                    $plaintext.= $iv ^ substr($ciphertext, -$len);
1124
                    $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
1125
                    $pos = $len;
1126
                }
1127
1128
                return $plaintext;
1129
            }
1130
1131
            $plaintext = @mdecrypt_generic($this->demcrypt, $ciphertext);
0 ignored issues
show
Deprecated Code introduced by
The function mdecrypt_generic() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1131
            $plaintext = @/** @scrutinizer ignore-deprecated */ mdecrypt_generic($this->demcrypt, $ciphertext);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1132
1133
            if (!$this->continuousBuffer) {
1134
                @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_generic_init() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1134
                @/** @scrutinizer ignore-deprecated */ mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1135
            }
1136
1137
            return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1138
        }
1139
1140
        if ($this->changed) {
1141
            $this->_setup();
1142
            $this->changed = false;
1143
        }
1144
        if ($this->use_inline_crypt) {
1145
            $inline = $this->inline_crypt;
1146
            return $inline('decrypt', $this, $ciphertext);
1147
        }
1148
1149
        $block_size = $this->block_size;
1150
1151
        $buffer = &$this->debuffer;
1152
        $plaintext = '';
1153
        switch ($this->mode) {
1154
            case self::MODE_ECB:
1155
                for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1156
                    $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
1157
                }
1158
                break;
1159
            case self::MODE_CBC:
1160
                $xor = $this->decryptIV;
1161
                for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1162
                    $block = substr($ciphertext, $i, $block_size);
1163
                    $plaintext.= $this->_decryptBlock($block) ^ $xor;
1164
                    $xor = $block;
1165
                }
1166
                if ($this->continuousBuffer) {
1167
                    $this->decryptIV = $xor;
1168
                }
1169
                break;
1170
            case self::MODE_CTR:
1171
                $xor = $this->decryptIV;
1172
                if (strlen($buffer['ciphertext'])) {
1173
                    for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1174
                        $block = substr($ciphertext, $i, $block_size);
1175
                        if (strlen($block) > strlen($buffer['ciphertext'])) {
1176
                            $buffer['ciphertext'].= $this->_encryptBlock($xor);
1177
                            $this->_increment_str($xor);
1178
                        }
1179
                        $key = $this->_string_shift($buffer['ciphertext'], $block_size);
1180
                        $plaintext.= $block ^ $key;
1181
                    }
1182
                } else {
1183
                    for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1184
                        $block = substr($ciphertext, $i, $block_size);
1185
                        $key = $this->_encryptBlock($xor);
1186
                        $this->_increment_str($xor);
1187
                        $plaintext.= $block ^ $key;
1188
                    }
1189
                }
1190
                if ($this->continuousBuffer) {
1191
                    $this->decryptIV = $xor;
1192
                    if ($start = strlen($ciphertext) % $block_size) {
1193
                        $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $key does not seem to be defined for all execution paths leading up to this point.
Loading history...
1194
                    }
1195
                }
1196
                break;
1197
            case self::MODE_CFB:
1198
                if ($this->continuousBuffer) {
1199
                    $iv = &$this->decryptIV;
1200
                    $pos = &$buffer['pos'];
1201
                } else {
1202
                    $iv = $this->decryptIV;
1203
                    $pos = 0;
1204
                }
1205
                $len = strlen($ciphertext);
1206
                $i = 0;
1207
                if ($pos) {
1208
                    $orig_pos = $pos;
1209
                    $max = $block_size - $pos;
1210
                    if ($len >= $max) {
1211
                        $i = $max;
1212
                        $len-= $max;
1213
                        $pos = 0;
1214
                    } else {
1215
                        $i = $len;
1216
                        $pos+= $len;
1217
                        $len = 0;
1218
                    }
1219
                    // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1220
                    $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1221
                    $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1222
                }
1223
                while ($len >= $block_size) {
1224
                    $iv = $this->_encryptBlock($iv);
1225
                    $cb = substr($ciphertext, $i, $block_size);
1226
                    $plaintext.= $iv ^ $cb;
1227
                    $iv = $cb;
1228
                    $len-= $block_size;
1229
                    $i+= $block_size;
1230
                }
1231
                if ($len) {
1232
                    $iv = $this->_encryptBlock($iv);
1233
                    $plaintext.= $iv ^ substr($ciphertext, $i);
1234
                    $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
1235
                    $pos = $len;
1236
                }
1237
                break;
1238
            case self::MODE_OFB:
1239
                $xor = $this->decryptIV;
1240
                if (strlen($buffer['xor'])) {
1241
                    for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1242
                        $block = substr($ciphertext, $i, $block_size);
1243
                        if (strlen($block) > strlen($buffer['xor'])) {
1244
                            $xor = $this->_encryptBlock($xor);
1245
                            $buffer['xor'].= $xor;
1246
                        }
1247
                        $key = $this->_string_shift($buffer['xor'], $block_size);
1248
                        $plaintext.= $block ^ $key;
1249
                    }
1250
                } else {
1251
                    for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1252
                        $xor = $this->_encryptBlock($xor);
1253
                        $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
1254
                    }
1255
                    $key = $xor;
1256
                }
1257
                if ($this->continuousBuffer) {
1258
                    $this->decryptIV = $xor;
1259
                    if ($start = strlen($ciphertext) % $block_size) {
1260
                        $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1261
                    }
1262
                }
1263
                break;
1264
            case self::MODE_STREAM:
1265
                $plaintext = $this->_decryptBlock($ciphertext);
1266
                break;
1267
        }
1268
        return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1269
    }
1270
1271
    /**
1272
     * OpenSSL CTR Processor
1273
     *
1274
     * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1275
     * for CTR is the same for both encrypting and decrypting this function is re-used by both Base::encrypt()
1276
     * and Base::decrypt(). Also, OpenSSL doesn't implement CTR for all of it's symmetric ciphers so this
1277
     * function will emulate CTR with ECB when necessary.
1278
     *
1279
     * @see self::encrypt()
1280
     * @see self::decrypt()
1281
     * @param string $plaintext
1282
     * @param string $encryptIV
1283
     * @param array $buffer
1284
     * @return string
1285
     * @access private
1286
     */
1287
    public function _openssl_ctr_process($plaintext, &$encryptIV, &$buffer)
1288
    {
1289
        $ciphertext = '';
1290
1291
        $block_size = $this->block_size;
1292
        $key = $this->key;
1293
1294
        if ($this->openssl_emulate_ctr) {
1295
            $xor = $encryptIV;
1296
            if (strlen($buffer['ciphertext'])) {
1297
                for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1298
                    $block = substr($plaintext, $i, $block_size);
1299
                    if (strlen($block) > strlen($buffer['ciphertext'])) {
1300
                        $result = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1301
                        $result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
1302
                        $buffer['ciphertext'].= $result;
1303
                    }
1304
                    $this->_increment_str($xor);
1305
                    $otp = $this->_string_shift($buffer['ciphertext'], $block_size);
1306
                    $ciphertext.= $block ^ $otp;
1307
                }
1308
            } else {
1309
                for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1310
                    $block = substr($plaintext, $i, $block_size);
1311
                    $otp = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1312
                    $otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp;
1313
                    $this->_increment_str($xor);
1314
                    $ciphertext.= $block ^ $otp;
1315
                }
1316
            }
1317
            if ($this->continuousBuffer) {
1318
                $encryptIV = $xor;
1319
                if ($start = strlen($plaintext) % $block_size) {
1320
                    $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1321
                }
1322
            }
1323
1324
            return $ciphertext;
1325
        }
1326
1327
        if (strlen($buffer['ciphertext'])) {
1328
            $ciphertext = $plaintext ^ $this->_string_shift($buffer['ciphertext'], strlen($plaintext));
1329
            $plaintext = substr($plaintext, strlen($ciphertext));
1330
1331
            if (!strlen($plaintext)) {
1332
                return $ciphertext;
1333
            }
1334
        }
1335
1336
        $overflow = strlen($plaintext) % $block_size;
1337
        if ($overflow) {
1338
            $plaintext2 = $this->_string_pop($plaintext, $overflow); // ie. trim $plaintext to a multiple of $block_size and put rest of $plaintext in $plaintext2
1339
            $encrypted = openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1340
            $temp = $this->_string_pop($encrypted, $block_size);
1341
            $ciphertext.= $encrypted . ($plaintext2 ^ $temp);
1342
            if ($this->continuousBuffer) {
1343
                $buffer['ciphertext'] = substr($temp, $overflow);
1344
                $encryptIV = $temp;
1345
            }
1346
        } elseif (!strlen($buffer['ciphertext'])) {
1347
            $ciphertext.= openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1348
            $temp = $this->_string_pop($ciphertext, $block_size);
1349
            if ($this->continuousBuffer) {
1350
                $encryptIV = $temp;
1351
            }
1352
        }
1353
        if ($this->continuousBuffer) {
1354
            if (!defined('OPENSSL_RAW_DATA')) {
1355
                $encryptIV.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1356
            }
1357
            $encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1358
            if ($overflow) {
1359
                $this->_increment_str($encryptIV);
1360
            }
1361
        }
1362
1363
        return $ciphertext;
1364
    }
1365
1366
    /**
1367
     * OpenSSL OFB Processor
1368
     *
1369
     * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1370
     * for OFB is the same for both encrypting and decrypting this function is re-used by both Base::encrypt()
1371
     * and Base::decrypt().
1372
     *
1373
     * @see self::encrypt()
1374
     * @see self::decrypt()
1375
     * @param string $plaintext
1376
     * @param string $encryptIV
1377
     * @param array $buffer
1378
     * @return string
1379
     * @access private
1380
     */
1381
    public function _openssl_ofb_process($plaintext, &$encryptIV, &$buffer)
1382
    {
1383
        if (strlen($buffer['xor'])) {
1384
            $ciphertext = $plaintext ^ $buffer['xor'];
1385
            $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
1386
            $plaintext = substr($plaintext, strlen($ciphertext));
1387
        } else {
1388
            $ciphertext = '';
1389
        }
1390
1391
        $block_size = $this->block_size;
1392
1393
        $len = strlen($plaintext);
1394
        $key = $this->key;
1395
        $overflow = $len % $block_size;
1396
1397
        if (strlen($plaintext)) {
1398
            if ($overflow) {
1399
                $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1400
                $xor = $this->_string_pop($ciphertext, $block_size);
1401
                if ($this->continuousBuffer) {
1402
                    $encryptIV = $xor;
1403
                }
1404
                $ciphertext.= $this->_string_shift($xor, $overflow) ^ substr($plaintext, -$overflow);
1405
                if ($this->continuousBuffer) {
1406
                    $buffer['xor'] = $xor;
1407
                }
1408
            } else {
1409
                $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1410
                if ($this->continuousBuffer) {
1411
                    $encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size);
1412
                }
1413
            }
1414
        }
1415
1416
        return $ciphertext;
1417
    }
1418
1419
    /**
1420
     * phpseclib <-> OpenSSL Mode Mapper
1421
     *
1422
     * May need to be overwritten by classes extending this one in some cases
1423
     *
1424
     * @return int
1425
     * @access private
1426
     */
1427
    public function _openssl_translate_mode()
1428
    {
1429
        switch ($this->mode) {
1430
            case self::MODE_ECB:
1431
                return 'ecb';
1432
            case self::MODE_CBC:
1433
                return 'cbc';
1434
            case self::MODE_CTR:
1435
                return 'ctr';
1436
            case self::MODE_CFB:
1437
                return 'cfb';
1438
            case self::MODE_OFB:
1439
                return 'ofb';
1440
        }
1441
    }
1442
1443
    /**
1444
     * Pad "packets".
1445
     *
1446
     * Block ciphers working by encrypting between their specified [$this->]block_size at a time
1447
     * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
1448
     * pad the input so that it is of the proper length.
1449
     *
1450
     * Padding is enabled by default.  Sometimes, however, it is undesirable to pad strings.  Such is the case in SSH,
1451
     * where "packets" are padded with random bytes before being encrypted.  Unpad these packets and you risk stripping
1452
     * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1453
     * transmitted separately)
1454
     *
1455
     * @see self::disablePadding()
1456
     * @access public
1457
     */
1458
    public function enablePadding()
1459
    {
1460
        $this->padding = true;
1461
    }
1462
1463
    /**
1464
     * Do not pad packets.
1465
     *
1466
     * @see self::enablePadding()
1467
     * @access public
1468
     */
1469
    public function disablePadding()
1470
    {
1471
        $this->padding = false;
1472
    }
1473
1474
    /**
1475
     * Treat consecutive "packets" as if they are a continuous buffer.
1476
     *
1477
     * Say you have a 32-byte plaintext $plaintext.  Using the default behavior, the two following code snippets
1478
     * will yield different outputs:
1479
     *
1480
     * <code>
1481
     *    echo $rijndael->encrypt(substr($plaintext,  0, 16));
1482
     *    echo $rijndael->encrypt(substr($plaintext, 16, 16));
1483
     * </code>
1484
     * <code>
1485
     *    echo $rijndael->encrypt($plaintext);
1486
     * </code>
1487
     *
1488
     * The solution is to enable the continuous buffer.  Although this will resolve the above discrepancy, it creates
1489
     * another, as demonstrated with the following:
1490
     *
1491
     * <code>
1492
     *    $rijndael->encrypt(substr($plaintext, 0, 16));
1493
     *    echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1494
     * </code>
1495
     * <code>
1496
     *    echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1497
     * </code>
1498
     *
1499
     * With the continuous buffer disabled, these would yield the same output.  With it enabled, they yield different
1500
     * outputs.  The reason is due to the fact that the initialization vector's change after every encryption /
1501
     * decryption round when the continuous buffer is enabled.  When it's disabled, they remain constant.
1502
     *
1503
     * Put another way, when the continuous buffer is enabled, the state of the \phpseclib\Crypt\*() object changes after each
1504
     * encryption / decryption round, whereas otherwise, it'd remain constant.  For this reason, it's recommended that
1505
     * continuous buffers not be used.  They do offer better security and are, in fact, sometimes required (SSH uses them),
1506
     * however, they are also less intuitive and more likely to cause you problems.
1507
     *
1508
     * @see self::disableContinuousBuffer()
1509
     * @access public
1510
     * @internal Could, but not must, extend by the child Crypt_* class
1511
     */
1512
    public function enableContinuousBuffer()
1513
    {
1514
        if ($this->mode == self::MODE_ECB) {
1515
            return;
1516
        }
1517
1518
        $this->continuousBuffer = true;
1519
1520
        $this->_setEngine();
1521
    }
1522
1523
    /**
1524
     * Treat consecutive packets as if they are a discontinuous buffer.
1525
     *
1526
     * The default behavior.
1527
     *
1528
     * @see self::enableContinuousBuffer()
1529
     * @access public
1530
     * @internal Could, but not must, extend by the child Crypt_* class
1531
     */
1532
    public function disableContinuousBuffer()
1533
    {
1534
        if ($this->mode == self::MODE_ECB) {
1535
            return;
1536
        }
1537
        if (!$this->continuousBuffer) {
1538
            return;
1539
        }
1540
1541
        $this->continuousBuffer = false;
1542
        $this->changed = true;
1543
1544
        $this->_setEngine();
1545
    }
1546
1547
    /**
1548
     * Test for engine validity
1549
     *
1550
     * @see self::__construct()
1551
     * @param int $engine
1552
     * @access public
1553
     * @return bool
1554
     */
1555
    public function isValidEngine($engine)
1556
    {
1557
        switch ($engine) {
1558
            case self::ENGINE_OPENSSL:
1559
                if ($this->mode == self::MODE_STREAM && $this->continuousBuffer) {
1560
                    return false;
1561
                }
1562
                $this->openssl_emulate_ctr = false;
1563
                $result = $this->cipher_name_openssl &&
1564
                          extension_loaded('openssl') &&
1565
                          // PHP 5.3.0 - 5.3.2 did not let you set IV's
1566
                          version_compare(PHP_VERSION, '5.3.3', '>=');
1567
                if (!$result) {
1568
                    return false;
1569
                }
1570
1571
                // prior to PHP 5.4.0 OPENSSL_RAW_DATA and OPENSSL_ZERO_PADDING were not defined. instead of expecting an integer
1572
                // $options openssl_encrypt expected a boolean $raw_data.
1573
                if (!defined('OPENSSL_RAW_DATA')) {
1574
                    $this->openssl_options = true;
1575
                } else {
1576
                    $this->openssl_options = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;
1577
                }
1578
1579
                $methods = openssl_get_cipher_methods();
1580
                if (in_array($this->cipher_name_openssl, $methods)) {
1581
                    return true;
1582
                }
1583
                // not all of openssl's symmetric cipher's support ctr. for those
1584
                // that don't we'll emulate it
1585
                switch ($this->mode) {
1586
                    case self::MODE_CTR:
1587
                        if (in_array($this->cipher_name_openssl_ecb, $methods)) {
1588
                            $this->openssl_emulate_ctr = true;
1589
                            return true;
1590
                        }
1591
                }
1592
                return false;
1593
            case self::ENGINE_MCRYPT:
1594
                return $this->cipher_name_mcrypt &&
1595
                       extension_loaded('mcrypt') &&
1596
                       in_array($this->cipher_name_mcrypt, @mcrypt_list_algorithms());
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_list_algorithms() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1596
                       in_array($this->cipher_name_mcrypt, @/** @scrutinizer ignore-deprecated */ mcrypt_list_algorithms());

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1597
            case self::ENGINE_INTERNAL:
1598
                return true;
1599
        }
1600
1601
        return false;
1602
    }
1603
1604
    /**
1605
     * Sets the preferred crypt engine
1606
     *
1607
     * Currently, $engine could be:
1608
     *
1609
     * - \phpseclib\Crypt\Base::ENGINE_OPENSSL  [very fast]
1610
     *
1611
     * - \phpseclib\Crypt\Base::ENGINE_MCRYPT   [fast]
1612
     *
1613
     * - \phpseclib\Crypt\Base::ENGINE_INTERNAL [slow]
1614
     *
1615
     * If the preferred crypt engine is not available the fastest available one will be used
1616
     *
1617
     * @see self::__construct()
1618
     * @param int $engine
1619
     * @access public
1620
     */
1621
    public function setPreferredEngine($engine)
1622
    {
1623
        switch ($engine) {
1624
            //case self::ENGINE_OPENSSL;
1625
            case self::ENGINE_MCRYPT:
1626
            case self::ENGINE_INTERNAL:
1627
                $this->preferredEngine = $engine;
1628
                break;
1629
            default:
1630
                $this->preferredEngine = self::ENGINE_OPENSSL;
1631
        }
1632
1633
        $this->_setEngine();
1634
    }
1635
1636
    /**
1637
     * Returns the engine currently being utilized
1638
     *
1639
     * @see self::_setEngine()
1640
     * @access public
1641
     */
1642
    public function getEngine()
1643
    {
1644
        return $this->engine;
1645
    }
1646
1647
    /**
1648
     * Sets the engine as appropriate
1649
     *
1650
     * @see self::__construct()
1651
     * @access private
1652
     */
1653
    public function _setEngine()
1654
    {
1655
        $this->engine = null;
1656
1657
        $candidateEngines = array(
1658
            $this->preferredEngine,
1659
            self::ENGINE_OPENSSL,
1660
            self::ENGINE_MCRYPT
1661
        );
1662
        foreach ($candidateEngines as $engine) {
1663
            if ($this->isValidEngine($engine)) {
1664
                $this->engine = $engine;
1665
                break;
1666
            }
1667
        }
1668
        if (!$this->engine) {
1669
            $this->engine = self::ENGINE_INTERNAL;
1670
        }
1671
1672
        if ($this->engine != self::ENGINE_MCRYPT && $this->enmcrypt) {
1673
            // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed,
1674
            // (re)open them with the module named in $this->cipher_name_mcrypt
1675
            @mcrypt_module_close($this->enmcrypt);
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_module_close() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1675
            @/** @scrutinizer ignore-deprecated */ mcrypt_module_close($this->enmcrypt);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1676
            @mcrypt_module_close($this->demcrypt);
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_module_close() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1676
            @/** @scrutinizer ignore-deprecated */ mcrypt_module_close($this->demcrypt);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1677
            $this->enmcrypt = null;
1678
            $this->demcrypt = null;
1679
1680
            if ($this->ecb) {
1681
                @mcrypt_module_close($this->ecb);
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_module_close() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1681
                @/** @scrutinizer ignore-deprecated */ mcrypt_module_close($this->ecb);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1682
                $this->ecb = null;
1683
            }
1684
        }
1685
1686
        $this->changed = true;
1687
    }
1688
1689
    /**
1690
     * Encrypts a block
1691
     *
1692
     * Note: Must be extended by the child \phpseclib\Crypt\* class
1693
     *
1694
     * @access private
1695
     * @param string $in
1696
     * @return string
1697
     */
1698
    abstract public function _encryptBlock($in);
1699
1700
    /**
1701
     * Decrypts a block
1702
     *
1703
     * Note: Must be extended by the child \phpseclib\Crypt\* class
1704
     *
1705
     * @access private
1706
     * @param string $in
1707
     * @return string
1708
     */
1709
    abstract public function _decryptBlock($in);
1710
1711
    /**
1712
     * Setup the key (expansion)
1713
     *
1714
     * Only used if $engine == self::ENGINE_INTERNAL
1715
     *
1716
     * Note: Must extend by the child \phpseclib\Crypt\* class
1717
     *
1718
     * @see self::_setup()
1719
     * @access private
1720
     */
1721
    abstract public function _setupKey();
1722
1723
    /**
1724
     * Setup the self::ENGINE_INTERNAL $engine
1725
     *
1726
     * (re)init, if necessary, the internal cipher $engine and flush all $buffers
1727
     * Used (only) if $engine == self::ENGINE_INTERNAL
1728
     *
1729
     * _setup() will be called each time if $changed === true
1730
     * typically this happens when using one or more of following public methods:
1731
     *
1732
     * - setKey()
1733
     *
1734
     * - setIV()
1735
     *
1736
     * - disableContinuousBuffer()
1737
     *
1738
     * - First run of encrypt() / decrypt() with no init-settings
1739
     *
1740
     * @see self::setKey()
1741
     * @see self::setIV()
1742
     * @see self::disableContinuousBuffer()
1743
     * @access private
1744
     * @internal _setup() is always called before en/decryption.
1745
     * @internal Could, but not must, extend by the child Crypt_* class
1746
     */
1747
    public function _setup()
1748
    {
1749
        $this->_clearBuffers();
1750
        $this->_setupKey();
1751
1752
        if ($this->use_inline_crypt) {
1753
            $this->_setupInlineCrypt();
1754
        }
1755
    }
1756
1757
    /**
1758
     * Setup the self::ENGINE_MCRYPT $engine
1759
     *
1760
     * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers
1761
     * Used (only) if $engine = self::ENGINE_MCRYPT
1762
     *
1763
     * _setupMcrypt() will be called each time if $changed === true
1764
     * typically this happens when using one or more of following public methods:
1765
     *
1766
     * - setKey()
1767
     *
1768
     * - setIV()
1769
     *
1770
     * - disableContinuousBuffer()
1771
     *
1772
     * - First run of encrypt() / decrypt()
1773
     *
1774
     * @see self::setKey()
1775
     * @see self::setIV()
1776
     * @see self::disableContinuousBuffer()
1777
     * @access private
1778
     * @internal Could, but not must, extend by the child Crypt_* class
1779
     */
1780
    public function _setupMcrypt()
1781
    {
1782
        $this->_clearBuffers();
1783
        $this->enchanged = $this->dechanged = true;
1784
1785
        if (!isset($this->enmcrypt)) {
1786
            static $mcrypt_modes = array(
1787
                self::MODE_CTR    => 'ctr',
1788
                self::MODE_ECB    => MCRYPT_MODE_ECB,
1789
                self::MODE_CBC    => MCRYPT_MODE_CBC,
1790
                self::MODE_CFB    => 'ncfb',
1791
                self::MODE_OFB    => MCRYPT_MODE_NOFB,
1792
                self::MODE_STREAM => MCRYPT_MODE_STREAM,
1793
            );
1794
1795
            $this->demcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_module_open() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1795
            $this->demcrypt = @/** @scrutinizer ignore-deprecated */ mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1796
            $this->enmcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_module_open() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1796
            $this->enmcrypt = @/** @scrutinizer ignore-deprecated */ mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1797
1798
            // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer()
1799
            // to workaround mcrypt's broken ncfb implementation in buffered mode
1800
            // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
1801
            if ($this->mode == self::MODE_CFB) {
1802
                $this->ecb = @mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_module_open() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1802
                $this->ecb = @/** @scrutinizer ignore-deprecated */ mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1803
            }
1804
        } // else should mcrypt_generic_deinit be called?
1805
1806
        if ($this->mode == self::MODE_CFB) {
1807
            @mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_generic_init() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1807
            @/** @scrutinizer ignore-deprecated */ mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1808
        }
1809
    }
1810
1811
    /**
1812
     * Pads a string
1813
     *
1814
     * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
1815
     * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to
1816
     * chr($this->block_size - (strlen($text) % $this->block_size)
1817
     *
1818
     * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1819
     * and padding will, hence forth, be enabled.
1820
     *
1821
     * @see self::_unpad()
1822
     * @param string $text
1823
     * @access private
1824
     * @return string
1825
     */
1826
    public function _pad($text)
1827
    {
1828
        $length = strlen($text);
1829
1830
        if (!$this->padding) {
1831
            if ($length % $this->block_size == 0) {
1832
                return $text;
1833
            } else {
1834
                user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
1835
                $this->padding = true;
1836
            }
1837
        }
1838
1839
        $pad = $this->block_size - ($length % $this->block_size);
1840
1841
        return str_pad($text, $length + $pad, chr($pad));
1842
    }
1843
1844
    /**
1845
     * Unpads a string.
1846
     *
1847
     * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1848
     * and false will be returned.
1849
     *
1850
     * @see self::_pad()
1851
     * @param string $text
1852
     * @access private
1853
     * @return string
1854
     */
1855
    public function _unpad($text)
1856
    {
1857
        if (!$this->padding) {
1858
            return $text;
1859
        }
1860
1861
        $length = ord($text[strlen($text) - 1]);
1862
1863
        if (!$length || $length > $this->block_size) {
1864
            return false;
1865
        }
1866
1867
        return substr($text, 0, -$length);
1868
    }
1869
1870
    /**
1871
     * Clears internal buffers
1872
     *
1873
     * Clearing/resetting the internal buffers is done everytime
1874
     * after disableContinuousBuffer() or on cipher $engine (re)init
1875
     * ie after setKey() or setIV()
1876
     *
1877
     * @access public
1878
     * @internal Could, but not must, extend by the child Crypt_* class
1879
     */
1880
    public function _clearBuffers()
1881
    {
1882
        $this->enbuffer = $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
1883
1884
        // mcrypt's handling of invalid's $iv:
1885
        // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size);
1886
        $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");
1887
1888
        if (!$this->skip_key_adjustment) {
1889
            $this->key = str_pad(substr($this->key, 0, $this->key_length), $this->key_length, "\0");
1890
        }
1891
    }
1892
1893
    /**
1894
     * String Shift
1895
     *
1896
     * Inspired by array_shift
1897
     *
1898
     * @param string $string
1899
     * @param int $index
1900
     * @access private
1901
     * @return string
1902
     */
1903
    public function _string_shift(&$string, $index = 1)
1904
    {
1905
        $substr = substr($string, 0, $index);
1906
        $string = substr($string, $index);
1907
        return $substr;
1908
    }
1909
1910
    /**
1911
     * String Pop
1912
     *
1913
     * Inspired by array_pop
1914
     *
1915
     * @param string $string
1916
     * @param int $index
1917
     * @access private
1918
     * @return string
1919
     */
1920
    public function _string_pop(&$string, $index = 1)
1921
    {
1922
        $substr = substr($string, -$index);
1923
        $string = substr($string, 0, -$index);
1924
        return $substr;
1925
    }
1926
1927
    /**
1928
     * Increment the current string
1929
     *
1930
     * @see self::decrypt()
1931
     * @see self::encrypt()
1932
     * @param string $var
1933
     * @access private
1934
     */
1935
    public function _increment_str(&$var)
1936
    {
1937
        for ($i = 4; $i <= strlen($var); $i+= 4) {
1938
            $temp = substr($var, -$i, 4);
1939
            switch ($temp) {
1940
                case "\xFF\xFF\xFF\xFF":
1941
                    $var = substr_replace($var, "\x00\x00\x00\x00", -$i, 4);
1942
                    break;
1943
                case "\x7F\xFF\xFF\xFF":
1944
                    $var = substr_replace($var, "\x80\x00\x00\x00", -$i, 4);
1945
                    return;
1946
                default:
1947
                    $temp = unpack('Nnum', $temp);
1948
                    $var = substr_replace($var, pack('N', $temp['num'] + 1), -$i, 4);
1949
                    return;
1950
            }
1951
        }
1952
1953
        $remainder = strlen($var) % 4;
1954
1955
        if ($remainder == 0) {
1956
            return;
1957
        }
1958
1959
        $temp = unpack('Nnum', str_pad(substr($var, 0, $remainder), 4, "\0", STR_PAD_LEFT));
1960
        $temp = substr(pack('N', $temp['num'] + 1), -$remainder);
1961
        $var = substr_replace($var, $temp, 0, $remainder);
1962
    }
1963
1964
    /**
1965
     * Setup the performance-optimized function for de/encrypt()
1966
     *
1967
     * Stores the created (or existing) callback function-name
1968
     * in $this->inline_crypt
1969
     *
1970
     * Internally for phpseclib developers:
1971
     *
1972
     *     _setupInlineCrypt() would be called only if:
1973
     *
1974
     *     - $engine == self::ENGINE_INTERNAL and
1975
     *
1976
     *     - $use_inline_crypt === true
1977
     *
1978
     *     - each time on _setup(), after(!) _setupKey()
1979
     *
1980
     *
1981
     *     This ensures that _setupInlineCrypt() has always a
1982
     *     full ready2go initializated internal cipher $engine state
1983
     *     where, for example, the keys allready expanded,
1984
     *     keys/block_size calculated and such.
1985
     *
1986
     *     It is, each time if called, the responsibility of _setupInlineCrypt():
1987
     *
1988
     *     - to set $this->inline_crypt to a valid and fully working callback function
1989
     *       as a (faster) replacement for encrypt() / decrypt()
1990
     *
1991
     *     - NOT to create unlimited callback functions (for memory reasons!)
1992
     *       no matter how often _setupInlineCrypt() would be called. At some
1993
     *       point of amount they must be generic re-useable.
1994
     *
1995
     *     - the code of _setupInlineCrypt() it self,
1996
     *       and the generated callback code,
1997
     *       must be, in following order:
1998
     *       - 100% safe
1999
     *       - 100% compatible to encrypt()/decrypt()
2000
     *       - using only php5+ features/lang-constructs/php-extensions if
2001
     *         compatibility (down to php4) or fallback is provided
2002
     *       - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-)
2003
     *       - >= 10% faster than encrypt()/decrypt() [which is, by the way,
2004
     *         the reason for the existence of _setupInlineCrypt() :-)]
2005
     *       - memory-nice
2006
     *       - short (as good as possible)
2007
     *
2008
     * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code.
2009
     *       - In case of using inline crypting, _setupInlineCrypt() must extend by the child \phpseclib\Crypt\* class.
2010
     *       - The following variable names are reserved:
2011
     *         - $_*  (all variable names prefixed with an underscore)
2012
     *         - $self (object reference to it self. Do not use $this, but $self instead)
2013
     *         - $in (the content of $in has to en/decrypt by the generated code)
2014
     *       - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only
2015
     *
2016
     *
2017
     * @see self::_setup()
2018
     * @see self::_createInlineCryptFunction()
2019
     * @see self::encrypt()
2020
     * @see self::decrypt()
2021
     * @access private
2022
     * @internal If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt()
2023
     */
2024
    public function _setupInlineCrypt()
2025
    {
2026
        // If, for any reason, an extending \phpseclib\Crypt\Base() \phpseclib\Crypt\* class
2027
        // not using inline crypting then it must be ensured that: $this->use_inline_crypt = false
2028
        // ie in the class var declaration of $use_inline_crypt in general for the \phpseclib\Crypt\* class,
2029
        // in the constructor at object instance-time
2030
        // or, if it's runtime-specific, at runtime
2031
2032
        $this->use_inline_crypt = false;
2033
    }
2034
2035
    /**
2036
     * Creates the performance-optimized function for en/decrypt()
2037
     *
2038
     * Internally for phpseclib developers:
2039
     *
2040
     *    _createInlineCryptFunction():
2041
     *
2042
     *    - merge the $cipher_code [setup'ed by _setupInlineCrypt()]
2043
     *      with the current [$this->]mode of operation code
2044
     *
2045
     *    - create the $inline function, which called by encrypt() / decrypt()
2046
     *      as its replacement to speed up the en/decryption operations.
2047
     *
2048
     *    - return the name of the created $inline callback function
2049
     *
2050
     *    - used to speed up en/decryption
2051
     *
2052
     *
2053
     *
2054
     *    The main reason why can speed up things [up to 50%] this way are:
2055
     *
2056
     *    - using variables more effective then regular.
2057
     *      (ie no use of expensive arrays but integers $k_0, $k_1 ...
2058
     *      or even, for example, the pure $key[] values hardcoded)
2059
     *
2060
     *    - avoiding 1000's of function calls of ie _encryptBlock()
2061
     *      but inlining the crypt operations.
2062
     *      in the mode of operation for() loop.
2063
     *
2064
     *    - full loop unroll the (sometimes key-dependent) rounds
2065
     *      avoiding this way ++$i counters and runtime-if's etc...
2066
     *
2067
     *    The basic code architectur of the generated $inline en/decrypt()
2068
     *    lambda function, in pseudo php, is:
2069
     *
2070
     *    <code>
2071
     *    +----------------------------------------------------------------------------------------------+
2072
     *    | callback $inline = create_function:                                                          |
2073
     *    | lambda_function_0001_crypt_ECB($action, $text)                                               |
2074
     *    | {                                                                                            |
2075
     *    |     INSERT PHP CODE OF:                                                                      |
2076
     *    |     $cipher_code['init_crypt'];                  // general init code.                       |
2077
     *    |                                                  // ie: $sbox'es declarations used for       |
2078
     *    |                                                  //     encrypt and decrypt'ing.             |
2079
     *    |                                                                                              |
2080
     *    |     switch ($action) {                                                                       |
2081
     *    |         case 'encrypt':                                                                      |
2082
     *    |             INSERT PHP CODE OF:                                                              |
2083
     *    |             $cipher_code['init_encrypt'];       // encrypt sepcific init code.               |
2084
     *    |                                                    ie: specified $key or $box                |
2085
     *    |                                                        declarations for encrypt'ing.         |
2086
     *    |                                                                                              |
2087
     *    |             foreach ($ciphertext) {                                                          |
2088
     *    |                 $in = $block_size of $ciphertext;                                            |
2089
     *    |                                                                                              |
2090
     *    |                 INSERT PHP CODE OF:                                                          |
2091
     *    |                 $cipher_code['encrypt_block'];  // encrypt's (string) $in, which is always:  |
2092
     *    |                                                 // strlen($in) == $this->block_size          |
2093
     *    |                                                 // here comes the cipher algorithm in action |
2094
     *    |                                                 // for encryption.                           |
2095
     *    |                                                 // $cipher_code['encrypt_block'] has to      |
2096
     *    |                                                 // encrypt the content of the $in variable   |
2097
     *    |                                                                                              |
2098
     *    |                 $plaintext .= $in;                                                           |
2099
     *    |             }                                                                                |
2100
     *    |             return $plaintext;                                                               |
2101
     *    |                                                                                              |
2102
     *    |         case 'decrypt':                                                                      |
2103
     *    |             INSERT PHP CODE OF:                                                              |
2104
     *    |             $cipher_code['init_decrypt'];       // decrypt sepcific init code                |
2105
     *    |                                                    ie: specified $key or $box                |
2106
     *    |                                                        declarations for decrypt'ing.         |
2107
     *    |             foreach ($plaintext) {                                                           |
2108
     *    |                 $in = $block_size of $plaintext;                                             |
2109
     *    |                                                                                              |
2110
     *    |                 INSERT PHP CODE OF:                                                          |
2111
     *    |                 $cipher_code['decrypt_block'];  // decrypt's (string) $in, which is always   |
2112
     *    |                                                 // strlen($in) == $this->block_size          |
2113
     *    |                                                 // here comes the cipher algorithm in action |
2114
     *    |                                                 // for decryption.                           |
2115
     *    |                                                 // $cipher_code['decrypt_block'] has to      |
2116
     *    |                                                 // decrypt the content of the $in variable   |
2117
     *    |                 $ciphertext .= $in;                                                          |
2118
     *    |             }                                                                                |
2119
     *    |             return $ciphertext;                                                              |
2120
     *    |     }                                                                                        |
2121
     *    | }                                                                                            |
2122
     *    +----------------------------------------------------------------------------------------------+
2123
     *    </code>
2124
     *
2125
     *    See also the \phpseclib\Crypt\*::_setupInlineCrypt()'s for
2126
     *    productive inline $cipher_code's how they works.
2127
     *
2128
     *    Structure of:
2129
     *    <code>
2130
     *    $cipher_code = array(
2131
     *        'init_crypt'    => (string) '', // optional
2132
     *        'init_encrypt'  => (string) '', // optional
2133
     *        'init_decrypt'  => (string) '', // optional
2134
     *        'encrypt_block' => (string) '', // required
2135
     *        'decrypt_block' => (string) ''  // required
2136
     *    );
2137
     *    </code>
2138
     *
2139
     * @see self::_setupInlineCrypt()
2140
     * @see self::encrypt()
2141
     * @see self::decrypt()
2142
     * @param array $cipher_code
2143
     * @access private
2144
     * @return string (the name of the created callback function)
2145
     */
2146
    public function _createInlineCryptFunction($cipher_code)
2147
    {
2148
        $block_size = $this->block_size;
2149
2150
        // optional
2151
        $init_crypt    = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : '';
2152
        $init_encrypt  = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : '';
2153
        $init_decrypt  = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : '';
2154
        // required
2155
        $encrypt_block = $cipher_code['encrypt_block'];
2156
        $decrypt_block = $cipher_code['decrypt_block'];
2157
2158
        // Generating mode of operation inline code,
2159
        // merged with the $cipher_code algorithm
2160
        // for encrypt- and decryption.
2161
        switch ($this->mode) {
2162
            case self::MODE_ECB:
2163
                $encrypt = $init_encrypt . '
2164
                    $_ciphertext = "";
2165
                    $_plaintext_len = strlen($_text);
2166
2167
                    for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
2168
                        $in = substr($_text, $_i, ' . $block_size . ');
2169
                        ' . $encrypt_block . '
2170
                        $_ciphertext.= $in;
2171
                    }
2172
2173
                    return $_ciphertext;
2174
                    ';
2175
2176
                $decrypt = $init_decrypt . '
2177
                    $_plaintext = "";
2178
                    $_text = str_pad($_text, strlen($_text) + (' . $block_size . ' - strlen($_text) % ' . $block_size . ') % ' . $block_size . ', chr(0));
2179
                    $_ciphertext_len = strlen($_text);
2180
2181
                    for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
2182
                        $in = substr($_text, $_i, ' . $block_size . ');
2183
                        ' . $decrypt_block . '
2184
                        $_plaintext.= $in;
2185
                    }
2186
2187
                    return $self->_unpad($_plaintext);
2188
                    ';
2189
                break;
2190
            case self::MODE_CTR:
2191
                $encrypt = $init_encrypt . '
2192
                    $_ciphertext = "";
2193
                    $_plaintext_len = strlen($_text);
2194
                    $_xor = $self->encryptIV;
2195
                    $_buffer = &$self->enbuffer;
2196
                    if (strlen($_buffer["ciphertext"])) {
2197
                        for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
2198
                            $_block = substr($_text, $_i, ' . $block_size . ');
2199
                            if (strlen($_block) > strlen($_buffer["ciphertext"])) {
2200
                                $in = $_xor;
2201
                                ' . $encrypt_block . '
2202
                                $self->_increment_str($_xor);
2203
                                $_buffer["ciphertext"].= $in;
2204
                            }
2205
                            $_key = $self->_string_shift($_buffer["ciphertext"], ' . $block_size . ');
2206
                            $_ciphertext.= $_block ^ $_key;
2207
                        }
2208
                    } else {
2209
                        for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
2210
                            $_block = substr($_text, $_i, ' . $block_size . ');
2211
                            $in = $_xor;
2212
                            ' . $encrypt_block . '
2213
                            $self->_increment_str($_xor);
2214
                            $_key = $in;
2215
                            $_ciphertext.= $_block ^ $_key;
2216
                        }
2217
                    }
2218
                    if ($self->continuousBuffer) {
2219
                        $self->encryptIV = $_xor;
2220
                        if ($_start = $_plaintext_len % ' . $block_size . ') {
2221
                            $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
2222
                        }
2223
                    }
2224
2225
                    return $_ciphertext;
2226
                ';
2227
2228
                $decrypt = $init_encrypt . '
2229
                    $_plaintext = "";
2230
                    $_ciphertext_len = strlen($_text);
2231
                    $_xor = $self->decryptIV;
2232
                    $_buffer = &$self->debuffer;
2233
2234
                    if (strlen($_buffer["ciphertext"])) {
2235
                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
2236
                            $_block = substr($_text, $_i, ' . $block_size . ');
2237
                            if (strlen($_block) > strlen($_buffer["ciphertext"])) {
2238
                                $in = $_xor;
2239
                                ' . $encrypt_block . '
2240
                                $self->_increment_str($_xor);
2241
                                $_buffer["ciphertext"].= $in;
2242
                            }
2243
                            $_key = $self->_string_shift($_buffer["ciphertext"], ' . $block_size . ');
2244
                            $_plaintext.= $_block ^ $_key;
2245
                        }
2246
                    } else {
2247
                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
2248
                            $_block = substr($_text, $_i, ' . $block_size . ');
2249
                            $in = $_xor;
2250
                            ' . $encrypt_block . '
2251
                            $self->_increment_str($_xor);
2252
                            $_key = $in;
2253
                            $_plaintext.= $_block ^ $_key;
2254
                        }
2255
                    }
2256
                    if ($self->continuousBuffer) {
2257
                        $self->decryptIV = $_xor;
2258
                        if ($_start = $_ciphertext_len % ' . $block_size . ') {
2259
                            $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
2260
                        }
2261
                    }
2262
2263
                    return $_plaintext;
2264
                    ';
2265
                break;
2266
            case self::MODE_CFB:
2267
                $encrypt = $init_encrypt . '
2268
                    $_ciphertext = "";
2269
                    $_buffer = &$self->enbuffer;
2270
2271
                    if ($self->continuousBuffer) {
2272
                        $_iv = &$self->encryptIV;
2273
                        $_pos = &$_buffer["pos"];
2274
                    } else {
2275
                        $_iv = $self->encryptIV;
2276
                        $_pos = 0;
2277
                    }
2278
                    $_len = strlen($_text);
2279
                    $_i = 0;
2280
                    if ($_pos) {
2281
                        $_orig_pos = $_pos;
2282
                        $_max = ' . $block_size . ' - $_pos;
2283
                        if ($_len >= $_max) {
2284
                            $_i = $_max;
2285
                            $_len-= $_max;
2286
                            $_pos = 0;
2287
                        } else {
2288
                            $_i = $_len;
2289
                            $_pos+= $_len;
2290
                            $_len = 0;
2291
                        }
2292
                        $_ciphertext = substr($_iv, $_orig_pos) ^ $_text;
2293
                        $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i);
2294
                    }
2295
                    while ($_len >= ' . $block_size . ') {
2296
                        $in = $_iv;
2297
                        ' . $encrypt_block . ';
2298
                        $_iv = $in ^ substr($_text, $_i, ' . $block_size . ');
2299
                        $_ciphertext.= $_iv;
2300
                        $_len-= ' . $block_size . ';
2301
                        $_i+= ' . $block_size . ';
2302
                    }
2303
                    if ($_len) {
2304
                        $in = $_iv;
2305
                        ' . $encrypt_block . '
2306
                        $_iv = $in;
2307
                        $_block = $_iv ^ substr($_text, $_i);
2308
                        $_iv = substr_replace($_iv, $_block, 0, $_len);
2309
                        $_ciphertext.= $_block;
2310
                        $_pos = $_len;
2311
                    }
2312
                    return $_ciphertext;
2313
                ';
2314
2315
                $decrypt = $init_encrypt . '
2316
                    $_plaintext = "";
2317
                    $_buffer = &$self->debuffer;
2318
2319
                    if ($self->continuousBuffer) {
2320
                        $_iv = &$self->decryptIV;
2321
                        $_pos = &$_buffer["pos"];
2322
                    } else {
2323
                        $_iv = $self->decryptIV;
2324
                        $_pos = 0;
2325
                    }
2326
                    $_len = strlen($_text);
2327
                    $_i = 0;
2328
                    if ($_pos) {
2329
                        $_orig_pos = $_pos;
2330
                        $_max = ' . $block_size . ' - $_pos;
2331
                        if ($_len >= $_max) {
2332
                            $_i = $_max;
2333
                            $_len-= $_max;
2334
                            $_pos = 0;
2335
                        } else {
2336
                            $_i = $_len;
2337
                            $_pos+= $_len;
2338
                            $_len = 0;
2339
                        }
2340
                        $_plaintext = substr($_iv, $_orig_pos) ^ $_text;
2341
                        $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i);
2342
                    }
2343
                    while ($_len >= ' . $block_size . ') {
2344
                        $in = $_iv;
2345
                        ' . $encrypt_block . '
2346
                        $_iv = $in;
2347
                        $cb = substr($_text, $_i, ' . $block_size . ');
2348
                        $_plaintext.= $_iv ^ $cb;
2349
                        $_iv = $cb;
2350
                        $_len-= ' . $block_size . ';
2351
                        $_i+= ' . $block_size . ';
2352
                    }
2353
                    if ($_len) {
2354
                        $in = $_iv;
2355
                        ' . $encrypt_block . '
2356
                        $_iv = $in;
2357
                        $_plaintext.= $_iv ^ substr($_text, $_i);
2358
                        $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len);
2359
                        $_pos = $_len;
2360
                    }
2361
2362
                    return $_plaintext;
2363
                    ';
2364
                break;
2365
            case self::MODE_OFB:
2366
                $encrypt = $init_encrypt . '
2367
                    $_ciphertext = "";
2368
                    $_plaintext_len = strlen($_text);
2369
                    $_xor = $self->encryptIV;
2370
                    $_buffer = &$self->enbuffer;
2371
2372
                    if (strlen($_buffer["xor"])) {
2373
                        for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
2374
                            $_block = substr($_text, $_i, ' . $block_size . ');
2375
                            if (strlen($_block) > strlen($_buffer["xor"])) {
2376
                                $in = $_xor;
2377
                                ' . $encrypt_block . '
2378
                                $_xor = $in;
2379
                                $_buffer["xor"].= $_xor;
2380
                            }
2381
                            $_key = $self->_string_shift($_buffer["xor"], ' . $block_size . ');
2382
                            $_ciphertext.= $_block ^ $_key;
2383
                        }
2384
                    } else {
2385
                        for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
2386
                            $in = $_xor;
2387
                            ' . $encrypt_block . '
2388
                            $_xor = $in;
2389
                            $_ciphertext.= substr($_text, $_i, ' . $block_size . ') ^ $_xor;
2390
                        }
2391
                        $_key = $_xor;
2392
                    }
2393
                    if ($self->continuousBuffer) {
2394
                        $self->encryptIV = $_xor;
2395
                        if ($_start = $_plaintext_len % ' . $block_size . ') {
2396
                             $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
2397
                        }
2398
                    }
2399
                    return $_ciphertext;
2400
                    ';
2401
2402
                $decrypt = $init_encrypt . '
2403
                    $_plaintext = "";
2404
                    $_ciphertext_len = strlen($_text);
2405
                    $_xor = $self->decryptIV;
2406
                    $_buffer = &$self->debuffer;
2407
2408
                    if (strlen($_buffer["xor"])) {
2409
                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
2410
                            $_block = substr($_text, $_i, ' . $block_size . ');
2411
                            if (strlen($_block) > strlen($_buffer["xor"])) {
2412
                                $in = $_xor;
2413
                                ' . $encrypt_block . '
2414
                                $_xor = $in;
2415
                                $_buffer["xor"].= $_xor;
2416
                            }
2417
                            $_key = $self->_string_shift($_buffer["xor"], ' . $block_size . ');
2418
                            $_plaintext.= $_block ^ $_key;
2419
                        }
2420
                    } else {
2421
                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
2422
                            $in = $_xor;
2423
                            ' . $encrypt_block . '
2424
                            $_xor = $in;
2425
                            $_plaintext.= substr($_text, $_i, ' . $block_size . ') ^ $_xor;
2426
                        }
2427
                        $_key = $_xor;
2428
                    }
2429
                    if ($self->continuousBuffer) {
2430
                        $self->decryptIV = $_xor;
2431
                        if ($_start = $_ciphertext_len % ' . $block_size . ') {
2432
                             $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
2433
                        }
2434
                    }
2435
                    return $_plaintext;
2436
                    ';
2437
                break;
2438
            case self::MODE_STREAM:
2439
                $encrypt = $init_encrypt . '
2440
                    $_ciphertext = "";
2441
                    ' . $encrypt_block . '
2442
                    return $_ciphertext;
2443
                    ';
2444
                $decrypt = $init_decrypt . '
2445
                    $_plaintext = "";
2446
                    ' . $decrypt_block . '
2447
                    return $_plaintext;
2448
                    ';
2449
                break;
2450
            // case self::MODE_CBC:
2451
            default:
2452
                $encrypt = $init_encrypt . '
2453
                    $_ciphertext = "";
2454
                    $_plaintext_len = strlen($_text);
2455
2456
                    $in = $self->encryptIV;
2457
2458
                    for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
2459
                        $in = substr($_text, $_i, ' . $block_size . ') ^ $in;
2460
                        ' . $encrypt_block . '
2461
                        $_ciphertext.= $in;
2462
                    }
2463
2464
                    if ($self->continuousBuffer) {
2465
                        $self->encryptIV = $in;
2466
                    }
2467
2468
                    return $_ciphertext;
2469
                    ';
2470
2471
                $decrypt = $init_decrypt . '
2472
                    $_plaintext = "";
2473
                    $_text = str_pad($_text, strlen($_text) + (' . $block_size . ' - strlen($_text) % ' . $block_size . ') % ' . $block_size . ', chr(0));
2474
                    $_ciphertext_len = strlen($_text);
2475
2476
                    $_iv = $self->decryptIV;
2477
2478
                    for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
2479
                        $in = $_block = substr($_text, $_i, ' . $block_size . ');
2480
                        ' . $decrypt_block . '
2481
                        $_plaintext.= $in ^ $_iv;
2482
                        $_iv = $_block;
2483
                    }
2484
2485
                    if ($self->continuousBuffer) {
2486
                        $self->decryptIV = $_iv;
2487
                    }
2488
2489
                    return $self->_unpad($_plaintext);
2490
                    ';
2491
                break;
2492
        }
2493
2494
        // Create the $inline function and return its name as string. Ready to run!
2495
        return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }');
0 ignored issues
show
Deprecated Code introduced by
The function create_function() has been deprecated: 7.2 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

2495
        return /** @scrutinizer ignore-deprecated */ create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
2496
    }
2497
2498
    /**
2499
     * Holds the lambda_functions table (classwide)
2500
     *
2501
     * Each name of the lambda function, created from
2502
     * _setupInlineCrypt() && _createInlineCryptFunction()
2503
     * is stored, classwide (!), here for reusing.
2504
     *
2505
     * The string-based index of $function is a classwide
2506
     * unique value representing, at least, the $mode of
2507
     * operation (or more... depends of the optimizing level)
2508
     * for which $mode the lambda function was created.
2509
     *
2510
     * @access private
2511
     * @return array &$functions
2512
     */
2513
    public function &_getLambdaFunctions()
2514
    {
2515
        static $functions = array();
2516
        return $functions;
2517
    }
2518
2519
    /**
2520
     * Generates a digest from $bytes
2521
     *
2522
     * @see self::_setupInlineCrypt()
2523
     * @access private
2524
     * @param $bytes
2525
     * @return string
2526
     */
2527
    public function _hashInlineCryptFunction($bytes)
2528
    {
2529
        if (!isset(self::$WHIRLPOOL_AVAILABLE)) {
2530
            self::$WHIRLPOOL_AVAILABLE = extension_loaded('hash') && in_array('whirlpool', hash_algos());
2531
        }
2532
2533
        $result = '';
2534
        $hash = $bytes;
2535
2536
        switch (true) {
2537
            case self::$WHIRLPOOL_AVAILABLE:
2538
                foreach (str_split($bytes, 64) as $t) {
2539
                    $hash = hash('whirlpool', $hash, true);
2540
                    $result .= $t ^ $hash;
2541
                }
2542
                return $result . hash('whirlpool', $hash, true);
2543
            default:
2544
                $len = strlen($bytes);
2545
                for ($i = 0; $i < $len; $i+=20) {
2546
                    $t = substr($bytes, $i, 20);
2547
                    $hash = pack('H*', hash('sha256', $hash));
2548
                    $result .= $t ^ $hash;
2549
                }
2550
                return $result . pack('H*', hash('sha256', $hash));
2551
        }
2552
    }
2553
}
2554