[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/ -> SymmetricKey.php (source)

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