+Based on the [constant-time base64 implementation made by Steve "Sc00bz" Thomas](https://github.com/Sc00bz/ConstTimeEncoding),
+this library aims to offer character encoding functions that do not leak
+information about what you are encoding/decoding via processor cache
+misses. Further reading on [cache-timing attacks](http://blog.ircmaxell.com/2014/11/its-all-about-time.html).
+
+Our fork offers the following enchancements:
+
+* `mbstring.func_overload` resistance
+* Unit tests
+* Composer- and Packagist-ready
+* Base16 encoding
+* Base32 encoding
+* Uses `pack()` and `unpack()` instead of `chr()` and `ord()`
+
+## PHP Version Requirements
+
+Version 2 of this library should work on **PHP 7** or newer. For PHP 5
+support, see [the v1.x branch](https://github.com/paragonie/constant_time_encoding/tree/v1.x).
+
+If you are adding this as a dependency to a project intended to work on both PHP 5 and PHP 7, please set the required version to `^1|^2` instead of just `^1` or `^2`.
+phpseclib ongoing development is made possible by [Tidelift](https://tidelift.com/subscription/pkg/packagist-phpseclib-phpseclib?utm_source=packagist-phpseclib-phpseclib&utm_medium=referral&utm_campaign=readme) and by contributions by users like you. Thank you.
+- [Become a backer or sponsor on Patreon](https://www.patreon.com/phpseclib)
+- [One-time donation via PayPal or crypto-currencies](http://sourceforge.net/donate/index.php?group_id=198487)
+- [Subscribe to Tidelift](https://tidelift.com/subscription/pkg/packagist-phpseclib-phpseclib?utm_source=packagist-phpseclib-phpseclib&utm_medium=referral&utm_campaign=readme)
+
+## Introduction
+
+MIT-licensed pure-PHP implementations of the following:
+* [API Documentation](https://api.phpseclib.com/3.0/) (generated by Doctum)
+
+## Branches
+
+### master
+
+* Development Branch
+* Unstable API
+* Do not use in production
+
+### 3.0
+
+* Long term support (LTS) release
+* Major expansion of cryptographic primitives
+* Minimum PHP version: 5.6.1
+* PSR-4 autoloading with namespace rooted at `\phpseclib3`
+* Install via Composer: `composer require phpseclib/phpseclib:~3.0`
+
+### 2.0
+
+* Long term support (LTS) release
+* Modernized version of 1.0
+* Minimum PHP version: 5.3.3
+* PSR-4 autoloading with namespace rooted at `\phpseclib`
+* Install via Composer: `composer require phpseclib/phpseclib:~2.0`
+
+### 1.0
+
+* Long term support (LTS) release
+* PHP4 compatible
+* Composer compatible (PSR-0 autoloading)
+* Install using Composer: `composer require phpseclib/phpseclib:~1.0`
+* Install using PEAR: See [phpseclib PEAR Channel Documentation](http://phpseclib.sourceforge.net/pear.htm)
+* [Download 1.0.20 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.20.zip/download)
+
+## Security contact information
+
+To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure.
+
+## Support
+
+Need Support?
+
+* [Checkout Questions and Answers on Stack Overflow](http://stackoverflow.com/questions/tagged/phpseclib)
+* [Create a Support Ticket on GitHub](https://github.com/phpseclib/phpseclib/issues/new)
+* [Browse the Support Forum](http://www.frostjedi.com/phpbb/viewforum.php?f=46) (no longer in use)
+
+## Special Thanks
+
+Special Thanks to our $50+ sponsors!:
+
+- Allan Simon
+- [ChargeOver](https://chargeover.com/)
+
+## Contributing
+
+1. Fork the Project
+
+2. Ensure you have Composer installed (see [Composer Download Instructions](https://getcomposer.org/download/))
+
+3. Install Development Dependencies
+ ```sh
+ composer install
+ ```
+
+4. Create a Feature Branch
+
+5. Run continuous integration checks:
+ ```sh
+ composer global require php:^8.1 squizlabs/php_codesniffer friendsofphp/php-cs-fixer vimeo/psalm
+ * @throws \InvalidArgumentException if an invalid / unsupported mode is provided
+ */
+ public function __construct($mode)
+ {
+ parent::__construct($mode);
+
+ if ($this->mode == self::MODE_STREAM) {
+ throw new \InvalidArgumentException('Block ciphers cannot be ran in stream mode');
+ }
+ }
+
+ /**
+ * Sets the key length.
+ *
+ * Key lengths can be between 32 and 448 bits.
+ *
+ * @param int $length
+ */
+ public function setKeyLength($length)
+ {
+ if ($length < 32 || $length > 448) {
+ throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes between 32 and 448 bits are supported');
+ }
+
+ $this->key_length = $length >> 3;
+
+ parent::setKeyLength($length);
+ }
+
+ /**
+ * Test for engine validity
+ *
+ * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
+ throw new \UnexpectedValueException('The nonce should be a string');
+ }
+
+ /*
+ from https://tools.ietf.org/html/rfc7539#page-7
+
+ "Note also that the original ChaCha had a 64-bit nonce and 64-bit
+ block count. We have modified this here to be more consistent with
+ recommendations in Section 3.2 of [RFC5116]."
+ */
+ switch (strlen($nonce)) {
+ case 8: // 64 bits
+ case 12: // 96 bits
+ break;
+ default:
+ throw new \LengthException('Nonce of size ' . strlen($nonce) . ' not supported by this algorithm. Only 64-bit nonces or 96-bit nonces are supported');
+ }
+
+ $this->nonce = $nonce;
+ $this->changed = true;
+ $this->setEngine();
+ }
+
+ /**
+ * Setup the self::ENGINE_INTERNAL $engine
+ *
+ * (re)init, if necessary, the internal cipher $engine
+ *
+ * _setup() will be called each time if $changed === true
+ * typically this happens when using one or more of following public methods:
+ *
+ * - setKey()
+ *
+ * - setNonce()
+ *
+ * - First run of encrypt() / decrypt() with no init-settings
+ $private['privateKeyAlgorithm']['parameters'] = new ASN1\Element(substr($key, $temp['start'], $temp['length']));
+ }
+ if (is_array(static::OID_NAME)) {
+ if (!in_array($private['privateKeyAlgorithm']['algorithm'], static::OID_NAME)) {
+ throw new UnsupportedAlgorithmException($private['privateKeyAlgorithm']['algorithm'] . ' is not a supported key type');
+ }
+ } else {
+ if ($private['privateKeyAlgorithm']['algorithm'] != static::OID_NAME) {
+ throw new UnsupportedAlgorithmException('Only ' . static::OID_NAME . ' keys are supported; this is a ' . $private['privateKeyAlgorithm']['algorithm'] . ' key');
+ }
+ }
+ if (isset($private['publicKey'])) {
+ if ($private['publicKey'][0] != "\0") {
+ throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . bin2hex($private['publicKey'][0]));
+ throw new \UnexpectedValueException('Human readable string claims private key but DER encoded string claims public key');
+ }
+
+ if ($public['publicKey'][0] != "\0") {
+ throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . bin2hex($public['publicKey'][0]));
+ }
+ if (is_array(static::OID_NAME)) {
+ if (!in_array($public['publicKeyAlgorithm']['algorithm'], static::OID_NAME)) {
+ throw new UnsupportedAlgorithmException($public['publicKeyAlgorithm']['algorithm'] . ' is not a supported key type');
+ }
+ } else {
+ if ($public['publicKeyAlgorithm']['algorithm'] != static::OID_NAME) {
+ throw new UnsupportedAlgorithmException('Only ' . static::OID_NAME . ' keys are supported; this is a ' . $public['publicKeyAlgorithm']['algorithm'] . ' key');
+ }
+ }
+ if (isset($public['publicKeyAlgorithm']['parameters']) && !$public['publicKeyAlgorithm']['parameters'] instanceof ASN1\Element && isset($decoded[0]['content'][0]['content'][1])) {
+ * Returns whether or not the algorithm uses a nonce
+ *
+ * @return bool
+ */
+ public function usesNonce()
+ {
+ return $this->mode == self::MODE_GCM;
+ }
+
+ /**
+ * Returns the current key length in bits
+ *
+ * @return int
+ */
+ public function getKeyLength()
+ {
+ return $this->key_length << 3;
+ }
+
+ /**
+ * Returns the current block length in bits
+ *
+ * @return int
+ */
+ public function getBlockLength()
+ {
+ return $this->block_size << 3;
+ }
+
+ /**
+ * Returns the current block length in bytes
+ *
+ * @return int
+ */
+ public function getBlockLengthInBytes()
+ {
+ return $this->block_size;
+ }
+
+ /**
+ * Sets the key length.
+ *
+ * Keys with explicitly set lengths need to be treated accordingly
+ *
+ * @param int $length
+ */
+ public function setKeyLength($length)
+ {
+ $this->explicit_key_length = $length >> 3;
+
+ if (is_string($this->key) && strlen($this->key) != $this->explicit_key_length) {
+ $this->key = false;
+ throw new InconsistentSetupException('Key has already been set and is not ' . $this->explicit_key_length . ' bytes long');
+ }
+ }
+
+ /**
+ * Sets the key.
+ *
+ * The min/max length(s) of the key depends on the cipher which is used.
+ * If the key not fits the length(s) of the cipher it will paded with null bytes
+ * up to the closest valid key length. If the key is more than max length,
+ * we trim the excess bits.
+ *
+ * If the key is not explicitly set, it'll be assumed to be all null bytes.
+ *
+ * {@internal Could, but not must, extend by the child Crypt_* class}
+ *
+ * @param string $key
+ */
+ public function setKey($key)
+ {
+ if ($this->explicit_key_length !== false && strlen($key) != $this->explicit_key_length) {
+ throw new InconsistentSetupException('Key length has already been set to ' . $this->explicit_key_length . ' bytes and this key is ' . strlen($key) . ' bytes');
+ }
+
+ $this->key = $key;
+ $this->key_length = strlen($key);
+ $this->setEngine();
+ }
+
+ /**
+ * Sets the password.
+ *
+ * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
+ * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
+ * $hash, $salt, $count, $dkLen
+ *
+ * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
+ * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
+ * it is.
+ *
+ * {@internal Could, but not must, extend by the child Crypt_* class}
+ *
+ * @see self::encrypt()
+ * @param string $ciphertext
+ * @return string $plaintext
+ * @throws \LengthException if we're inside a block cipher and the ciphertext length is not a multiple of the block size
+ */
+ public function decrypt($ciphertext)
+ {
+ if ($this->paddable && strlen($ciphertext) % $this->block_size) {
+ throw new \LengthException('The ciphertext length (' . strlen($ciphertext) . ') needs to be a multiple of the block size (' . $this->block_size . ')');
+ }
+ $this->setup();
+
+ if ($this->mode == self::MODE_GCM || isset($this->poly1305Key)) {
+ if ($this->oldtag === false) {
+ throw new InsufficientSetupException('Authentication Tag has not been set');
+ throw new \InvalidArgumentException('Valid parameters are either: two BigInteger\'s (prime and base), a single integer (the length of the prime; base is assumed to be 2) or a string');
+ }
+ switch ($args[0]) {
+ // see http://tools.ietf.org/html/rfc2409#section-6.2 and
+ // http://tools.ietf.org/html/rfc2412, appendex E
+ * Calling this function after setting the key has no effect until the next
+ * \phpseclib3\Crypt\RC2::setKey() call.
+ *
+ * @param int $length in bits
+ * @throws \LengthException if the key length isn't supported
+ */
+ public function setKeyLength($length)
+ {
+ if ($length < 8 || $length > 1024) {
+ throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 1024 bits, inclusive, are supported');
+ * @throws \LengthException if the key length isn't supported
+ */
+ public function setKey($key, $t1 = false)
+ {
+ $this->orig_key = $key;
+
+ if ($t1 === false) {
+ $t1 = $this->default_key_length;
+ }
+
+ if ($t1 < 1 || $t1 > 1024) {
+ throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 1024 bits, inclusive, are supported');
+ }
+
+ $this->current_key_length = $t1;
+ if (strlen($key) < 1 || strlen($key) > 128) {
+ throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes between 8 and 1024 bits, inclusive, are supported');
+ }
+
+ $t = strlen($key);
+
+ // The mcrypt RC2 implementation only supports effective key length
+ // of 1024 bits. It is however possible to handle effective key
+ // lengths in range 1..1024 by expanding the key and applying
+ // inverse pitable mapping to the first byte before submitting it
+ // to mcrypt.
+
+ // Key expansion.
+ $l = array_values(unpack('C*', $key));
+ $t8 = ($t1 + 7) >> 3;
+ $tm = 0xFF >> (8 * $t8 - $t1);
+
+ // Expand key.
+ $pitable = self::$pitable;
+ for ($i = $t; $i < 128; $i++) {
+ $l[$i] = $pitable[$l[$i - 1] + $l[$i - $t]];
+ }
+ $i = 128 - $t8;
+ $l[$i] = $pitable[$l[$i] & $tm];
+ while ($i--) {
+ $l[$i] = $pitable[$l[$i + 1] ^ $l[$i + $t8]];
+ }
+
+ // Prepare the key for mcrypt.
+ $l[0] = self::$invpitable[$l[0]];
+ array_unshift($l, 'C*');
+
+ $this->key = pack(...$l);
+ $this->key_length = strlen($this->key);
+ $this->changed = $this->nonIVChanged = true;
+ $this->setEngine();
+ }
+
+ /**
+ * Encrypts a message.
+ *
+ * Mostly a wrapper for \phpseclib3\Crypt\Common\SymmetricKey::encrypt, with some additional OpenSSL handling code
+ *
+ * @see self::decrypt()
+ * @param string $plaintext
+ * @return string $ciphertext
+ */
+ public function encrypt($plaintext)
+ {
+ if ($this->engine == self::ENGINE_OPENSSL) {
+ $temp = $this->key;
+ $this->key = $this->orig_key;
+ $result = parent::encrypt($plaintext);
+ $this->key = $temp;
+ return $result;
+ }
+
+ return parent::encrypt($plaintext);
+ }
+
+ /**
+ * Decrypts a message.
+ *
+ * Mostly a wrapper for \phpseclib3\Crypt\Common\SymmetricKey::decrypt, with some additional OpenSSL handling code
+ * {@internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
+ * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
+ * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
+ * of that, we'll just precompute it once.}
+ *
+ * @see self::setBlockLength()
+ * @var int
+ */
+ private $Nb = 4;
+
+ /**
+ * The Key Length (in bytes)
+ *
+ * {@internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk
+ * because the encryption / decryption / key schedule creation requires this number and not $key_length. We could
+ * derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
+ * of that, we'll just precompute it once.}
+ *
+ * @see self::setKeyLength()
+ * @var int
+ */
+ protected $key_length = 16;
+
+ /**
+ * The Key Length divided by 32
+ *
+ * @see self::setKeyLength()
+ * @var int
+ * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
+ */
+ private $Nk = 4;
+
+ /**
+ * The Number of Rounds
+ *
+ * {@internal The max value is 14, the min value is 10.}
+ *
+ * @var int
+ */
+ private $Nr;
+
+ /**
+ * Shift offsets
+ *
+ * @var array
+ */
+ private $c;
+
+ /**
+ * Holds the last used key- and block_size information
+ *
+ * @var array
+ */
+ private $kl;
+
+ /**
+ * Default Constructor.
+ *
+ * @param string $mode
+ * @throws \InvalidArgumentException if an invalid / unsupported mode is provided
+ */
+ public function __construct($mode)
+ {
+ parent::__construct($mode);
+
+ if ($this->mode == self::MODE_STREAM) {
+ throw new BadModeException('Block ciphers cannot be ran in stream mode');
+ }
+ }
+
+ /**
+ * Sets the key length.
+ *
+ * Valid key lengths are 128, 160, 192, 224, and 256.
+ *
+ * Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined
+ * and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to
+ * 192/256 bits as, for example, mcrypt will do.
+ *
+ * That said, if you want be compatible with other Rijndael and AES implementations,
+ * you should not setKeyLength(160) or setKeyLength(224).
+ *
+ * Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use
+ * the mcrypt php extension, even if available.
+ * This results then in slower encryption.
+ *
+ * @throws \LengthException if the key length is invalid
+ * @param int $length
+ */
+ public function setKeyLength($length)
+ {
+ switch ($length) {
+ case 128:
+ case 160:
+ case 192:
+ case 224:
+ case 256:
+ $this->key_length = $length >> 3;
+ break;
+ default:
+ throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes 128, 160, 192, 224 or 256 bits are supported');
+ }
+
+ parent::setKeyLength($length);
+ }
+
+ /**
+ * Sets the key.
+ *
+ * Rijndael supports five different key lengths
+ *
+ * @see setKeyLength()
+ * @param string $key
+ * @throws \LengthException if the key length isn't supported
+ */
+ public function setKey($key)
+ {
+ switch (strlen($key)) {
+ case 16:
+ case 20:
+ case 24:
+ case 28:
+ case 32:
+ break;
+ default:
+ throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 20, 24, 28 or 32 are supported');
+ }
+
+ parent::setKey($key);
+ }
+
+ /**
+ * Sets the block length
+ *
+ * Valid block lengths are 128, 160, 192, 224, and 256.
+ *
+ * @param int $length
+ */
+ public function setBlockLength($length)
+ {
+ switch ($length) {
+ case 128:
+ case 160:
+ case 192:
+ case 224:
+ case 256:
+ break;
+ default:
+ throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes 128, 160, 192, 224 or 256 bits are supported');
+ }
+
+ $this->Nb = $length >> 5;
+ $this->block_size = $length >> 3;
+ $this->changed = $this->nonIVChanged = true;
+ $this->setEngine();
+ }
+
+ /**
+ * Test for engine validity
+ *
+ * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
+ * @throws \LengthException if the key length is invalid
+ * @param string $key
+ */
+ public function setKey($key)
+ {
+ if ($this->explicit_key_length !== false && strlen($key) != $this->explicit_key_length) {
+ throw new \LengthException('Key length has already been set to ' . $this->explicit_key_length . ' bytes and this key is ' . strlen($key) . ' bytes');
+ }
+
+ switch (strlen($key)) {
+ case 16:
+ $key .= substr($key, 0, 8);
+ break;
+ case 24:
+ break;
+ default:
+ throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16 or 24 are supported');
+ * Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the
+ * $t parameter is distributability. BigInteger::randomPrime() can be distributed across multiple pageloads
+ * on a website instead of just one.
+ *
+ * @param int|bool $t
+ * @return bool
+ */
+ public function isPrime($t = false)
+ {
+ if (!$t) {
+ $t = $this->setupIsPrime();
+ }
+ return $this->testPrimality($t);
+ }
+
+ /**
+ * Performs a few preliminary checks on root
+ *
+ * @param int $n
+ * @return Engine
+ */
+ protected function rootHelper($n)
+ {
+ if ($n < 1) {
+ return clone static::$zero[static::class];
+ } // we want positive exponents
+ if ($this->compare(static::$one[static::class]) < 0) {
+ return clone static::$zero[static::class];
+ } // we want positive numbers
+ if ($this->compare(static::$two[static::class]) < 0) {
+ return clone static::$one[static::class];
+ } // n-th root of 1 or 2 is 1
+
+ return $this->rootInner($n);
+ }
+
+ /**
+ * Calculates the nth root of a biginteger.
+ *
+ * Returns the nth root of a positive biginteger, where n defaults to 2
+ *
+ * {@internal This function is based off of {@link http://mathforum.org/library/drmath/view/52605.html this page} and {@link http://stackoverflow.com/questions/11242920/calculating-nth-root-with-bcmath-in-php this stackoverflow question}.}
+ *
+ * @param int $n
+ * @return Engine
+ */
+ protected function rootInner($n)
+ {
+ $n = new static($n);
+
+ // g is our guess number
+ $g = static::$two[static::class];
+ // while (g^n < num) g=g*2
+ while ($g->pow($n)->compare($this) < 0) {
+ $g = $g->multiply(static::$two[static::class]);
+ }
+ // if (g^n==num) num is a power of 2, we're lucky, end of job
+ // == 0 bccomp(bcpow($g, $n), $n->value)==0
+ if ($g->pow($n)->equals($this) > 0) {
+ $root = $g;
+ return $this->normalize($root);
+ }
+
+ // if we're here num wasn't a power of 2 :(
+ $og = $g; // og means original guess and here is our upper bound
+ $g = $g->divide(static::$two[static::class])[0]; // g is set to be our lower bound
+ $step = $og->subtract($g)->divide(static::$two[static::class])[0]; // step is the half of upper bound - lower bound
+ $g = $g->add($step); // we start at lower bound + step , basically in the middle of our interval
+
+ // while step>1
+
+ while ($step->compare(static::$one[static::class]) == 1) {
+ if (isset($request_id) && $this->use_request_id && $packet_id != $request_id) {
+ $this->requestBuffer[$packet_id] = [
+ 'packet_type' => $this->packet_type,
+ 'packet' => $packet
+ ];
+ return $this->get_sftp_packet($request_id);
+ }
+
+ return $packet;
+ }
+
+ /**
+ * Logs data packets
+ *
+ * Makes sure that only the last 1MB worth of packets will be logged
+ *
+ * @param string $message_number
+ * @param string $message
+ */
+ private function append_log($message_number, $message)
+ {
+ $this->append_log_helper(
+ NET_SFTP_LOGGING,
+ $message_number,
+ $message,
+ $this->packet_type_log,
+ $this->packet_log,
+ $this->log_size,
+ $this->realtime_log_file,
+ $this->realtime_log_wrap,
+ $this->realtime_log_size
+ );
+ }
+
+ /**
+ * Returns a log of the packets that have been sent and received.
+ *
+ * Returns a string if NET_SFTP_LOGGING == self::LOG_COMPLEX, an array if NET_SFTP_LOGGING == self::LOG_SIMPLE and false if !defined('NET_SFTP_LOGGING')
+ protected function sublogin($username, ...$args)
+ {
+ if (!($this->bitmap & self::MASK_CONSTRUCTOR)) {
+ $this->connect();
+ }
+
+ if (empty($args)) {
+ return $this->login_helper($username);
+ }
+
+ foreach ($args as $arg) {
+ switch (true) {
+ case $arg instanceof PublicKey:
+ throw new \UnexpectedValueException('A PublicKey object was passed to the login method instead of a PrivateKey object');
+ case $arg instanceof PrivateKey:
+ case $arg instanceof Agent:
+ case is_array($arg):
+ case Strings::is_stringable($arg):
+ break;
+ default:
+ throw new \UnexpectedValueException('$password needs to either be an instance of \phpseclib3\Crypt\Common\PrivateKey, \System\SSH\Agent, an array or a string');
+ }
+ }
+
+ while (count($args)) {
+ if (!$this->auth_methods_to_continue || !$this->smartMFA) {
+ $newargs = $args;
+ $args = [];
+ } else {
+ $newargs = [];
+ foreach ($this->auth_methods_to_continue as $method) {
+ switch ($method) {
+ case 'publickey':
+ foreach ($args as $key => $arg) {
+ if ($arg instanceof PrivateKey || $arg instanceof Agent) {
+ $newargs[] = $arg;
+ unset($args[$key]);
+ break;
+ }
+ }
+ break;
+ case 'keyboard-interactive':
+ $hasArray = $hasString = false;
+ foreach ($args as $arg) {
+ if ($hasArray || is_array($arg)) {
+ $hasArray = true;
+ break;
+ }
+ if ($hasString || Strings::is_stringable($arg)) {
+ $hasString = true;
+ break;
+ }
+ }
+ if ($hasArray && $hasString) {
+ foreach ($args as $key => $arg) {
+ if (is_array($arg)) {
+ $newargs[] = $arg;
+ break 2;
+ }
+ }
+ }
+ // fall-through
+ case 'password':
+ foreach ($args as $key => $arg) {
+ $newargs[] = $arg;
+ unset($args[$key]);
+ break;
+ }
+ }
+ }
+ }
+
+ if (!count($newargs)) {
+ return false;
+ }
+
+ foreach ($newargs as $arg) {
+ if ($this->login_helper($username, $arg)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Login Helper
+ *
+ * {@internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
+ if (is_resource($this->fsock) && get_resource_type($this->fsock) === 'stream') {
+ fclose($this->fsock);
+ }
+
+ return false;
+ }
+
+ /**
+ * Define Array
+ *
+ * Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of
+ * named constants from it, using the value as the name of the constant and the index as the value of the constant.
+ * If any of the constants that would be defined already exists, none of the constants will be defined.
+ *
+ * @param mixed[] ...$args
+ * @access protected
+ */
+ protected function define_array(...$args)
+ {
+ foreach ($args as $arg) {
+ foreach ($arg as $key => $value) {
+ if (!defined($value)) {
+ define($value, $key);
+ } else {
+ break 2;
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns a log of the packets that have been sent and received.
+ *
+ * Returns a string if NET_SSH2_LOGGING == self::LOG_COMPLEX, an array if NET_SSH2_LOGGING == self::LOG_SIMPLE and false if !defined('NET_SSH2_LOGGING')