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