[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/vendor/phpseclib/phpseclib/phpseclib/Crypt/ -> Blowfish.php (source)

   1  <?php
   2  
   3  /**
   4   * Pure-PHP implementation of Blowfish.
   5   *
   6   * Uses mcrypt, if available, and an internal implementation, otherwise.
   7   *
   8   * PHP version 5
   9   *
  10   * Useful resources are as follows:
  11   *
  12   *  - {@link http://en.wikipedia.org/wiki/Blowfish_(cipher) Wikipedia description of Blowfish}
  13   *
  14   * # An overview of bcrypt vs Blowfish
  15   *
  16   * OpenSSH private keys use a customized version of bcrypt. Specifically, instead of
  17   * encrypting OrpheanBeholderScryDoubt 64 times OpenSSH's bcrypt variant encrypts
  18   * OxychromaticBlowfishSwatDynamite 64 times. so we can't use crypt().
  19   *
  20   * bcrypt is basically Blowfish but instead of performing the key expansion once it performs
  21   * the expansion 129 times for each round, with the first key expansion interleaving the salt
  22   * and password. This renders OpenSSL unusable and forces us to use a pure-PHP implementation
  23   * of blowfish.
  24   *
  25   * # phpseclib's four different _encryptBlock() implementations
  26   *
  27   * When using Blowfish as an encryption algorithm, _encryptBlock() is called 9 + 512 +
  28   * (the number of blocks in the plaintext) times.
  29   *
  30   * Each of the first 9 calls to _encryptBlock() modify the P-array. Each of the next 512
  31   * calls modify the S-boxes. The remaining _encryptBlock() calls operate on the plaintext to
  32   * produce the ciphertext. In the pure-PHP implementation of Blowfish these remaining
  33   * _encryptBlock() calls are highly optimized through the use of eval(). Among other things,
  34   * P-array lookups are eliminated by hard-coding the key-dependent P-array values, and thus we
  35   * have explained 2 of the 4 different _encryptBlock() implementations.
  36   *
  37   * With bcrypt things are a bit different. _encryptBlock() is called 1,079,296 times,
  38   * assuming 16 rounds (which is what OpenSSH's bcrypt defaults to). The eval()-optimized
  39   * _encryptBlock() isn't as beneficial because the P-array values are not constant. Well, they
  40   * are constant, but only for, at most, 777 _encryptBlock() calls, which is equivalent to ~6KB
  41   * of data. The average length of back to back _encryptBlock() calls with a fixed P-array is
  42   * 514.12, which is ~4KB of data. Creating an eval()-optimized _encryptBlock() has an upfront
  43   * cost, which is CPU dependent and is probably not going to be worth it for just ~4KB of
  44   * data. Conseqeuently, bcrypt does not benefit from the eval()-optimized _encryptBlock().
  45   *
  46   * The regular _encryptBlock() does unpack() and pack() on every call, as well, and that can
  47   * begin to add up after one million function calls.
  48   *
  49   * In theory, one might think that it might be beneficial to rewrite all block ciphers so
  50   * that, instead of passing strings to _encryptBlock(), you convert the string to an array of
  51   * integers and then pass successive subarrays of that array to _encryptBlock. This, however,
  52   * kills PHP's memory use. Like let's say you have a 1MB long string. After doing
  53   * $in = str_repeat('a', 1024 * 1024); PHP's memory utilization jumps up by ~1MB. After doing
  54   * $blocks = str_split($in, 4); it jumps up by an additional ~16MB. After
  55   * $blocks = array_map(fn($x) => unpack('N*', $x), $blocks); it jumps up by an additional
  56   * ~90MB, yielding a 106x increase in memory usage. Consequently, it bcrypt calls a different
  57   * _encryptBlock() then the regular Blowfish does. That said, the Blowfish _encryptBlock() is
  58   * basically just a thin wrapper around the bcrypt _encryptBlock(), so there's that.
  59   *
  60   * This explains 3 of the 4 _encryptBlock() implementations. the last _encryptBlock()
  61   * implementation can best be understood by doing Ctrl + F and searching for where
  62   * CRYPT_BASE_USE_REG_INTVAL is defined.
  63   *
  64   * # phpseclib's three different _setupKey() implementations
  65   *
  66   * Every bcrypt round is the equivalent of encrypting 512KB of data. Since OpenSSH uses 16
  67   * rounds by default that's ~8MB of data that's essentially being encrypted whenever
  68   * you use bcrypt. That's a lot of data, however, bcrypt operates within tighter constraints
  69   * than regular Blowfish, so we can use that to our advantage. In particular, whereas Blowfish
  70   * supports variable length keys, in bcrypt, the initial "key" is the sha512 hash of the
  71   * password. sha512 hashes are 512 bits or 64 bytes long and thus the bcrypt keys are of a
  72   * fixed length whereas Blowfish keys are not of a fixed length.
  73   *
  74   * bcrypt actually has two different key expansion steps. The first one (expandstate) is
  75   * constantly XOR'ing every _encryptBlock() parameter against the salt prior _encryptBlock()'s
  76   * being called. The second one (expand0state) is more similar to Blowfish's _setupKey()
  77   * but it can still use the fixed length key optimization discussed above and can do away with
  78   * the pack() / unpack() calls.
  79   *
  80   * I suppose _setupKey() could be made to be a thin wrapper around expandstate() but idk it's
  81   * just a lot of work for very marginal benefits as _setupKey() is only called once for
  82   * regular Blowfish vs the 128 times it's called --per round-- with bcrypt.
  83   *
  84   * # blowfish + bcrypt in the same class
  85   *
  86   * Altho there's a lot of Blowfish code that bcrypt doesn't re-use, bcrypt does re-use the
  87   * initial S-boxes, the initial P-array and the int-only _encryptBlock() implementation.
  88   *
  89   * # Credit
  90   *
  91   * phpseclib's bcrypt implementation is based losely off of OpenSSH's implementation:
  92   *
  93   * https://github.com/openssh/openssh-portable/blob/master/openbsd-compat/bcrypt_pbkdf.c
  94   *
  95   * Here's a short example of how to use this library:
  96   * <code>
  97   * <?php
  98   *    include 'vendor/autoload.php';
  99   *
 100   *    $blowfish = new \phpseclib\Crypt\Blowfish();
 101   *
 102   *    $blowfish->setKey('12345678901234567890123456789012');
 103   *
 104   *    $plaintext = str_repeat('a', 1024);
 105   *
 106   *    echo $blowfish->decrypt($blowfish->encrypt($plaintext));
 107   * ?>
 108   * </code>
 109   *
 110   * @category  Crypt
 111   * @package   Blowfish
 112   * @author    Jim Wigginton <terrafrost@php.net>
 113   * @author    Hans-Juergen Petrich <petrich@tronic-media.com>
 114   * @copyright 2007 Jim Wigginton
 115   * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 116   * @link      http://phpseclib.sourceforge.net
 117   */
 118  
 119  namespace phpseclib\Crypt;
 120  
 121  /**
 122   * Pure-PHP implementation of Blowfish.
 123   *
 124   * @package Blowfish
 125   * @author  Jim Wigginton <terrafrost@php.net>
 126   * @author  Hans-Juergen Petrich <petrich@tronic-media.com>
 127   * @access  public
 128   */
 129  class Blowfish extends Base
 130  {
 131      /**
 132       * Block Length of the cipher
 133       *
 134       * @see \phpseclib\Crypt\Base::block_size
 135       * @var int
 136       * @access private
 137       */
 138      var $block_size = 8;
 139  
 140      /**
 141       * The mcrypt specific name of the cipher
 142       *
 143       * @see \phpseclib\Crypt\Base::cipher_name_mcrypt
 144       * @var string
 145       * @access private
 146       */
 147      var $cipher_name_mcrypt = 'blowfish';
 148  
 149      /**
 150       * Optimizing value while CFB-encrypting
 151       *
 152       * @see \phpseclib\Crypt\Base::cfb_init_len
 153       * @var int
 154       * @access private
 155       */
 156      var $cfb_init_len = 500;
 157  
 158      /**
 159       * SHA512 Object
 160       *
 161       * @see self::bcrypt_pbkdf
 162       * @var object
 163       * @access private
 164       */
 165      var $sha512;
 166  
 167      /**
 168       * The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each
 169       *
 170       * S-Box 0
 171       *
 172       * @access private
 173       * @var    array
 174       */
 175      var $sbox0 = array(
 176          0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
 177          0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
 178          0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
 179          0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
 180          0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
 181          0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
 182          0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
 183          0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
 184          0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
 185          0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
 186          0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
 187          0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
 188          0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
 189          0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
 190          0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
 191          0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
 192          0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
 193          0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
 194          0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
 195          0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
 196          0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
 197          0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
 198          0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
 199          0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
 200          0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
 201          0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
 202          0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
 203          0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
 204          0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
 205          0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
 206          0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
 207          0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
 208      );
 209  
 210      /**
 211       * S-Box 1
 212       *
 213       * @access private
 214       * @var    array
 215       */
 216      var $sbox1 = array(
 217          0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
 218          0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
 219          0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
 220          0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
 221          0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
 222          0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
 223          0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
 224          0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
 225          0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
 226          0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
 227          0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
 228          0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
 229          0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
 230          0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
 231          0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
 232          0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
 233          0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
 234          0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
 235          0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
 236          0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
 237          0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
 238          0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
 239          0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
 240          0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
 241          0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
 242          0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
 243          0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
 244          0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
 245          0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
 246          0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
 247          0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
 248          0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
 249      );
 250  
 251      /**
 252       * S-Box 2
 253       *
 254       * @access private
 255       * @var    array
 256       */
 257      var $sbox2 = array(
 258          0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
 259          0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
 260          0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
 261          0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
 262          0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
 263          0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
 264          0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
 265          0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
 266          0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
 267          0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
 268          0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
 269          0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
 270          0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
 271          0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
 272          0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
 273          0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
 274          0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
 275          0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
 276          0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
 277          0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
 278          0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
 279          0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
 280          0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
 281          0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
 282          0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
 283          0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
 284          0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
 285          0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
 286          0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
 287          0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
 288          0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
 289          0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
 290      );
 291  
 292      /**
 293       * S-Box 3
 294       *
 295       * @access private
 296       * @var    array
 297       */
 298      var $sbox3 = array(
 299          0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
 300          0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
 301          0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
 302          0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
 303          0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
 304          0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
 305          0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
 306          0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
 307          0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
 308          0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
 309          0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
 310          0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
 311          0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
 312          0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
 313          0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
 314          0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
 315          0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
 316          0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
 317          0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
 318          0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
 319          0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
 320          0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
 321          0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
 322          0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
 323          0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
 324          0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
 325          0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
 326          0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
 327          0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
 328          0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
 329          0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
 330          0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
 331      );
 332  
 333      /**
 334       * P-Array consists of 18 32-bit subkeys
 335       *
 336       * @var array
 337       * @access private
 338       */
 339      var $parray = array(
 340          0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
 341          0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
 342          0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
 343      );
 344  
 345      /**
 346       * The BCTX-working Array
 347       *
 348       * Holds the expanded key [p] and the key-depended s-boxes [sb]
 349       *
 350       * @var array
 351       * @access private
 352       */
 353      var $bctx;
 354  
 355      /**
 356       * Holds the last used key
 357       *
 358       * @var array
 359       * @access private
 360       */
 361      var $kl;
 362  
 363      /**
 364       * The Key Length (in bytes)
 365       *
 366       * @see \phpseclib\Crypt\Base::setKeyLength()
 367       * @var int
 368       * @access private
 369       * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16.  Exists in conjunction with $Nk
 370       *    because the encryption / decryption / key schedule creation requires this number and not $key_length.  We could
 371       *    derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
 372       *    of that, we'll just precompute it once.
 373       */
 374      var $key_length = 16;
 375  
 376      /**
 377       * Default Constructor.
 378       *
 379       * Determines whether or not the mcrypt extension should be used.
 380       *
 381       * $mode could be:
 382       *
 383       * - CRYPT_MODE_ECB
 384       *
 385       * - CRYPT_MODE_CBC
 386       *
 387       * - CRYPT_MODE_CTR
 388       *
 389       * - CRYPT_MODE_CFB
 390       *
 391       * - CRYPT_MODE_OFB
 392       *
 393       * (or the alias constants of the chosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...)
 394       *
 395       * If not explicitly set, CRYPT_MODE_CBC will be used.
 396       *
 397       * @param int $mode
 398       * @access public
 399       */
 400      function __construct($mode = self::MODE_CBC)
 401      {
 402          parent::__construct($mode);
 403  
 404          $this->sbox0 = array_map('intval', $this->sbox0);
 405          $this->sbox1 = array_map('intval', $this->sbox1);
 406          $this->sbox2 = array_map('intval', $this->sbox2);
 407          $this->sbox3 = array_map('intval', $this->sbox3);
 408          $this->parray = array_map('intval', $this->parray);
 409      }
 410  
 411      /**
 412       * Sets the key length.
 413       *
 414       * Key lengths can be between 32 and 448 bits.
 415       *
 416       * @access public
 417       * @param int $length
 418       */
 419      function setKeyLength($length)
 420      {
 421          if ($length < 32) {
 422              $this->key_length = 4;
 423          } elseif ($length > 448) {
 424              $this->key_length = 56;
 425          } else {
 426              $this->key_length = $length >> 3;
 427          }
 428  
 429          parent::setKeyLength($length);
 430      }
 431  
 432      /**
 433       * Test for engine validity
 434       *
 435       * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Base::isValidEngine()
 436       *
 437       * @see \phpseclib\Crypt\Base::isValidEngine()
 438       * @param int $engine
 439       * @access public
 440       * @return bool
 441       */
 442      function isValidEngine($engine)
 443      {
 444          if ($engine == self::ENGINE_OPENSSL) {
 445              // quoting https://www.openssl.org/news/openssl-3.0-notes.html, OpenSSL 3.0.1
 446              // "Moved all variations of the EVP ciphers CAST5, BF, IDEA, SEED, RC2, RC4, RC5, and DES to the legacy provider"
 447              // in theory openssl_get_cipher_methods() should catch this but, on GitHub Actions, at least, it does not
 448              if (defined('OPENSSL_VERSION_TEXT') && version_compare(preg_replace('#OpenSSL (\d+\.\d+\.\d+) .*#', '$1', OPENSSL_VERSION_TEXT), '3.0.1', '>=')) {
 449                  return false;
 450              }
 451              if (version_compare(PHP_VERSION, '5.3.7') < 0 && $this->key_length != 16) {
 452                  return false;
 453              }
 454              if ($this->key_length < 16) {
 455                  return false;
 456              }
 457              $this->cipher_name_openssl_ecb = 'bf-ecb';
 458              $this->cipher_name_openssl = 'bf-' . $this->_openssl_translate_mode();
 459          }
 460  
 461          return parent::isValidEngine($engine);
 462      }
 463  
 464      /**
 465       * Setup the key (expansion)
 466       *
 467       * @see \phpseclib\Crypt\Base::_setupKey()
 468       * @access private
 469       */
 470      function _setupKey()
 471      {
 472          if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
 473              // already expanded
 474              return;
 475          }
 476          $this->kl = array('key' => $this->key);
 477  
 478          /* key-expanding p[] and S-Box building sb[] */
 479          $this->bctx = array(
 480              'p'  => array(),
 481              'sb' => array(
 482                  $this->sbox0,
 483                  $this->sbox1,
 484                  $this->sbox2,
 485                  $this->sbox3
 486              )
 487          );
 488  
 489          // unpack binary string in unsigned chars
 490          $key  = array_values(unpack('C*', $this->key));
 491          $keyl = count($key);
 492          // with bcrypt $keyl will always be 16 (because the key is the sha512 of the key you provide)
 493          for ($j = 0, $i = 0; $i < 18; ++$i) {
 494              // xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ...
 495              for ($data = 0, $k = 0; $k < 4; ++$k) {
 496                  $data = ($data << 8) | $key[$j];
 497                  if (++$j >= $keyl) {
 498                      $j = 0;
 499                  }
 500              }
 501              $this->bctx['p'][] = $this->parray[$i] ^ intval($data);
 502          }
 503  
 504          // encrypt the zero-string, replace P1 and P2 with the encrypted data,
 505          // encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys
 506          $data = "\0\0\0\0\0\0\0\0";
 507          for ($i = 0; $i < 18; $i += 2) {
 508              list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
 509              $this->bctx['p'][$i    ] = $l;
 510              $this->bctx['p'][$i + 1] = $r;
 511          }
 512          for ($i = 0; $i < 4; ++$i) {
 513              for ($j = 0; $j < 256; $j += 2) {
 514                  list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
 515                  $this->bctx['sb'][$i][$j    ] = $l;
 516                  $this->bctx['sb'][$i][$j + 1] = $r;
 517              }
 518          }
 519      }
 520  
 521      /**
 522       * bcrypt
 523       *
 524       * @param string $sha2pass
 525       * @param string $sha2salt
 526       * @access private
 527       * @return string
 528       */
 529      function _bcrypt_hash($sha2pass, $sha2salt)
 530      {
 531          $p = $this->parray;
 532          $sbox0 = $this->sbox0;
 533          $sbox1 = $this->sbox1;
 534          $sbox2 = $this->sbox2;
 535          $sbox3 = $this->sbox3;
 536  
 537          $cdata = array_values(unpack('N*', 'OxychromaticBlowfishSwatDynamite'));
 538          $sha2pass = array_values(unpack('N*', $sha2pass));
 539          $sha2salt = array_values(unpack('N*', $sha2salt));
 540  
 541          $this->_expandstate($sha2salt, $sha2pass, $sbox0, $sbox1, $sbox2, $sbox3, $p);
 542          for ($i = 0; $i < 64; $i++) {
 543              $this->_expand0state($sha2salt, $sbox0, $sbox1, $sbox2, $sbox3, $p);
 544              $this->_expand0state($sha2pass, $sbox0, $sbox1, $sbox2, $sbox3, $p);
 545          }
 546  
 547          for ($i = 0; $i < 64; $i++) {
 548              for ($j = 0; $j < 8; $j+= 2) { // count($cdata) == 8
 549                  list($cdata[$j], $cdata[$j + 1]) = $this->_encryptBlockHelperFast($cdata[$j], $cdata[$j + 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 550              }
 551          }
 552  
 553          $output = '';
 554          for ($i = 0; $i < count($cdata); $i++) {
 555              $output.= pack('L*', $cdata[$i]);
 556          }
 557          return $output;
 558      }
 559  
 560      /**
 561       * Performs OpenSSH-style bcrypt
 562       *
 563       * @param string $pass
 564       * @param string $salt
 565       * @param int $keylen
 566       * @param int $rounds
 567       * @access public
 568       * @return false|string
 569       */
 570      function bcrypt_pbkdf($pass, $salt, $keylen, $rounds)
 571      {
 572          if (PHP_INT_SIZE == 4) {
 573              user_error('bcrypt is far too slow to be practical on 32-bit versions of PHP');
 574              return false;
 575          }
 576  
 577          if (!isset($this->sha512)) {
 578              $this->sha512 = new Hash('sha512');
 579          }
 580  
 581          $sha2pass = $this->sha512->hash($pass);
 582          $results = array();
 583          $count = 1;
 584          while (32 * count($results) < $keylen) {
 585              $countsalt = $salt . pack('N', $count++);
 586              $sha2salt = $this->sha512->hash($countsalt);
 587              $out = $tmpout = $this->_bcrypt_hash($sha2pass, $sha2salt);
 588              for ($i = 1; $i < $rounds; $i++) {
 589                  $sha2salt = $this->sha512->hash($tmpout);
 590                  $tmpout = $this->_bcrypt_hash($sha2pass, $sha2salt);
 591                  $out^= $tmpout;
 592              }
 593              $results[] = $out;
 594          }
 595          $output = '';
 596          for ($i = 0; $i < 32; $i++) {
 597              foreach ($results as $result) {
 598                  $output.= $result[$i];
 599              }
 600          }
 601          return substr($output, 0, $keylen);
 602      }
 603  
 604      /**
 605       * Key expansion without salt
 606       *
 607       * @access private
 608       * @param int[] $key
 609       * @param int[] $sbox0
 610       * @param int[] $sbox1
 611       * @param int[] $sbox2
 612       * @param int[] $sbox3
 613       * @param int[] $p
 614       * @see self::_bcrypt_hash()
 615       */
 616      function _expand0state($key, &$sbox0, &$sbox1, &$sbox2, &$sbox3, &$p)
 617      {
 618          // expand0state is basically the same thing as this:
 619          //return $this->_expandstate(array_fill(0, 16, 0), $key);
 620          // but this separate function eliminates a bunch of XORs and array lookups
 621  
 622          $p = array(
 623              $p[0] ^ $key[0],
 624              $p[1] ^ $key[1],
 625              $p[2] ^ $key[2],
 626              $p[3] ^ $key[3],
 627              $p[4] ^ $key[4],
 628              $p[5] ^ $key[5],
 629              $p[6] ^ $key[6],
 630              $p[7] ^ $key[7],
 631              $p[8] ^ $key[8],
 632              $p[9] ^ $key[9],
 633              $p[10] ^ $key[10],
 634              $p[11] ^ $key[11],
 635              $p[12] ^ $key[12],
 636              $p[13] ^ $key[13],
 637              $p[14] ^ $key[14],
 638              $p[15] ^ $key[15],
 639              $p[16] ^ $key[0],
 640              $p[17] ^ $key[1]
 641          );
 642  
 643          // @codingStandardsIgnoreStart
 644          list( $p[0],  $p[1]) = $this->_encryptBlockHelperFast(     0,      0, $sbox0, $sbox1, $sbox2, $sbox3, $p);
 645          list( $p[2],  $p[3]) = $this->_encryptBlockHelperFast($p[ 0], $p[ 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 646          list( $p[4],  $p[5]) = $this->_encryptBlockHelperFast($p[ 2], $p[ 3], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 647          list( $p[6],  $p[7]) = $this->_encryptBlockHelperFast($p[ 4], $p[ 5], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 648          list( $p[8],  $p[9]) = $this->_encryptBlockHelperFast($p[ 6], $p[ 7], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 649          list($p[10], $p[11]) = $this->_encryptBlockHelperFast($p[ 8], $p[ 9], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 650          list($p[12], $p[13]) = $this->_encryptBlockHelperFast($p[10], $p[11], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 651          list($p[14], $p[15]) = $this->_encryptBlockHelperFast($p[12], $p[13], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 652          list($p[16], $p[17]) = $this->_encryptBlockHelperFast($p[14], $p[15], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 653          // @codingStandardsIgnoreEnd
 654  
 655          list($sbox0[0], $sbox0[1]) = $this->_encryptBlockHelperFast($p[16], $p[17], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 656          for ($i = 2; $i < 256; $i+= 2) {
 657              list($sbox0[$i], $sbox0[$i + 1]) = $this->_encryptBlockHelperFast($sbox0[$i - 2], $sbox0[$i - 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 658          }
 659  
 660          list($sbox1[0], $sbox1[1]) = $this->_encryptBlockHelperFast($sbox0[254], $sbox0[255], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 661          for ($i = 2; $i < 256; $i+= 2) {
 662              list($sbox1[$i], $sbox1[$i + 1]) = $this->_encryptBlockHelperFast($sbox1[$i - 2], $sbox1[$i - 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 663          }
 664  
 665          list($sbox2[0], $sbox2[1]) = $this->_encryptBlockHelperFast($sbox1[254], $sbox1[255], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 666          for ($i = 2; $i < 256; $i+= 2) {
 667              list($sbox2[$i], $sbox2[$i + 1]) = $this->_encryptBlockHelperFast($sbox2[$i - 2], $sbox2[$i - 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 668          }
 669  
 670          list($sbox3[0], $sbox3[1]) = $this->_encryptBlockHelperFast($sbox2[254], $sbox2[255], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 671          for ($i = 2; $i < 256; $i+= 2) {
 672              list($sbox3[$i], $sbox3[$i + 1]) = $this->_encryptBlockHelperFast($sbox3[$i - 2], $sbox3[$i - 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 673          }
 674      }
 675  
 676      /**
 677       * Key expansion with salt
 678       *
 679       * @access private
 680       * @param int[] $data
 681       * @param int[] $key
 682       * @param int[] $sbox0
 683       * @param int[] $sbox1
 684       * @param int[] $sbox2
 685       * @param int[] $sbox3
 686       * @param int[] $p
 687       * @see self::_bcrypt_hash()
 688       */
 689      function _expandstate($data, $key, &$sbox0, &$sbox1, &$sbox2, &$sbox3, &$p)
 690      {
 691          $p = array(
 692              $p[0] ^ $key[0],
 693              $p[1] ^ $key[1],
 694              $p[2] ^ $key[2],
 695              $p[3] ^ $key[3],
 696              $p[4] ^ $key[4],
 697              $p[5] ^ $key[5],
 698              $p[6] ^ $key[6],
 699              $p[7] ^ $key[7],
 700              $p[8] ^ $key[8],
 701              $p[9] ^ $key[9],
 702              $p[10] ^ $key[10],
 703              $p[11] ^ $key[11],
 704              $p[12] ^ $key[12],
 705              $p[13] ^ $key[13],
 706              $p[14] ^ $key[14],
 707              $p[15] ^ $key[15],
 708              $p[16] ^ $key[0],
 709              $p[17] ^ $key[1]
 710          );
 711  
 712          // @codingStandardsIgnoreStart
 713          list( $p[0],  $p[1]) = $this->_encryptBlockHelperFast($data[ 0]         , $data[ 1]         , $sbox0, $sbox1, $sbox2, $sbox3, $p);
 714          list( $p[2],  $p[3]) = $this->_encryptBlockHelperFast($data[ 2] ^ $p[ 0], $data[ 3] ^ $p[ 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 715          list( $p[4],  $p[5]) = $this->_encryptBlockHelperFast($data[ 4] ^ $p[ 2], $data[ 5] ^ $p[ 3], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 716          list( $p[6],  $p[7]) = $this->_encryptBlockHelperFast($data[ 6] ^ $p[ 4], $data[ 7] ^ $p[ 5], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 717          list( $p[8],  $p[9]) = $this->_encryptBlockHelperFast($data[ 8] ^ $p[ 6], $data[ 9] ^ $p[ 7], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 718          list($p[10], $p[11]) = $this->_encryptBlockHelperFast($data[10] ^ $p[ 8], $data[11] ^ $p[ 9], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 719          list($p[12], $p[13]) = $this->_encryptBlockHelperFast($data[12] ^ $p[10], $data[13] ^ $p[11], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 720          list($p[14], $p[15]) = $this->_encryptBlockHelperFast($data[14] ^ $p[12], $data[15] ^ $p[13], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 721          list($p[16], $p[17]) = $this->_encryptBlockHelperFast($data[ 0] ^ $p[14], $data[ 1] ^ $p[15], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 722          // @codingStandardsIgnoreEnd
 723  
 724          list($sbox0[0], $sbox0[1]) = $this->_encryptBlockHelperFast($data[2] ^ $p[16], $data[3] ^ $p[17], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 725          for ($i = 2, $j = 4; $i < 256; $i+= 2, $j = ($j + 2) % 16) { // instead of 16 maybe count($data) would be better?
 726              list($sbox0[$i], $sbox0[$i + 1]) = $this->_encryptBlockHelperFast($data[$j] ^ $sbox0[$i - 2], $data[$j + 1] ^ $sbox0[$i - 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 727          }
 728  
 729          list($sbox1[0], $sbox1[1]) = $this->_encryptBlockHelperFast($data[2] ^ $sbox0[254], $data[3] ^ $sbox0[255], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 730          for ($i = 2, $j = 4; $i < 256; $i+= 2, $j = ($j + 2) % 16) {
 731              list($sbox1[$i], $sbox1[$i + 1]) = $this->_encryptBlockHelperFast($data[$j] ^ $sbox1[$i - 2], $data[$j + 1] ^ $sbox1[$i - 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 732          }
 733  
 734          list($sbox2[0], $sbox2[1]) = $this->_encryptBlockHelperFast($data[2] ^ $sbox1[254], $data[3] ^ $sbox1[255], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 735          for ($i = 2, $j = 4; $i < 256; $i+= 2, $j = ($j + 2) % 16) {
 736              list($sbox2[$i], $sbox2[$i + 1]) = $this->_encryptBlockHelperFast($data[$j] ^ $sbox2[$i - 2], $data[$j + 1] ^ $sbox2[$i - 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 737          }
 738  
 739          list($sbox3[0], $sbox3[1]) = $this->_encryptBlockHelperFast($data[2] ^ $sbox2[254], $data[3] ^ $sbox2[255], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 740          for ($i = 2, $j = 4; $i < 256; $i+= 2, $j = ($j + 2) % 16) {
 741              list($sbox3[$i], $sbox3[$i + 1]) = $this->_encryptBlockHelperFast($data[$j] ^ $sbox3[$i - 2], $data[$j + 1] ^ $sbox3[$i - 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
 742          }
 743      }
 744  
 745      /**
 746       * Encrypts a block
 747       *
 748       * @access private
 749       * @param string $in
 750       * @return string
 751       */
 752      function _encryptBlock($in)
 753      {
 754          $p = $this->bctx["p"];
 755          // extract($this->bctx["sb"], EXTR_PREFIX_ALL, "sb"); // slower
 756          $sb_0 = $this->bctx["sb"][0];
 757          $sb_1 = $this->bctx["sb"][1];
 758          $sb_2 = $this->bctx["sb"][2];
 759          $sb_3 = $this->bctx["sb"][3];
 760  
 761          $in = unpack("N*", $in);
 762          $l = $in[1];
 763          $r = $in[2];
 764  
 765          list($r, $l) = PHP_INT_SIZE === 8 ?
 766              $this->_encryptBlockHelperFast($l, $r, $sb_0, $sb_1, $sb_2, $sb_3, $p) :
 767              $this->_encryptBlockHelperSlow($l, $r, $sb_0, $sb_1, $sb_2, $sb_3, $p);
 768  
 769          return pack("N*", $r, $l);
 770      }
 771  
 772      /**
 773       * Fast helper function for block encryption
 774       *
 775       * @access private
 776       * @param int $x0
 777       * @param int $x1
 778       * @param int[] $sbox0
 779       * @param int[] $sbox1
 780       * @param int[] $sbox2
 781       * @param int[] $sbox3
 782       * @param int[] $p
 783       * @return int[]
 784       */
 785      function _encryptBlockHelperFast($x0, $x1, $sbox0, $sbox1, $sbox2, $sbox3, $p)
 786      {
 787          $x0 ^= $p[0];
 788          $x1 ^= ((($sbox0[($x0 & 0xFF000000) >> 24] + $sbox1[($x0 & 0xFF0000) >> 16]) ^ $sbox2[($x0 & 0xFF00) >> 8]) + $sbox3[$x0 & 0xFF]) ^ $p[1];
 789          $x0 ^= ((($sbox0[($x1 & 0xFF000000) >> 24] + $sbox1[($x1 & 0xFF0000) >> 16]) ^ $sbox2[($x1 & 0xFF00) >> 8]) + $sbox3[$x1 & 0xFF]) ^ $p[2];
 790          $x1 ^= ((($sbox0[($x0 & 0xFF000000) >> 24] + $sbox1[($x0 & 0xFF0000) >> 16]) ^ $sbox2[($x0 & 0xFF00) >> 8]) + $sbox3[$x0 & 0xFF]) ^ $p[3];
 791          $x0 ^= ((($sbox0[($x1 & 0xFF000000) >> 24] + $sbox1[($x1 & 0xFF0000) >> 16]) ^ $sbox2[($x1 & 0xFF00) >> 8]) + $sbox3[$x1 & 0xFF]) ^ $p[4];
 792          $x1 ^= ((($sbox0[($x0 & 0xFF000000) >> 24] + $sbox1[($x0 & 0xFF0000) >> 16]) ^ $sbox2[($x0 & 0xFF00) >> 8]) + $sbox3[$x0 & 0xFF]) ^ $p[5];
 793          $x0 ^= ((($sbox0[($x1 & 0xFF000000) >> 24] + $sbox1[($x1 & 0xFF0000) >> 16]) ^ $sbox2[($x1 & 0xFF00) >> 8]) + $sbox3[$x1 & 0xFF]) ^ $p[6];
 794          $x1 ^= ((($sbox0[($x0 & 0xFF000000) >> 24] + $sbox1[($x0 & 0xFF0000) >> 16]) ^ $sbox2[($x0 & 0xFF00) >> 8]) + $sbox3[$x0 & 0xFF]) ^ $p[7];
 795          $x0 ^= ((($sbox0[($x1 & 0xFF000000) >> 24] + $sbox1[($x1 & 0xFF0000) >> 16]) ^ $sbox2[($x1 & 0xFF00) >> 8]) + $sbox3[$x1 & 0xFF]) ^ $p[8];
 796          $x1 ^= ((($sbox0[($x0 & 0xFF000000) >> 24] + $sbox1[($x0 & 0xFF0000) >> 16]) ^ $sbox2[($x0 & 0xFF00) >> 8]) + $sbox3[$x0 & 0xFF]) ^ $p[9];
 797          $x0 ^= ((($sbox0[($x1 & 0xFF000000) >> 24] + $sbox1[($x1 & 0xFF0000) >> 16]) ^ $sbox2[($x1 & 0xFF00) >> 8]) + $sbox3[$x1 & 0xFF]) ^ $p[10];
 798          $x1 ^= ((($sbox0[($x0 & 0xFF000000) >> 24] + $sbox1[($x0 & 0xFF0000) >> 16]) ^ $sbox2[($x0 & 0xFF00) >> 8]) + $sbox3[$x0 & 0xFF]) ^ $p[11];
 799          $x0 ^= ((($sbox0[($x1 & 0xFF000000) >> 24] + $sbox1[($x1 & 0xFF0000) >> 16]) ^ $sbox2[($x1 & 0xFF00) >> 8]) + $sbox3[$x1 & 0xFF]) ^ $p[12];
 800          $x1 ^= ((($sbox0[($x0 & 0xFF000000) >> 24] + $sbox1[($x0 & 0xFF0000) >> 16]) ^ $sbox2[($x0 & 0xFF00) >> 8]) + $sbox3[$x0 & 0xFF]) ^ $p[13];
 801          $x0 ^= ((($sbox0[($x1 & 0xFF000000) >> 24] + $sbox1[($x1 & 0xFF0000) >> 16]) ^ $sbox2[($x1 & 0xFF00) >> 8]) + $sbox3[$x1 & 0xFF]) ^ $p[14];
 802          $x1 ^= ((($sbox0[($x0 & 0xFF000000) >> 24] + $sbox1[($x0 & 0xFF0000) >> 16]) ^ $sbox2[($x0 & 0xFF00) >> 8]) + $sbox3[$x0 & 0xFF]) ^ $p[15];
 803          $x0 ^= ((($sbox0[($x1 & 0xFF000000) >> 24] + $sbox1[($x1 & 0xFF0000) >> 16]) ^ $sbox2[($x1 & 0xFF00) >> 8]) + $sbox3[$x1 & 0xFF]) ^ $p[16];
 804  
 805          return array($x1 & 0xFFFFFFFF ^ $p[17], $x0 & 0xFFFFFFFF);
 806      }
 807  
 808      /**
 809       * Slow helper function for block encryption
 810       *
 811       * @access private
 812       * @param int $x0
 813       * @param int $x1
 814       * @param int[] $sbox0
 815       * @param int[] $sbox1
 816       * @param int[] $sbox2
 817       * @param int[] $sbox3
 818       * @param int[] $p
 819       * @return int[]
 820       */
 821      function _encryptBlockHelperSlow($x0, $x1, $sbox0, $sbox1, $sbox2, $sbox3, $p)
 822      {
 823          // -16777216 == intval(0xFF000000) on 32-bit PHP installs
 824          $x0^= $p[0];
 825          $x1^= $this->safe_intval(($this->safe_intval($sbox0[(($x0 & -16777216) >> 24) & 0xFF] + $sbox1[($x0 & 0xFF0000) >> 16]) ^ $sbox2[($x0 & 0xFF00) >> 8]) + $sbox3[$x0 & 0xFF]) ^ $p[1];
 826          $x0^= $this->safe_intval(($this->safe_intval($sbox0[(($x1 & -16777216) >> 24) & 0xFF] + $sbox1[($x1 & 0xFF0000) >> 16]) ^ $sbox2[($x1 & 0xFF00) >> 8]) + $sbox3[$x1 & 0xFF]) ^ $p[2];
 827          $x1^= $this->safe_intval(($this->safe_intval($sbox0[(($x0 & -16777216) >> 24) & 0xFF] + $sbox1[($x0 & 0xFF0000) >> 16]) ^ $sbox2[($x0 & 0xFF00) >> 8]) + $sbox3[$x0 & 0xFF]) ^ $p[3];
 828          $x0^= $this->safe_intval(($this->safe_intval($sbox0[(($x1 & -16777216) >> 24) & 0xFF] + $sbox1[($x1 & 0xFF0000) >> 16]) ^ $sbox2[($x1 & 0xFF00) >> 8]) + $sbox3[$x1 & 0xFF]) ^ $p[4];
 829          $x1^= $this->safe_intval(($this->safe_intval($sbox0[(($x0 & -16777216) >> 24) & 0xFF] + $sbox1[($x0 & 0xFF0000) >> 16]) ^ $sbox2[($x0 & 0xFF00) >> 8]) + $sbox3[$x0 & 0xFF]) ^ $p[5];
 830          $x0^= $this->safe_intval(($this->safe_intval($sbox0[(($x1 & -16777216) >> 24) & 0xFF] + $sbox1[($x1 & 0xFF0000) >> 16]) ^ $sbox2[($x1 & 0xFF00) >> 8]) + $sbox3[$x1 & 0xFF]) ^ $p[6];
 831          $x1^= $this->safe_intval(($this->safe_intval($sbox0[(($x0 & -16777216) >> 24) & 0xFF] + $sbox1[($x0 & 0xFF0000) >> 16]) ^ $sbox2[($x0 & 0xFF00) >> 8]) + $sbox3[$x0 & 0xFF]) ^ $p[7];
 832          $x0^= $this->safe_intval(($this->safe_intval($sbox0[(($x1 & -16777216) >> 24) & 0xFF] + $sbox1[($x1 & 0xFF0000) >> 16]) ^ $sbox2[($x1 & 0xFF00) >> 8]) + $sbox3[$x1 & 0xFF]) ^ $p[8];
 833          $x1^= $this->safe_intval(($this->safe_intval($sbox0[(($x0 & -16777216) >> 24) & 0xFF] + $sbox1[($x0 & 0xFF0000) >> 16]) ^ $sbox2[($x0 & 0xFF00) >> 8]) + $sbox3[$x0 & 0xFF]) ^ $p[9];
 834          $x0^= $this->safe_intval(($this->safe_intval($sbox0[(($x1 & -16777216) >> 24) & 0xFF] + $sbox1[($x1 & 0xFF0000) >> 16]) ^ $sbox2[($x1 & 0xFF00) >> 8]) + $sbox3[$x1 & 0xFF]) ^ $p[10];
 835          $x1^= $this->safe_intval(($this->safe_intval($sbox0[(($x0 & -16777216) >> 24) & 0xFF] + $sbox1[($x0 & 0xFF0000) >> 16]) ^ $sbox2[($x0 & 0xFF00) >> 8]) + $sbox3[$x0 & 0xFF]) ^ $p[11];
 836          $x0^= $this->safe_intval(($this->safe_intval($sbox0[(($x1 & -16777216) >> 24) & 0xFF] + $sbox1[($x1 & 0xFF0000) >> 16]) ^ $sbox2[($x1 & 0xFF00) >> 8]) + $sbox3[$x1 & 0xFF]) ^ $p[12];
 837          $x1^= $this->safe_intval(($this->safe_intval($sbox0[(($x0 & -16777216) >> 24) & 0xFF] + $sbox1[($x0 & 0xFF0000) >> 16]) ^ $sbox2[($x0 & 0xFF00) >> 8]) + $sbox3[$x0 & 0xFF]) ^ $p[13];
 838          $x0^= $this->safe_intval(($this->safe_intval($sbox0[(($x1 & -16777216) >> 24) & 0xFF] + $sbox1[($x1 & 0xFF0000) >> 16]) ^ $sbox2[($x1 & 0xFF00) >> 8]) + $sbox3[$x1 & 0xFF]) ^ $p[14];
 839          $x1^= $this->safe_intval(($this->safe_intval($sbox0[(($x0 & -16777216) >> 24) & 0xFF] + $sbox1[($x0 & 0xFF0000) >> 16]) ^ $sbox2[($x0 & 0xFF00) >> 8]) + $sbox3[$x0 & 0xFF]) ^ $p[15];
 840          $x0^= $this->safe_intval(($this->safe_intval($sbox0[(($x1 & -16777216) >> 24) & 0xFF] + $sbox1[($x1 & 0xFF0000) >> 16]) ^ $sbox2[($x1 & 0xFF00) >> 8]) + $sbox3[$x1 & 0xFF]) ^ $p[16];
 841  
 842          return array($x1 ^ $p[17], $x0);
 843      }
 844  
 845      /**
 846       * Decrypts a block
 847       *
 848       * @access private
 849       * @param string $in
 850       * @return string
 851       */
 852      function _decryptBlock($in)
 853      {
 854          $p = $this->bctx["p"];
 855          $sb_0 = $this->bctx["sb"][0];
 856          $sb_1 = $this->bctx["sb"][1];
 857          $sb_2 = $this->bctx["sb"][2];
 858          $sb_3 = $this->bctx["sb"][3];
 859  
 860          $in = unpack("N*", $in);
 861          $l = $in[1];
 862          $r = $in[2];
 863  
 864          for ($i = 17; $i > 2; $i-= 2) {
 865              $l^= $p[$i];
 866              $r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
 867                    $sb_2[$l >>  8 & 0xff]) +
 868                    $sb_3[$l       & 0xff]);
 869  
 870              $r^= $p[$i - 1];
 871              $l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
 872                    $sb_2[$r >>  8 & 0xff]) +
 873                    $sb_3[$r       & 0xff]);
 874          }
 875          return pack("N*", $r ^ $p[0], $l ^ $p[1]);
 876      }
 877  
 878      /**
 879       * Setup the performance-optimized function for de/encrypt()
 880       *
 881       * @see \phpseclib\Crypt\Base::_setupInlineCrypt()
 882       * @access private
 883       */
 884      function _setupInlineCrypt()
 885      {
 886          $lambda_functions =& self::_getLambdaFunctions();
 887  
 888          // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
 889          // (Currently, for Blowfish, one generated $lambda_function cost on php5.5@32bit ~100kb unfreeable mem and ~180kb on php5.5@64bit)
 890          // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
 891          $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
 892  
 893          // Generation of a unique hash for our generated code
 894          $code_hash = "Crypt_Blowfish, {$this->mode}";
 895          if ($gen_hi_opt_code) {
 896              $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
 897          }
 898  
 899          $safeint = $this->safe_intval_inline();
 900  
 901          if (!isset($lambda_functions[$code_hash])) {
 902              switch (true) {
 903                  case $gen_hi_opt_code:
 904                      $p = $this->bctx['p'];
 905                      $init_crypt = '
 906                          static $sb_0, $sb_1, $sb_2, $sb_3;
 907                          if (!$sb_0) {
 908                              $sb_0 = $self->bctx["sb"][0];
 909                              $sb_1 = $self->bctx["sb"][1];
 910                              $sb_2 = $self->bctx["sb"][2];
 911                              $sb_3 = $self->bctx["sb"][3];
 912                          }
 913                      ';
 914                      break;
 915                  default:
 916                      $p   = array();
 917                      for ($i = 0; $i < 18; ++$i) {
 918                          $p[] = '$p_' . $i;
 919                      }
 920                      $init_crypt = '
 921                          list($sb_0, $sb_1, $sb_2, $sb_3) = $self->bctx["sb"];
 922                          list(' . implode(',', $p) . ') = $self->bctx["p"];
 923  
 924                      ';
 925              }
 926  
 927              // Generating encrypt code:
 928              $encrypt_block = '
 929                  $in = unpack("N*", $in);
 930                  $l = $in[1];
 931                  $r = $in[2];
 932              ';
 933              for ($i = 0; $i < 16; $i+= 2) {
 934                  $encrypt_block.= '
 935                      $l^= ' . $p[$i] . ';
 936                      $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
 937                            $sb_2[$l >>  8 & 0xff]) +
 938                            $sb_3[$l       & 0xff]') . ';
 939  
 940                      $r^= ' . $p[$i + 1] . ';
 941                      $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . '  ^
 942                            $sb_2[$r >>  8 & 0xff]) +
 943                            $sb_3[$r       & 0xff]') . ';
 944                  ';
 945              }
 946              $encrypt_block.= '
 947                  $in = pack("N*",
 948                      $r ^ ' . $p[17] . ',
 949                      $l ^ ' . $p[16] . '
 950                  );
 951              ';
 952  
 953              // Generating decrypt code:
 954              $decrypt_block = '
 955                  $in = unpack("N*", $in);
 956                  $l = $in[1];
 957                  $r = $in[2];
 958              ';
 959  
 960              for ($i = 17; $i > 2; $i-= 2) {
 961                  $decrypt_block.= '
 962                      $l^= ' . $p[$i] . ';
 963                      $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
 964                            $sb_2[$l >>  8 & 0xff]) +
 965                            $sb_3[$l       & 0xff]') . ';
 966  
 967                      $r^= ' . $p[$i - 1] . ';
 968                      $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
 969                            $sb_2[$r >>  8 & 0xff]) +
 970                            $sb_3[$r       & 0xff]') . ';
 971                  ';
 972              }
 973  
 974              $decrypt_block.= '
 975                  $in = pack("N*",
 976                      $r ^ ' . $p[0] . ',
 977                      $l ^ ' . $p[1] . '
 978                  );
 979              ';
 980  
 981              $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
 982                  array(
 983                     'init_crypt'    => $init_crypt,
 984                     'init_encrypt'  => '',
 985                     'init_decrypt'  => '',
 986                     'encrypt_block' => $encrypt_block,
 987                     'decrypt_block' => $decrypt_block
 988                  )
 989              );
 990          }
 991          $this->inline_crypt = $lambda_functions[$code_hash];
 992      }
 993  }