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