1<?php
2
3/**
4 * Pure-PHP implementation of Twofish.
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/Twofish Wikipedia description of Twofish}
13 *
14 * Here's a short example of how to use this library:
15 * <code>
16 * <?php
17 *    include 'vendor/autoload.php';
18 *
19 *    $twofish = new \phpseclib3\Crypt\Twofish('ctr');
20 *
21 *    $twofish->setKey('12345678901234567890123456789012');
22 *
23 *    $plaintext = str_repeat('a', 1024);
24 *
25 *    echo $twofish->decrypt($twofish->encrypt($plaintext));
26 * ?>
27 * </code>
28 *
29 * @author    Jim Wigginton <terrafrost@php.net>
30 * @author    Hans-Juergen Petrich <petrich@tronic-media.com>
31 * @copyright 2007 Jim Wigginton
32 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
33 * @link      http://phpseclib.sourceforge.net
34 */
35
36namespace phpseclib3\Crypt;
37
38use phpseclib3\Crypt\Common\BlockCipher;
39use phpseclib3\Exception\BadModeException;
40
41/**
42 * Pure-PHP implementation of Twofish.
43 *
44 * @author  Jim Wigginton <terrafrost@php.net>
45 * @author  Hans-Juergen Petrich <petrich@tronic-media.com>
46 */
47class Twofish extends BlockCipher
48{
49    /**
50     * The mcrypt specific name of the cipher
51     *
52     * @see \phpseclib3\Crypt\Common\SymmetricKey::cipher_name_mcrypt
53     * @var string
54     */
55    protected $cipher_name_mcrypt = 'twofish';
56
57    /**
58     * Optimizing value while CFB-encrypting
59     *
60     * @see \phpseclib3\Crypt\Common\SymmetricKey::cfb_init_len
61     * @var int
62     */
63    protected $cfb_init_len = 800;
64
65    /**
66     * Q-Table
67     *
68     * @var array
69     */
70    private static $q0 = [
71        0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76,
72        0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38,
73        0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
74        0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48,
75        0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23,
76        0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
77        0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C,
78        0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61,
79        0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
80        0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1,
81        0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66,
82        0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
83        0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA,
84        0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71,
85        0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
86        0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7,
87        0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2,
88        0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
89        0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB,
90        0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF,
91        0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
92        0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64,
93        0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A,
94        0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
95        0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02,
96        0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D,
97        0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
98        0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
99        0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8,
100        0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
101        0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00,
102        0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0
103    ];
104
105    /**
106     * Q-Table
107     *
108     * @var array
109     */
110    private static $q1 = [
111        0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8,
112        0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B,
113        0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
114        0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F,
115        0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D,
116        0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
117        0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3,
118        0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51,
119        0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
120        0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C,
121        0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70,
122        0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
123        0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC,
124        0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2,
125        0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
126        0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17,
127        0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3,
128        0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
129        0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49,
130        0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9,
131        0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
132        0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48,
133        0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19,
134        0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
135        0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5,
136        0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69,
137        0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
138        0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC,
139        0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB,
140        0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
141        0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2,
142        0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91
143    ];
144
145    /**
146     * M-Table
147     *
148     * @var array
149     */
150    private static $m0 = [
151        0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, 0xE2E22BFB, 0x9E9EFAC8,
152        0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B,
153        0x3C3C57D6, 0x93938A32, 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
154        0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, 0xB0B0B306, 0x7575DE3F,
155        0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D,
156        0xAEAE2C6D, 0x7F7FABC1, 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
157        0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, 0x3131272C, 0x808065A3,
158        0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51,
159        0x2A2A3638, 0xC4C49CB0, 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
160        0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, 0x6767C027, 0xE9E9AF8C,
161        0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70,
162        0x29294CCA, 0xF0F035E3, 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
163        0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, 0xC8C81DC3, 0x9999FFCC,
164        0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2,
165        0xB5B53D79, 0x09090F0C, 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
166        0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, 0xEDEDD07A, 0x4343FC17,
167        0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3,
168        0x5656E70B, 0xE3E3DA72, 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
169        0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, 0x8181942A, 0x91910149,
170        0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9,
171        0x7878AEC5, 0xC5C56D39, 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
172        0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, 0x55559DF9, 0x7E7E5A48,
173        0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519,
174        0x0606F48D, 0x404086E5, 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
175        0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, 0x2D2D333C, 0x3030D6A5,
176        0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969,
177        0xD9D97929, 0x8686912E, 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
178        0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, 0xC1C112CF, 0x8585EBDC,
179        0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB,
180        0xABABA212, 0x6F6F3EA2, 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
181        0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, 0x04047FF6, 0x272746C2,
182        0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91
183    ];
184
185    /**
186     * M-Table
187     *
188     * @var array
189     */
190    private static $m1 = [
191        0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, 0xA3658080, 0x76DFE4E4,
192        0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A,
193        0x0D54E6E6, 0xC6432020, 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
194        0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, 0x94B1FBFB, 0x485A7E7E,
195        0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060,
196        0x1945FDFD, 0x5BA33A3A, 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
197        0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, 0x9B53AAAA, 0x7C635D5D,
198        0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7,
199        0xC0F09090, 0x8CAFE9E9, 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
200        0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, 0xB499C3C3, 0xF1975B5B,
201        0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8,
202        0xCCFF9999, 0x95EA1414, 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
203        0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, 0xBF7E9595, 0xBA207D7D,
204        0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB,
205        0x81FB0F0F, 0x793DB5B5, 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
206        0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, 0x86135050, 0xE730F7F7,
207        0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B,
208        0x410B9F9F, 0x7B8B0202, 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
209        0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, 0xB1C72B2B, 0xAB6F8E8E,
210        0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9,
211        0x91EF1313, 0x85FE0808, 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
212        0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, 0x6929A9A9, 0x647D4F4F,
213        0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED,
214        0xAC87D1D1, 0x7F8E0505, 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
215        0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, 0x4C5F7979, 0x02B6B7B7,
216        0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2,
217        0x57AC3333, 0xC718CFCF, 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
218        0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, 0x99E51D1D, 0x34392323,
219        0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA,
220        0xC8FA9E9E, 0xA882D6D6, 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
221        0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, 0x0FE25151, 0x00000000,
222        0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8
223    ];
224
225    /**
226     * M-Table
227     *
228     * @var array
229     */
230    private static $m2 = [
231        0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, 0xE2FBE22B, 0x9EC89EFA,
232        0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7,
233        0x3CD63C57, 0x9332938A, 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
234        0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, 0xB006B0B3, 0x753F75DE,
235        0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0,
236        0xAE6DAE2C, 0x7FC17FAB, 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
237        0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, 0x312C3127, 0x80A38065,
238        0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F,
239        0x2A382A36, 0xC4B0C49C, 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
240        0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, 0x672767C0, 0xE98CE9AF,
241        0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C,
242        0x29CA294C, 0xF0E3F035, 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
243        0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, 0xC8C3C81D, 0x99CC99FF,
244        0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E,
245        0xB579B53D, 0x090C090F, 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
246        0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, 0xED7AEDD0, 0x431743FC,
247        0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71,
248        0x560B56E7, 0xE372E3DA, 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
249        0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, 0x812A8194, 0x91499101,
250        0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5,
251        0x78C578AE, 0xC539C56D, 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
252        0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, 0x55F9559D, 0x7E487E5A,
253        0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45,
254        0x068D06F4, 0x40E54086, 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
255        0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, 0x2D3C2D33, 0x30A530D6,
256        0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929,
257        0xD929D979, 0x862E8691, 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
258        0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, 0xC1CFC112, 0x85DC85EB,
259        0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F,
260        0xAB12ABA2, 0x6FA26F3E, 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
261        0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, 0x04F6047F, 0x27C22746,
262        0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF
263    ];
264
265    /**
266     * M-Table
267     *
268     * @var array
269     */
270    private static $m3 = [
271        0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, 0x6580A365, 0xDFE476DF,
272        0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836,
273        0x54E60D54, 0x4320C643, 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
274        0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, 0xB1FB94B1, 0x5A7E485A,
275        0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5,
276        0x45FD1945, 0xA33A5BA3, 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
277        0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, 0x53AA9B53, 0x635D7C63,
278        0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123,
279        0xF090C0F0, 0xAFE98CAF, 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
280        0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, 0x99C3B499, 0x975BF197,
281        0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB,
282        0xFF99CCFF, 0xEA1495EA, 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
283        0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, 0x7E95BF7E, 0x207DBA20,
284        0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137,
285        0xFB0F81FB, 0x3DB5793D, 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
286        0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, 0x13508613, 0x30F7E730,
287        0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252,
288        0x0B9F410B, 0x8B027B8B, 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
289        0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, 0xC72BB1C7, 0x6F8EAB6F,
290        0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A,
291        0xEF1391EF, 0xFE0885FE, 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
292        0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, 0x29A96929, 0x7D4F647D,
293        0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0,
294        0x87D1AC87, 0x8E057F8E, 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
295        0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, 0x5F794C5F, 0xB6B702B6,
296        0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38,
297        0xAC3357AC, 0x18CFC718, 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
298        0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, 0xE51D99E5, 0x39233439,
299        0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6,
300        0xFA9EC8FA, 0x82D6A882, 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
301        0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, 0xE2510FE2, 0x00000000,
302        0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8
303    ];
304
305    /**
306     * The Key Schedule Array
307     *
308     * @var array
309     */
310    private $K = [];
311
312    /**
313     * The Key depended S-Table 0
314     *
315     * @var array
316     */
317    private $S0 = [];
318
319    /**
320     * The Key depended S-Table 1
321     *
322     * @var array
323     */
324    private $S1 = [];
325
326    /**
327     * The Key depended S-Table 2
328     *
329     * @var array
330     */
331    private $S2 = [];
332
333    /**
334     * The Key depended S-Table 3
335     *
336     * @var array
337     */
338    private $S3 = [];
339
340    /**
341     * Holds the last used key
342     *
343     * @var array
344     */
345    private $kl;
346
347    /**
348     * The Key Length (in bytes)
349     *
350     * @see Crypt_Twofish::setKeyLength()
351     * @var int
352     */
353    protected $key_length = 16;
354
355    /**
356     * Default Constructor.
357     *
358     * @param string $mode
359     * @throws BadModeException if an invalid / unsupported mode is provided
360     */
361    public function __construct($mode)
362    {
363        parent::__construct($mode);
364
365        if ($this->mode == self::MODE_STREAM) {
366            throw new BadModeException('Block ciphers cannot be ran in stream mode');
367        }
368    }
369
370    /**
371     * Initialize Static Variables
372     */
373    protected static function initialize_static_variables()
374    {
375        if (is_float(self::$m3[0])) {
376            self::$m0 = array_map('intval', self::$m0);
377            self::$m1 = array_map('intval', self::$m1);
378            self::$m2 = array_map('intval', self::$m2);
379            self::$m3 = array_map('intval', self::$m3);
380            self::$q0 = array_map('intval', self::$q0);
381            self::$q1 = array_map('intval', self::$q1);
382        }
383
384        parent::initialize_static_variables();
385    }
386
387    /**
388     * Sets the key length.
389     *
390     * Valid key lengths are 128, 192 or 256 bits
391     *
392     * @param int $length
393     */
394    public function setKeyLength($length)
395    {
396        switch ($length) {
397            case 128:
398            case 192:
399            case 256:
400                break;
401            default:
402                throw new \LengthException('Key of size ' . $length . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported');
403        }
404
405        parent::setKeyLength($length);
406    }
407
408    /**
409     * Sets the key.
410     *
411     * Rijndael supports five different key lengths
412     *
413     * @see setKeyLength()
414     * @param string $key
415     * @throws \LengthException if the key length isn't supported
416     */
417    public function setKey($key)
418    {
419        switch (strlen($key)) {
420            case 16:
421            case 24:
422            case 32:
423                break;
424            default:
425                throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported');
426        }
427
428        parent::setKey($key);
429    }
430
431    /**
432     * Setup the key (expansion)
433     *
434     * @see \phpseclib3\Crypt\Common\SymmetricKey::_setupKey()
435     */
436    protected function setupKey()
437    {
438        if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
439            // already expanded
440            return;
441        }
442        $this->kl = ['key' => $this->key];
443
444        /* Key expanding and generating the key-depended s-boxes */
445        $le_longs = unpack('V*', $this->key);
446        $key = unpack('C*', $this->key);
447        $m0 = self::$m0;
448        $m1 = self::$m1;
449        $m2 = self::$m2;
450        $m3 = self::$m3;
451        $q0 = self::$q0;
452        $q1 = self::$q1;
453
454        $K = $S0 = $S1 = $S2 = $S3 = [];
455
456        switch (strlen($this->key)) {
457            case 16:
458                list($s7, $s6, $s5, $s4) = $this->mdsrem($le_longs[1], $le_longs[2]);
459                list($s3, $s2, $s1, $s0) = $this->mdsrem($le_longs[3], $le_longs[4]);
460                for ($i = 0, $j = 1; $i < 40; $i += 2, $j += 2) {
461                    $A = $m0[$q0[$q0[$i] ^ $key[ 9]] ^ $key[1]] ^
462                         $m1[$q0[$q1[$i] ^ $key[10]] ^ $key[2]] ^
463                         $m2[$q1[$q0[$i] ^ $key[11]] ^ $key[3]] ^
464                         $m3[$q1[$q1[$i] ^ $key[12]] ^ $key[4]];
465                    $B = $m0[$q0[$q0[$j] ^ $key[13]] ^ $key[5]] ^
466                         $m1[$q0[$q1[$j] ^ $key[14]] ^ $key[6]] ^
467                         $m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^
468                         $m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]];
469                    $B = ($B << 8) | ($B >> 24 & 0xff);
470                    $A = self::safe_intval($A + $B);
471                    $K[] = $A;
472                    $A = self::safe_intval($A + $B);
473                    $K[] = ($A << 9 | $A >> 23 & 0x1ff);
474                }
475                for ($i = 0; $i < 256; ++$i) {
476                    $S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0];
477                    $S1[$i] = $m1[$q0[$q1[$i] ^ $s5] ^ $s1];
478                    $S2[$i] = $m2[$q1[$q0[$i] ^ $s6] ^ $s2];
479                    $S3[$i] = $m3[$q1[$q1[$i] ^ $s7] ^ $s3];
480                }
481                break;
482            case 24:
483                list($sb, $sa, $s9, $s8) = $this->mdsrem($le_longs[1], $le_longs[2]);
484                list($s7, $s6, $s5, $s4) = $this->mdsrem($le_longs[3], $le_longs[4]);
485                list($s3, $s2, $s1, $s0) = $this->mdsrem($le_longs[5], $le_longs[6]);
486                for ($i = 0, $j = 1; $i < 40; $i += 2, $j += 2) {
487                    $A = $m0[$q0[$q0[$q1[$i] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
488                         $m1[$q0[$q1[$q1[$i] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
489                         $m2[$q1[$q0[$q0[$i] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
490                         $m3[$q1[$q1[$q0[$i] ^ $key[20]] ^ $key[12]] ^ $key[4]];
491                    $B = $m0[$q0[$q0[$q1[$j] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
492                         $m1[$q0[$q1[$q1[$j] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
493                         $m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
494                         $m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]];
495                    $B = ($B << 8) | ($B >> 24 & 0xff);
496                    $A = self::safe_intval($A + $B);
497                    $K[] = $A;
498                    $A = self::safe_intval($A + $B);
499                    $K[] = ($A << 9 | $A >> 23 & 0x1ff);
500                }
501                for ($i = 0; $i < 256; ++$i) {
502                    $S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0];
503                    $S1[$i] = $m1[$q0[$q1[$q1[$i] ^ $s9] ^ $s5] ^ $s1];
504                    $S2[$i] = $m2[$q1[$q0[$q0[$i] ^ $sa] ^ $s6] ^ $s2];
505                    $S3[$i] = $m3[$q1[$q1[$q0[$i] ^ $sb] ^ $s7] ^ $s3];
506                }
507                break;
508            default: // 32
509                list($sf, $se, $sd, $sc) = $this->mdsrem($le_longs[1], $le_longs[2]);
510                list($sb, $sa, $s9, $s8) = $this->mdsrem($le_longs[3], $le_longs[4]);
511                list($s7, $s6, $s5, $s4) = $this->mdsrem($le_longs[5], $le_longs[6]);
512                list($s3, $s2, $s1, $s0) = $this->mdsrem($le_longs[7], $le_longs[8]);
513                for ($i = 0, $j = 1; $i < 40; $i += 2, $j += 2) {
514                    $A = $m0[$q0[$q0[$q1[$q1[$i] ^ $key[25]] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
515                         $m1[$q0[$q1[$q1[$q0[$i] ^ $key[26]] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
516                         $m2[$q1[$q0[$q0[$q0[$i] ^ $key[27]] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
517                         $m3[$q1[$q1[$q0[$q1[$i] ^ $key[28]] ^ $key[20]] ^ $key[12]] ^ $key[4]];
518                    $B = $m0[$q0[$q0[$q1[$q1[$j] ^ $key[29]] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
519                         $m1[$q0[$q1[$q1[$q0[$j] ^ $key[30]] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
520                         $m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
521                         $m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]];
522                    $B = ($B << 8) | ($B >> 24 & 0xff);
523                    $A = self::safe_intval($A + $B);
524                    $K[] = $A;
525                    $A = self::safe_intval($A + $B);
526                    $K[] = ($A << 9 | $A >> 23 & 0x1ff);
527                }
528                for ($i = 0; $i < 256; ++$i) {
529                    $S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0];
530                    $S1[$i] = $m1[$q0[$q1[$q1[$q0[$i] ^ $sd] ^ $s9] ^ $s5] ^ $s1];
531                    $S2[$i] = $m2[$q1[$q0[$q0[$q0[$i] ^ $se] ^ $sa] ^ $s6] ^ $s2];
532                    $S3[$i] = $m3[$q1[$q1[$q0[$q1[$i] ^ $sf] ^ $sb] ^ $s7] ^ $s3];
533                }
534        }
535
536        $this->K  = $K;
537        $this->S0 = $S0;
538        $this->S1 = $S1;
539        $this->S2 = $S2;
540        $this->S3 = $S3;
541    }
542
543    /**
544     * _mdsrem function using by the twofish cipher algorithm
545     *
546     * @param string $A
547     * @param string $B
548     * @return array
549     */
550    private function mdsrem($A, $B)
551    {
552        // No gain by unrolling this loop.
553        for ($i = 0; $i < 8; ++$i) {
554            // Get most significant coefficient.
555            $t = 0xff & ($B >> 24);
556
557            // Shift the others up.
558            $B = ($B << 8) | (0xff & ($A >> 24));
559            $A <<= 8;
560
561            $u = $t << 1;
562
563            // Subtract the modular polynomial on overflow.
564            if ($t & 0x80) {
565                $u ^= 0x14d;
566            }
567
568            // Remove t * (a * x^2 + 1).
569            $B ^= $t ^ ($u << 16);
570
571            // Form u = a*t + t/a = t*(a + 1/a).
572            $u ^= 0x7fffffff & ($t >> 1);
573
574            // Add the modular polynomial on underflow.
575            if ($t & 0x01) {
576                $u ^= 0xa6 ;
577            }
578
579            // Remove t * (a + 1/a) * (x^3 + x).
580            $B ^= ($u << 24) | ($u << 8);
581        }
582
583        return [
584            0xff & $B >> 24,
585            0xff & $B >> 16,
586            0xff & $B >>  8,
587            0xff & $B];
588    }
589
590    /**
591     * Encrypts a block
592     *
593     * @param string $in
594     * @return string
595     */
596    protected function encryptBlock($in)
597    {
598        $S0 = $this->S0;
599        $S1 = $this->S1;
600        $S2 = $this->S2;
601        $S3 = $this->S3;
602        $K  = $this->K;
603
604        $in = unpack("V4", $in);
605        $R0 = $K[0] ^ $in[1];
606        $R1 = $K[1] ^ $in[2];
607        $R2 = $K[2] ^ $in[3];
608        $R3 = $K[3] ^ $in[4];
609
610        $ki = 7;
611        while ($ki < 39) {
612            $t0 = $S0[ $R0        & 0xff] ^
613                  $S1[($R0 >>  8) & 0xff] ^
614                  $S2[($R0 >> 16) & 0xff] ^
615                  $S3[($R0 >> 24) & 0xff];
616            $t1 = $S0[($R1 >> 24) & 0xff] ^
617                  $S1[ $R1        & 0xff] ^
618                  $S2[($R1 >>  8) & 0xff] ^
619                  $S3[($R1 >> 16) & 0xff];
620            $R2 ^= self::safe_intval($t0 + $t1 + $K[++$ki]);
621            $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
622            $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ self::safe_intval($t0 + ($t1 << 1) + $K[++$ki]);
623
624            $t0 = $S0[ $R2        & 0xff] ^
625                  $S1[($R2 >>  8) & 0xff] ^
626                  $S2[($R2 >> 16) & 0xff] ^
627                  $S3[($R2 >> 24) & 0xff];
628            $t1 = $S0[($R3 >> 24) & 0xff] ^
629                  $S1[ $R3        & 0xff] ^
630                  $S2[($R3 >>  8) & 0xff] ^
631                  $S3[($R3 >> 16) & 0xff];
632            $R0 ^= self::safe_intval($t0 + $t1 + $K[++$ki]);
633            $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
634            $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ self::safe_intval($t0 + ($t1 << 1) + $K[++$ki]);
635        }
636
637        // @codingStandardsIgnoreStart
638        return pack("V4", $K[4] ^ $R2,
639                          $K[5] ^ $R3,
640                          $K[6] ^ $R0,
641                          $K[7] ^ $R1);
642        // @codingStandardsIgnoreEnd
643    }
644
645    /**
646     * Decrypts a block
647     *
648     * @param string $in
649     * @return string
650     */
651    protected function decryptBlock($in)
652    {
653        $S0 = $this->S0;
654        $S1 = $this->S1;
655        $S2 = $this->S2;
656        $S3 = $this->S3;
657        $K  = $this->K;
658
659        $in = unpack("V4", $in);
660        $R0 = $K[4] ^ $in[1];
661        $R1 = $K[5] ^ $in[2];
662        $R2 = $K[6] ^ $in[3];
663        $R3 = $K[7] ^ $in[4];
664
665        $ki = 40;
666        while ($ki > 8) {
667            $t0 = $S0[$R0       & 0xff] ^
668                  $S1[$R0 >>  8 & 0xff] ^
669                  $S2[$R0 >> 16 & 0xff] ^
670                  $S3[$R0 >> 24 & 0xff];
671            $t1 = $S0[$R1 >> 24 & 0xff] ^
672                  $S1[$R1       & 0xff] ^
673                  $S2[$R1 >>  8 & 0xff] ^
674                  $S3[$R1 >> 16 & 0xff];
675            $R3 ^= self::safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
676            $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
677            $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ self::safe_intval($t0 + $t1 + $K[--$ki]);
678
679            $t0 = $S0[$R2       & 0xff] ^
680                  $S1[$R2 >>  8 & 0xff] ^
681                  $S2[$R2 >> 16 & 0xff] ^
682                  $S3[$R2 >> 24 & 0xff];
683            $t1 = $S0[$R3 >> 24 & 0xff] ^
684                  $S1[$R3       & 0xff] ^
685                  $S2[$R3 >>  8 & 0xff] ^
686                  $S3[$R3 >> 16 & 0xff];
687            $R1 ^= self::safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
688            $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
689            $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ self::safe_intval($t0 + $t1 + $K[--$ki]);
690        }
691
692        // @codingStandardsIgnoreStart
693        return pack("V4", $K[0] ^ $R2,
694                          $K[1] ^ $R3,
695                          $K[2] ^ $R0,
696                          $K[3] ^ $R1);
697        // @codingStandardsIgnoreEnd
698    }
699
700    /**
701     * Setup the performance-optimized function for de/encrypt()
702     *
703     * @see \phpseclib3\Crypt\Common\SymmetricKey::_setupInlineCrypt()
704     */
705    protected function setupInlineCrypt()
706    {
707        $K = $this->K;
708        $init_crypt = '
709            static $S0, $S1, $S2, $S3;
710            if (!$S0) {
711                for ($i = 0; $i < 256; ++$i) {
712                    $S0[] = (int)$this->S0[$i];
713                    $S1[] = (int)$this->S1[$i];
714                    $S2[] = (int)$this->S2[$i];
715                    $S3[] = (int)$this->S3[$i];
716                }
717            }
718        ';
719
720        $safeint = self::safe_intval_inline();
721
722        // Generating encrypt code:
723        $encrypt_block = '
724            $in = unpack("V4", $in);
725            $R0 = ' . $K[0] . ' ^ $in[1];
726            $R1 = ' . $K[1] . ' ^ $in[2];
727            $R2 = ' . $K[2] . ' ^ $in[3];
728            $R3 = ' . $K[3] . ' ^ $in[4];
729        ';
730        for ($ki = 7, $i = 0; $i < 8; ++$i) {
731            $encrypt_block .= '
732                $t0 = $S0[ $R0        & 0xff] ^
733                      $S1[($R0 >>  8) & 0xff] ^
734                      $S2[($R0 >> 16) & 0xff] ^
735                      $S3[($R0 >> 24) & 0xff];
736                $t1 = $S0[($R1 >> 24) & 0xff] ^
737                      $S1[ $R1        & 0xff] ^
738                      $S2[($R1 >>  8) & 0xff] ^
739                      $S3[($R1 >> 16) & 0xff];
740                    $R2^= ' . sprintf($safeint, '$t0 + $t1 + ' . $K[++$ki]) . ';
741                $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
742                $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';
743
744                $t0 = $S0[ $R2        & 0xff] ^
745                      $S1[($R2 >>  8) & 0xff] ^
746                      $S2[($R2 >> 16) & 0xff] ^
747                      $S3[($R2 >> 24) & 0xff];
748                $t1 = $S0[($R3 >> 24) & 0xff] ^
749                      $S1[ $R3        & 0xff] ^
750                      $S2[($R3 >>  8) & 0xff] ^
751                      $S3[($R3 >> 16) & 0xff];
752                $R0^= ' . sprintf($safeint, '($t0 + $t1 + ' . $K[++$ki] . ')') . ';
753                $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
754                $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';
755            ';
756        }
757        $encrypt_block .= '
758            $in = pack("V4", ' . $K[4] . ' ^ $R2,
759                             ' . $K[5] . ' ^ $R3,
760                             ' . $K[6] . ' ^ $R0,
761                             ' . $K[7] . ' ^ $R1);
762        ';
763
764        // Generating decrypt code:
765        $decrypt_block = '
766            $in = unpack("V4", $in);
767            $R0 = ' . $K[4] . ' ^ $in[1];
768            $R1 = ' . $K[5] . ' ^ $in[2];
769            $R2 = ' . $K[6] . ' ^ $in[3];
770            $R3 = ' . $K[7] . ' ^ $in[4];
771        ';
772        for ($ki = 40, $i = 0; $i < 8; ++$i) {
773            $decrypt_block .= '
774                $t0 = $S0[$R0       & 0xff] ^
775                      $S1[$R0 >>  8 & 0xff] ^
776                      $S2[$R0 >> 16 & 0xff] ^
777                      $S3[$R0 >> 24 & 0xff];
778                $t1 = $S0[$R1 >> 24 & 0xff] ^
779                      $S1[$R1       & 0xff] ^
780                      $S2[$R1 >>  8 & 0xff] ^
781                      $S3[$R1 >> 16 & 0xff];
782                $R3^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
783                $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
784                $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + ' . $K[--$ki] . ')') . ';
785
786                $t0 = $S0[$R2       & 0xff] ^
787                      $S1[$R2 >>  8 & 0xff] ^
788                      $S2[$R2 >> 16 & 0xff] ^
789                      $S3[$R2 >> 24 & 0xff];
790                $t1 = $S0[$R3 >> 24 & 0xff] ^
791                      $S1[$R3       & 0xff] ^
792                      $S2[$R3 >>  8 & 0xff] ^
793                      $S3[$R3 >> 16 & 0xff];
794                $R1^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
795                $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
796                $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + ' . $K[--$ki] . ')') . ';
797            ';
798        }
799        $decrypt_block .= '
800            $in = pack("V4", ' . $K[0] . ' ^ $R2,
801                             ' . $K[1] . ' ^ $R3,
802                             ' . $K[2] . ' ^ $R0,
803                             ' . $K[3] . ' ^ $R1);
804        ';
805
806        $this->inline_crypt = $this->createInlineCryptFunction(
807            [
808               'init_crypt'    => $init_crypt,
809               'init_encrypt'  => '',
810               'init_decrypt'  => '',
811               'encrypt_block' => $encrypt_block,
812               'decrypt_block' => $decrypt_block
813            ]
814        );
815    }
816}
817