Subversion Repositories cheapmusic

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
103 - 1
<?php
2
 
3
/**
4
 * Base Class for all \phpseclib\Crypt\* cipher classes
5
 *
6
 * PHP version 5
7
 *
8
 * Internally for phpseclib developers:
9
 *  If you plan to add a new cipher class, please note following rules:
10
 *
11
 *  - The new \phpseclib\Crypt\* cipher class should extend \phpseclib\Crypt\Base
12
 *
13
 *  - Following methods are then required to be overridden/overloaded:
14
 *
15
 *    - _encryptBlock()
16
 *
17
 *    - _decryptBlock()
18
 *
19
 *    - _setupKey()
20
 *
21
 *  - All other methods are optional to be overridden/overloaded
22
 *
23
 *  - Look at the source code of the current ciphers how they extend \phpseclib\Crypt\Base
24
 *    and take one of them as a start up for the new cipher class.
25
 *
26
 *  - Please read all the other comments/notes/hints here also for each class var/method
27
 *
28
 * @category  Crypt
29
 * @package   Base
30
 * @author    Jim Wigginton <terrafrost@php.net>
31
 * @author    Hans-Juergen Petrich <petrich@tronic-media.com>
32
 * @copyright 2007 Jim Wigginton
33
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
34
 * @link      http://phpseclib.sourceforge.net
35
 */
36
 
37
namespace phpseclib\Crypt;
38
 
39
/**
40
 * Base Class for all \phpseclib\Crypt\* cipher classes
41
 *
42
 * @package Base
43
 * @author  Jim Wigginton <terrafrost@php.net>
44
 * @author  Hans-Juergen Petrich <petrich@tronic-media.com>
45
 */
