[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

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


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer