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
117namespace phpseclib3\Crypt;
118
119use 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 */
127class 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
155     *
156     * S-Box
157     *
158     * @var    array
159     */
160    private static $sbox = [
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        0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
195        0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
196        0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
197        0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
198        0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
199        0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
200        0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
201        0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
202        0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
203        0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
204        0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
205        0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
206        0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
207        0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
208        0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
209        0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
210        0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
211        0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
212        0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
213        0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
214        0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
215        0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
216        0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
217        0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
218        0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
219        0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
220        0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
221        0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
222        0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
223        0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
224        0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
225        0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
226
227        0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
228        0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
229        0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
230        0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
231        0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
232        0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
233        0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
234        0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
235        0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
236        0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
237        0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
238        0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
239        0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
240        0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
241        0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
242        0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
243        0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
244        0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
245        0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
246        0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
247        0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
248        0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
249        0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
250        0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
251        0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
252        0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
253        0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
254        0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
255        0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
256        0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
257        0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
258        0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
259
260        0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
261        0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
262        0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
263        0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
264        0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
265        0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
266        0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
267        0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
268        0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
269        0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
270        0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
271        0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
272        0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
273        0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
274        0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
275        0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
276        0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
277        0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
278        0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
279        0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
280        0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
281        0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
282        0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
283        0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
284        0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
285        0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
286        0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
287        0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
288        0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
289        0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
290        0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
291        0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
292    ];
293
294    /**
295     * P-Array consists of 18 32-bit subkeys
296     *
297     * @var array
298     */
299    private static $parray = [
300        0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
301        0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
302        0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
303    ];
304
305    /**
306     * The BCTX-working Array
307     *
308     * Holds the expanded key [p] and the key-depended s-boxes [sb]
309     *
310     * @var array
311     */
312    private $bctx;
313
314    /**
315     * Holds the last used key
316     *
317     * @var array
318     */
319    private $kl;
320
321    /**
322     * The Key Length (in bytes)
323     * {@internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16.  Exists in conjunction with $Nk
324     *    because the encryption / decryption / key schedule creation requires this number and not $key_length.  We could
325     *    derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
326     *    of that, we'll just precompute it once.}
327     *
328     * @see \phpseclib3\Crypt\Common\SymmetricKey::setKeyLength()
329     * @var int
330     */
331    protected $key_length = 16;
332
333    /**
334     * Default Constructor.
335     *
336     * @param string $mode
337     * @throws \InvalidArgumentException if an invalid / unsupported mode is provided
338     */
339    public function __construct($mode)
340    {
341        parent::__construct($mode);
342
343        if ($this->mode == self::MODE_STREAM) {
344            throw new \InvalidArgumentException('Block ciphers cannot be ran in stream mode');
345        }
346    }
347
348    /**
349     * Sets the key length.
350     *
351     * Key lengths can be between 32 and 448 bits.
352     *
353     * @param int $length
354     */
355    public function setKeyLength($length)
356    {
357        if ($length < 32 || $length > 448) {
358                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');
359        }
360
361        $this->key_length = $length >> 3;
362
363        parent::setKeyLength($length);
364    }
365
366    /**
367     * Test for engine validity
368     *
369     * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
370     *
371     * @see \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
372     * @param int $engine
373     * @return bool
374     */
375    protected function isValidEngineHelper($engine)
376    {
377        if ($engine == self::ENGINE_OPENSSL) {
378            if ($this->key_length < 16) {
379                return false;
380            }
381            // quoting https://www.openssl.org/news/openssl-3.0-notes.html, OpenSSL 3.0.1
382            // "Moved all variations of the EVP ciphers CAST5, BF, IDEA, SEED, RC2, RC4, RC5, and DES to the legacy provider"
383            // in theory openssl_get_cipher_methods() should catch this but, on GitHub Actions, at least, it does not
384            if (defined('OPENSSL_VERSION_TEXT') && version_compare(preg_replace('#OpenSSL (\d+\.\d+\.\d+) .*#', '$1', OPENSSL_VERSION_TEXT), '3.0.1', '>=')) {
385                return false;
386            }
387            $this->cipher_name_openssl_ecb = 'bf-ecb';
388            $this->cipher_name_openssl = 'bf-' . $this->openssl_translate_mode();
389        }
390
391        return parent::isValidEngineHelper($engine);
392    }
393
394    /**
395     * Setup the key (expansion)
396     *
397     * @see \phpseclib3\Crypt\Common\SymmetricKey::_setupKey()
398     */
399    protected function setupKey()
400    {
401        if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
402            // already expanded
403            return;
404        }
405        $this->kl = ['key' => $this->key];
406
407        /* key-expanding p[] and S-Box building sb[] */
408        $this->bctx = [
409            'p'  => [],
410            'sb' => self::$sbox
411        ];
412
413        // unpack binary string in unsigned chars
414        $key  = array_values(unpack('C*', $this->key));
415        $keyl = count($key);
416        // with bcrypt $keyl will always be 16 (because the key is the sha512 of the key you provide)
417        for ($j = 0, $i = 0; $i < 18; ++$i) {
418            // xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ...
419            for ($data = 0, $k = 0; $k < 4; ++$k) {
420                $data = ($data << 8) | $key[$j];
421                if (++$j >= $keyl) {
422                    $j = 0;
423                }
424            }
425            $this->bctx['p'][] = self::$parray[$i] ^ intval($data);
426        }
427
428        // encrypt the zero-string, replace P1 and P2 with the encrypted data,
429        // encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys
430        $data = "\0\0\0\0\0\0\0\0";
431        for ($i = 0; $i < 18; $i += 2) {
432            list($l, $r) = array_values(unpack('N*', $data = $this->encryptBlock($data)));
433            $this->bctx['p'][$i    ] = $l;
434            $this->bctx['p'][$i + 1] = $r;
435        }
436        for ($i = 0; $i < 0x400; $i += 0x100) {
437            for ($j = 0; $j < 256; $j += 2) {
438                list($l, $r) = array_values(unpack('N*', $data = $this->encryptBlock($data)));
439                $this->bctx['sb'][$i | $j] = $l;
440                $this->bctx['sb'][$i | ($j + 1)] = $r;
441            }
442        }
443    }
444
445    /**
446     * Initialize Static Variables
447     */
448    protected static function initialize_static_variables()
449    {
450        if (is_float(self::$sbox[0x200])) {
451            self::$sbox = array_map('intval', self::$sbox);
452            self::$parray = array_map('intval', self::$parray);
453        }
454
455        parent::initialize_static_variables();
456    }
457
458    /**
459     * bcrypt
460     *
461     * @param string $sha2pass
462     * @param string $sha2salt
463     * @access private
464     * @return string
465     */
466    private static function bcrypt_hash($sha2pass, $sha2salt)
467    {
468        $p = self::$parray;
469        $sbox = self::$sbox;
470
471        $cdata = array_values(unpack('N*', 'OxychromaticBlowfishSwatDynamite'));
472        $sha2pass = array_values(unpack('N*', $sha2pass));
473        $sha2salt = array_values(unpack('N*', $sha2salt));
474
475        self::expandstate($sha2salt, $sha2pass, $sbox, $p);
476        for ($i = 0; $i < 64; $i++) {
477            self::expand0state($sha2salt, $sbox, $p);
478            self::expand0state($sha2pass, $sbox, $p);
479        }
480
481        for ($i = 0; $i < 64; $i++) {
482            for ($j = 0; $j < 8; $j += 2) { // count($cdata) == 8
483                list($cdata[$j], $cdata[$j + 1]) = self::encryptBlockHelperFast($cdata[$j], $cdata[$j + 1], $sbox, $p);
484            }
485        }
486
487        return pack('V*', ...$cdata);
488    }
489
490    /**
491     * Performs OpenSSH-style bcrypt
492     *
493     * @param string $pass
494     * @param string $salt
495     * @param int $keylen
496     * @param int $rounds
497     * @access public
498     * @return string
499     */
500    public static function bcrypt_pbkdf($pass, $salt, $keylen, $rounds)
501    {
502        self::initialize_static_variables();
503
504        if (PHP_INT_SIZE == 4) {
505            throw new \RuntimeException('bcrypt is far too slow to be practical on 32-bit versions of PHP');
506        }
507
508        $sha2pass = hash('sha512', $pass, true);
509        $results = [];
510        $count = 1;
511        while (32 * count($results) < $keylen) {
512            $countsalt = $salt . pack('N', $count++);
513            $sha2salt = hash('sha512', $countsalt, true);
514            $out = $tmpout = self::bcrypt_hash($sha2pass, $sha2salt);
515            for ($i = 1; $i < $rounds; $i++) {
516                $sha2salt = hash('sha512', $tmpout, true);
517                $tmpout = self::bcrypt_hash($sha2pass, $sha2salt);
518                $out ^= $tmpout;
519            }
520            $results[] = $out;
521        }
522        $output = '';
523        for ($i = 0; $i < 32; $i++) {
524            foreach ($results as $result) {
525                $output .= $result[$i];
526            }
527        }
528        return substr($output, 0, $keylen);
529    }
530
531    /**
532     * Key expansion without salt
533     *
534     * @access private
535     * @param int[] $key
536     * @param int[] $sbox
537     * @param int[] $p
538     * @see self::_bcrypt_hash()
539     */
540    private static function expand0state(array $key, array &$sbox, array &$p)
541    {
542        // expand0state is basically the same thing as this:
543        //return self::expandstate(array_fill(0, 16, 0), $key);
544        // but this separate function eliminates a bunch of XORs and array lookups
545
546        $p = [
547            $p[0] ^ $key[0],
548            $p[1] ^ $key[1],
549            $p[2] ^ $key[2],
550            $p[3] ^ $key[3],
551            $p[4] ^ $key[4],
552            $p[5] ^ $key[5],
553            $p[6] ^ $key[6],
554            $p[7] ^ $key[7],
555            $p[8] ^ $key[8],
556            $p[9] ^ $key[9],
557            $p[10] ^ $key[10],
558            $p[11] ^ $key[11],
559            $p[12] ^ $key[12],
560            $p[13] ^ $key[13],
561            $p[14] ^ $key[14],
562            $p[15] ^ $key[15],
563            $p[16] ^ $key[0],
564            $p[17] ^ $key[1]
565        ];
566
567        // @codingStandardsIgnoreStart
568        list( $p[0],  $p[1]) = self::encryptBlockHelperFast(     0,      0, $sbox, $p);
569        list( $p[2],  $p[3]) = self::encryptBlockHelperFast($p[ 0], $p[ 1], $sbox, $p);
570        list( $p[4],  $p[5]) = self::encryptBlockHelperFast($p[ 2], $p[ 3], $sbox, $p);
571        list( $p[6],  $p[7]) = self::encryptBlockHelperFast($p[ 4], $p[ 5], $sbox, $p);
572        list( $p[8],  $p[9]) = self::encryptBlockHelperFast($p[ 6], $p[ 7], $sbox, $p);
573        list($p[10], $p[11]) = self::encryptBlockHelperFast($p[ 8], $p[ 9], $sbox, $p);
574        list($p[12], $p[13]) = self::encryptBlockHelperFast($p[10], $p[11], $sbox, $p);
575        list($p[14], $p[15]) = self::encryptBlockHelperFast($p[12], $p[13], $sbox, $p);
576        list($p[16], $p[17]) = self::encryptBlockHelperFast($p[14], $p[15], $sbox, $p);
577        // @codingStandardsIgnoreEnd
578
579        list($sbox[0], $sbox[1]) = self::encryptBlockHelperFast($p[16], $p[17], $sbox, $p);
580        for ($i = 2; $i < 1024; $i += 2) {
581            list($sbox[$i], $sbox[$i + 1]) = self::encryptBlockHelperFast($sbox[$i - 2], $sbox[$i - 1], $sbox, $p);
582        }
583    }
584
585    /**
586     * Key expansion with salt
587     *
588     * @access private
589     * @param int[] $data
590     * @param int[] $key
591     * @param int[] $sbox
592     * @param int[] $p
593     * @see self::_bcrypt_hash()
594     */
595    private static function expandstate(array $data, array $key, array &$sbox, array &$p)
596    {
597        $p = [
598            $p[0] ^ $key[0],
599            $p[1] ^ $key[1],
600            $p[2] ^ $key[2],
601            $p[3] ^ $key[3],
602            $p[4] ^ $key[4],
603            $p[5] ^ $key[5],
604            $p[6] ^ $key[6],
605            $p[7] ^ $key[7],
606            $p[8] ^ $key[8],
607            $p[9] ^ $key[9],
608            $p[10] ^ $key[10],
609            $p[11] ^ $key[11],
610            $p[12] ^ $key[12],
611            $p[13] ^ $key[13],
612            $p[14] ^ $key[14],
613            $p[15] ^ $key[15],
614            $p[16] ^ $key[0],
615            $p[17] ^ $key[1]
616        ];
617
618        // @codingStandardsIgnoreStart
619        list( $p[0],  $p[1]) = self::encryptBlockHelperFast($data[ 0]         , $data[ 1]         , $sbox, $p);
620        list( $p[2],  $p[3]) = self::encryptBlockHelperFast($data[ 2] ^ $p[ 0], $data[ 3] ^ $p[ 1], $sbox, $p);
621        list( $p[4],  $p[5]) = self::encryptBlockHelperFast($data[ 4] ^ $p[ 2], $data[ 5] ^ $p[ 3], $sbox, $p);
622        list( $p[6],  $p[7]) = self::encryptBlockHelperFast($data[ 6] ^ $p[ 4], $data[ 7] ^ $p[ 5], $sbox, $p);
623        list( $p[8],  $p[9]) = self::encryptBlockHelperFast($data[ 8] ^ $p[ 6], $data[ 9] ^ $p[ 7], $sbox, $p);
624        list($p[10], $p[11]) = self::encryptBlockHelperFast($data[10] ^ $p[ 8], $data[11] ^ $p[ 9], $sbox, $p);
625        list($p[12], $p[13]) = self::encryptBlockHelperFast($data[12] ^ $p[10], $data[13] ^ $p[11], $sbox, $p);
626        list($p[14], $p[15]) = self::encryptBlockHelperFast($data[14] ^ $p[12], $data[15] ^ $p[13], $sbox, $p);
627        list($p[16], $p[17]) = self::encryptBlockHelperFast($data[ 0] ^ $p[14], $data[ 1] ^ $p[15], $sbox, $p);
628        // @codingStandardsIgnoreEnd
629
630        list($sbox[0], $sbox[1]) = self::encryptBlockHelperFast($data[2] ^ $p[16], $data[3] ^ $p[17], $sbox, $p);
631        for ($i = 2, $j = 4; $i < 1024; $i += 2, $j = ($j + 2) % 16) { // instead of 16 maybe count($data) would be better?
632            list($sbox[$i], $sbox[$i + 1]) = self::encryptBlockHelperFast($data[$j] ^ $sbox[$i - 2], $data[$j + 1] ^ $sbox[$i - 1], $sbox, $p);
633        }
634    }
635
636    /**
637     * Encrypts a block
638     *
639     * @param string $in
640     * @return string
641     */
642    protected function encryptBlock($in)
643    {
644        $p = $this->bctx['p'];
645        // extract($this->bctx['sb'], EXTR_PREFIX_ALL, 'sb'); // slower
646        $sb = $this->bctx['sb'];
647
648        $in = unpack('N*', $in);
649        $l = $in[1];
650        $r = $in[2];
651
652        list($r, $l) = PHP_INT_SIZE == 4 ?
653            self::encryptBlockHelperSlow($l, $r, $sb, $p) :
654            self::encryptBlockHelperFast($l, $r, $sb, $p);
655
656        return pack("N*", $r, $l);
657    }
658
659    /**
660     * Fast helper function for block encryption
661     *
662     * @access private
663     * @param int $x0
664     * @param int $x1
665     * @param int[] $sbox
666     * @param int[] $p
667     * @return int[]
668     */
669    private static function encryptBlockHelperFast($x0, $x1, array $sbox, array $p)
670    {
671        $x0 ^= $p[0];
672        $x1 ^= ((($sbox[($x0 & 0xFF000000) >> 24] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[1];
673        $x0 ^= ((($sbox[($x1 & 0xFF000000) >> 24] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[2];
674        $x1 ^= ((($sbox[($x0 & 0xFF000000) >> 24] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[3];
675        $x0 ^= ((($sbox[($x1 & 0xFF000000) >> 24] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[4];
676        $x1 ^= ((($sbox[($x0 & 0xFF000000) >> 24] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[5];
677        $x0 ^= ((($sbox[($x1 & 0xFF000000) >> 24] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[6];
678        $x1 ^= ((($sbox[($x0 & 0xFF000000) >> 24] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[7];
679        $x0 ^= ((($sbox[($x1 & 0xFF000000) >> 24] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[8];
680        $x1 ^= ((($sbox[($x0 & 0xFF000000) >> 24] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[9];
681        $x0 ^= ((($sbox[($x1 & 0xFF000000) >> 24] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[10];
682        $x1 ^= ((($sbox[($x0 & 0xFF000000) >> 24] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[11];
683        $x0 ^= ((($sbox[($x1 & 0xFF000000) >> 24] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[12];
684        $x1 ^= ((($sbox[($x0 & 0xFF000000) >> 24] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[13];
685        $x0 ^= ((($sbox[($x1 & 0xFF000000) >> 24] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[14];
686        $x1 ^= ((($sbox[($x0 & 0xFF000000) >> 24] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[15];
687        $x0 ^= ((($sbox[($x1 & 0xFF000000) >> 24] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[16];
688
689        return [$x1 & 0xFFFFFFFF ^ $p[17], $x0 & 0xFFFFFFFF];
690    }
691
692    /**
693     * Slow helper function for block encryption
694     *
695     * @access private
696     * @param int $x0
697     * @param int $x1
698     * @param int[] $sbox
699     * @param int[] $p
700     * @return int[]
701     */
702    private static function encryptBlockHelperSlow($x0, $x1, array $sbox, array $p)
703    {
704        // -16777216 == intval(0xFF000000) on 32-bit PHP installs
705        $x0 ^= $p[0];
706        $x1 ^= self::safe_intval((self::safe_intval($sbox[(($x0 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[1];
707        $x0 ^= self::safe_intval((self::safe_intval($sbox[(($x1 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[2];
708        $x1 ^= self::safe_intval((self::safe_intval($sbox[(($x0 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[3];
709        $x0 ^= self::safe_intval((self::safe_intval($sbox[(($x1 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[4];
710        $x1 ^= self::safe_intval((self::safe_intval($sbox[(($x0 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[5];
711        $x0 ^= self::safe_intval((self::safe_intval($sbox[(($x1 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[6];
712        $x1 ^= self::safe_intval((self::safe_intval($sbox[(($x0 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[7];
713        $x0 ^= self::safe_intval((self::safe_intval($sbox[(($x1 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[8];
714        $x1 ^= self::safe_intval((self::safe_intval($sbox[(($x0 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[9];
715        $x0 ^= self::safe_intval((self::safe_intval($sbox[(($x1 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[10];
716        $x1 ^= self::safe_intval((self::safe_intval($sbox[(($x0 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[11];
717        $x0 ^= self::safe_intval((self::safe_intval($sbox[(($x1 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[12];
718        $x1 ^= self::safe_intval((self::safe_intval($sbox[(($x0 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[13];
719        $x0 ^= self::safe_intval((self::safe_intval($sbox[(($x1 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[14];
720        $x1 ^= self::safe_intval((self::safe_intval($sbox[(($x0 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[15];
721        $x0 ^= self::safe_intval((self::safe_intval($sbox[(($x1 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[16];
722
723        return [$x1 ^ $p[17], $x0];
724    }
725
726    /**
727     * Decrypts a block
728     *
729     * @param string $in
730     * @return string
731     */
732    protected function decryptBlock($in)
733    {
734        $p = $this->bctx['p'];
735        $sb = $this->bctx['sb'];
736
737        $in = unpack('N*', $in);
738        $l = $in[1];
739        $r = $in[2];
740
741        for ($i = 17; $i > 2; $i -= 2) {
742            $l ^= $p[$i];
743            $r ^= self::safe_intval((self::safe_intval($sb[$l >> 24 & 0xff] + $sb[0x100 + ($l >> 16 & 0xff)]) ^
744                  $sb[0x200 + ($l >>  8 & 0xff)]) +
745                  $sb[0x300 + ($l       & 0xff)]);
746
747            $r ^= $p[$i - 1];
748            $l ^= self::safe_intval((self::safe_intval($sb[$r >> 24 & 0xff] + $sb[0x100 + ($r >> 16 & 0xff)]) ^
749                  $sb[0x200 + ($r >>  8 & 0xff)]) +
750                  $sb[0x300 + ($r       & 0xff)]);
751        }
752        return pack('N*', $r ^ $p[0], $l ^ $p[1]);
753    }
754
755    /**
756     * Setup the performance-optimized function for de/encrypt()
757     *
758     * @see \phpseclib3\Crypt\Common\SymmetricKey::_setupInlineCrypt()
759     */
760    protected function setupInlineCrypt()
761    {
762        $p = $this->bctx['p'];
763        $init_crypt = '
764            static $sb;
765            if (!$sb) {
766                $sb = $this->bctx["sb"];
767            }
768        ';
769
770        $safeint = self::safe_intval_inline();
771
772        // Generating encrypt code:
773        $encrypt_block = '
774            $in = unpack("N*", $in);
775            $l = $in[1];
776            $r = $in[2];
777        ';
778        for ($i = 0; $i < 16; $i += 2) {
779            $encrypt_block .= '
780                $l^= ' . $p[$i] . ';
781                $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb[$l >> 24 & 0xff] + $sb[0x100 + ($l >> 16 & 0xff)]') . ' ^
782                      $sb[0x200 + ($l >>  8 & 0xff)]) +
783                      $sb[0x300 + ($l       & 0xff)]') . ';
784
785                $r^= ' . $p[$i + 1] . ';
786                $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb[$r >> 24 & 0xff] + $sb[0x100 + ($r >> 16 & 0xff)]') . '  ^
787                      $sb[0x200 + ($r >>  8 & 0xff)]) +
788                      $sb[0x300 + ($r       & 0xff)]') . ';
789            ';
790        }
791        $encrypt_block .= '
792            $in = pack("N*",
793                $r ^ ' . $p[17] . ',
794                $l ^ ' . $p[16] . '
795            );
796        ';
797         // Generating decrypt code:
798        $decrypt_block = '
799            $in = unpack("N*", $in);
800            $l = $in[1];
801            $r = $in[2];
802        ';
803
804        for ($i = 17; $i > 2; $i -= 2) {
805            $decrypt_block .= '
806                $l^= ' . $p[$i] . ';
807                $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb[$l >> 24 & 0xff] + $sb[0x100 + ($l >> 16 & 0xff)]') . ' ^
808                      $sb[0x200 + ($l >>  8 & 0xff)]) +
809                      $sb[0x300 + ($l       & 0xff)]') . ';
810
811                $r^= ' . $p[$i - 1] . ';
812                $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb[$r >> 24 & 0xff] + $sb[0x100 + ($r >> 16 & 0xff)]') . ' ^
813                      $sb[0x200 + ($r >>  8 & 0xff)]) +
814                      $sb[0x300 + ($r       & 0xff)]') . ';
815            ';
816        }
817
818        $decrypt_block .= '
819            $in = pack("N*",
820                $r ^ ' . $p[0] . ',
821                $l ^ ' . $p[1] . '
822            );
823        ';
824
825        $this->inline_crypt = $this->createInlineCryptFunction(
826            [
827               'init_crypt'    => $init_crypt,
828               'init_encrypt'  => '',
829               'init_decrypt'  => '',
830               'encrypt_block' => $encrypt_block,
831               'decrypt_block' => $decrypt_block
832            ]
833        );
834    }
835}
836