46
abstract class Base
47
{
48
    /**#@+
49
     * @access public
50
     * @see \phpseclib\Crypt\Base::encrypt()
51
     * @see \phpseclib\Crypt\Base::decrypt()
52
     */
53
    /**
54
     * Encrypt / decrypt using the Counter mode.
55
     *
56
     * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
57
     *
58
     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
59
     */
60
    const MODE_CTR = -1;
61
    /**
62
     * Encrypt / decrypt using the Electronic Code Book mode.
63
     *
64
     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
65
     */
66
    const MODE_ECB = 1;
67
    /**
68
     * Encrypt / decrypt using the Code Book Chaining mode.
69
     *
70
     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
71
     */
72
    const MODE_CBC = 2;
73
    /**
74
     * Encrypt / decrypt using the Cipher Feedback mode.
75
     *
76
     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
77
     */
78
    const MODE_CFB = 3;
79
    /**
80
     * Encrypt / decrypt using the Output Feedback mode.
81
     *
82
     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
83
     */
84
    const MODE_OFB = 4;
85
    /**
86
     * Encrypt / decrypt using streaming mode.
87
     */
88
    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
    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
    const ENGINE_INTERNAL = 1;
108
    /**
109
     * Base value for the mcrypt implementation $engine switch
110
     */
111
    const ENGINE_MCRYPT = 2;
112
    /**
113
     * Base value for the mcrypt implementation $engine switch
114
     */
115
    const ENGINE_OPENSSL = 3;
116
    /**#@-*/
117
 
118
    /**
119
     * The Encryption Mode
120
     *
121
     * @see self::__construct()
122
     * @var int
123
     * @access private
124
     */
125
    var $mode;
126
 
127
    /**
128
     * The Block Length of the block cipher
129
     *
130
     * @var int
131
     * @access private
132
     */
133
    var $block_size = 16;
134
 
135
    /**
136
     * The Key
137
     *
138
     * @see self::setKey()
139
     * @var string
140
     * @access private
141
     */
142
    var $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
    var $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
    var $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
    var $decryptIV;
172
 
173
    /**
174
     * Continuous Buffer status
175
     *
176
     * @see self::enableContinuousBuffer()
177
     * @var bool
178
     * @access private
179
     */
180
    var $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
    var $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
    var $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
    var $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
    var $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
    var $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
    var $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
    var $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
    var $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
    var $changed = true;
297
 
298
    /**
299
     * Padding status
300
     *
301
     * @see self::enablePadding()
302
     * @var bool
303
     * @access private
304
     */
305
    var $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
    var $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
    var $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
    var $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
    var $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
    var $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
    var $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
    var $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
    var $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
    var $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
    var $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
    var $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
    var $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
    var $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
    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
    function setIV($iv)
511
    {
512
        if ($this->mode == self::MODE_ECB) {
513
            return;
514
        }
515
 
516
        $this->iv = $iv;
517
        $this->changed = true;
518
    }
519
 
520
    /**
521
     * Sets the key length.
522
     *
523
     * Keys with explicitly set lengths need to be treated accordingly
524
     *
525
     * @access public
526
     * @param int $length
527
     */
528
    function setKeyLength($length)
529
    {
530
        $this->explicit_key_length = true;
531
        $this->changed = true;
532
        $this->_setEngine();
533
    }
534
 
535
    /**
536
     * Returns the current key length in bits
537
     *
538
     * @access public
539
     * @return int
540
     */
541
    function getKeyLength()
542
    {
543
        return $this->key_length << 3;
544
    }
545
 
546
    /**
547
     * Returns the current block length in bits
548
     *
549
     * @access public
550
     * @return int
551
     */
552
    function getBlockLength()
553
    {
554
        return $this->block_size << 3;
555
    }
556
 
557
    /**
558
     * Sets the key.
559
     *
560
     * The min/max length(s) of the key depends on the cipher which is used.
561
     * If the key not fits the length(s) of the cipher it will paded with null bytes
562
     * up to the closest valid key length.  If the key is more than max length,
563
     * we trim the excess bits.
564
     *
565
     * If the key is not explicitly set, it'll be assumed to be all null bytes.
566
     *
567
     * @access public
568
     * @param string $key
569
     * @internal Could, but not must, extend by the child Crypt_* class
570
     */
571
    function setKey($key)
572
    {
573
        if (!$this->explicit_key_length) {
574
            $this->setKeyLength(strlen($key) << 3);
575
            $this->explicit_key_length = false;
576
        }
577
 
578
        $this->key = $key;
579
        $this->changed = true;
580
        $this->_setEngine();
581
    }
582
 
583
    /**
584
     * Sets the password.
585
     *
586
     * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
587
     *     {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
588
     *         $hash, $salt, $count, $dkLen
589
     *
590
     *         Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
591
     *
592
     * @see Crypt/Hash.php
593
     * @param string $password
594
     * @param string $method
595
     * @return bool
596
     * @access public
597
     * @internal Could, but not must, extend by the child Crypt_* class
598
     */
599
    function setPassword($password, $method = 'pbkdf2')
600
    {
601
        $key = '';
602
 
603
        switch ($method) {
604
            default: // 'pbkdf2' or 'pbkdf1'
605
                $func_args = func_get_args();
606
 
607
                // Hash function
608
                $hash = isset($func_args[2]) ? $func_args[2] : 'sha1';
609
 
610
                // WPA and WPA2 use the SSID as the salt
611
                $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;
612
 
613
                // RFC2898#section-4.2 uses 1,000 iterations by default
614
                // WPA and WPA2 use 4,096.
615
                $count = isset($func_args[4]) ? $func_args[4] : 1000;
616
 
617
                // Keylength
618
                if (isset($func_args[5])) {
619
                    $dkLen = $func_args[5];
620
                } else {
621
                    $dkLen = $method == 'pbkdf1' ? 2 * $this->key_length : $this->key_length;
622
                }
623
 
624
                switch (true) {
625
                    case $method == 'pbkdf1':
626
                        $hashObj = new Hash();
627
                        $hashObj->setHash($hash);
628
                        if ($dkLen > $hashObj->getLength()) {
629
                            user_error('Derived key too long');
630
                            return false;
631
                        }
632
                        $t = $password . $salt;
633
                        for ($i = 0; $i < $count; ++$i) {
634
                            $t = $hashObj->hash($t);
635
                        }
636
                        $key = substr($t, 0, $dkLen);
637
 
638
                        $this->setKey(substr($key, 0, $dkLen >> 1));
639
                        $this->setIV(substr($key, $dkLen >> 1));
640
 
641
                        return true;
642
                    // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
643
                    case !function_exists('hash_pbkdf2'):
644
                    case !function_exists('hash_algos'):
645
                    case !in_array($hash, hash_algos()):
646
                        $i = 1;
647
                        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
    function encrypt($plaintext)
691
    {
692
        if ($this->paddable) {
693
            $plaintext = $this->_pad($plaintext);
694
        }
695
 
696
        if ($this->engine === self::ENGINE_OPENSSL) {
697
            if ($this->changed) {
698
                $this->_clearBuffers();
699
                $this->changed = false;
700
            }
701
            switch ($this->mode) {
702
                case self::MODE_STREAM:
703
                    return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
704
                case self::MODE_ECB:
705
                    $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
706
                    return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
707
                case self::MODE_CBC:
708
                    $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
709
                    if (!defined('OPENSSL_RAW_DATA')) {
710
                        $result = substr($result, 0, -$this->block_size);
711
                    }
712
                    if ($this->continuousBuffer) {
713
                        $this->encryptIV = substr($result, -$this->block_size);
714
                    }
715
                    return $result;
716
                case self::MODE_CTR:
717
                    return $this->_openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer);
718
                case self::MODE_CFB:
719
                    // cfb loosely routines inspired by openssl's:
720
                    // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
721
                    $ciphertext = '';
722
                    if ($this->continuousBuffer) {
723
                        $iv = &$this->encryptIV;
724
                        $pos = &$this->enbuffer['pos'];
725
                    } else {
726
                        $iv = $this->encryptIV;
727
                        $pos = 0;
728
                    }
729
                    $len = strlen($plaintext);
730
                    $i = 0;
731
                    if ($pos) {
732
                        $orig_pos = $pos;
733
                        $max = $this->block_size - $pos;
734
                        if ($len >= $max) {
735
                            $i = $max;
736
                            $len-= $max;
737
                            $pos = 0;
738
                        } else {
739
                            $i = $len;
740
                            $pos+= $len;
741
                            $len = 0;
742
                        }
743
                        // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
744
                        $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
745
                        $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
746
                        $plaintext = substr($plaintext, $i);
747
                    }
748
 
749
                    $overflow = $len % $this->block_size;
750
 
751
                    if ($overflow) {
752
                        $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
753
                        $iv = $this->_string_pop($ciphertext, $this->block_size);
754
 
755
                        $size = $len - $overflow;
756
                        $block = $iv ^ substr($plaintext, -$overflow);
757
                        $iv = substr_replace($iv, $block, 0, $overflow);
758
                        $ciphertext.= $block;
759
                        $pos = $overflow;
760
                    } elseif ($len) {
761
                        $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
762
                        $iv = substr($ciphertext, -$this->block_size);
763
                    }
764
 
765
                    return $ciphertext;
766
                case self::MODE_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);
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);
811
                            $this->enbuffer['enmcrypt_init'] = false;
812
                        }
813
                        $ciphertext.= @mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
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);
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);
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);
838
 
839
            if (!$this->continuousBuffer) {
840
                @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
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'];
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
    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);
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;
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);
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;
1118
                    $iv = substr($cb, -$block_size);
1119
                    $len%= $block_size;
1120
                }
1121
                if ($len) {
1122
                    $iv = @mcrypt_generic($this->ecb, $iv);
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);
1132
 
1133
            if (!$this->continuousBuffer) {
1134
                @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
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'];
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
    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
    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
    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
    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
    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
    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
    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
    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());
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
    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
    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
    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);
1676
            @mcrypt_module_close($this->demcrypt);
1677
            $this->enmcrypt = null;
1678
            $this->demcrypt = null;
1679
 
1680
            if ($this->ecb) {
1681
                @mcrypt_module_close($this->ecb);
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 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 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 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
    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
    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], '');
1796
            $this->enmcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
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, '');
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));
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
    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
    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
    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
    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
    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
    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
    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
    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 . ' }');
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
    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
    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*', sha1($hash));
2548
                    $result .= $t ^ $hash;
2549
                }
2550
                return $result . pack('H*', sha1($hash));
2551
        }
2552
    }
2553
}