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 * Here's a short example of how to use this library:
15 * <code>
16 * <?php
17 *    include 'vendor/autoload.php';
18 *
19 *    $blowfish = new \phpseclib3\Crypt\Blowfish('ctr');
20 *
21 *    $blowfish->setKey('12345678901234567890123456789012');
22 *
23 *    $plaintext = str_repeat('a', 1024);
24 *
25 *    echo $blowfish->decrypt($blowfish->encrypt($plaintext));
26 * ?>
27 * </code>
28 *
29 * @category  Crypt
30 * @package   Blowfish
31 * @author    Jim Wigginton <terrafrost@php.net>
32 * @author    Hans-Juergen Petrich <petrich@tronic-media.com>
33 * @copyright 2007 Jim Wigginton
34 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
35 * @link      http://phpseclib.sourceforge.net
36 */
37
38namespace phpseclib3\Crypt;
39
40use phpseclib3\Crypt\Common\BlockCipher;
41
42/**
43 * Pure-PHP implementation of Blowfish.
44 *
45 * @package Blowfish
46 * @author  Jim Wigginton <terrafrost@php.net>
47 * @author  Hans-Juergen Petrich <petrich@tronic-media.com>
48 * @access  public
49 */
50class Blowfish extends BlockCipher
51{
52    /**
53     * Block Length of the cipher
54     *
55     * @see \phpseclib3\Crypt\Common\SymmetricKey::block_size
56     * @var int
57     * @access private
58     */
59    protected $block_size = 8;
60
61    /**
62     * The mcrypt specific name of the cipher
63     *
64     * @see \phpseclib3\Crypt\Common\SymmetricKey::cipher_name_mcrypt
65     * @var string
66     * @access private
67     */
68    protected $cipher_name_mcrypt = 'blowfish';
69
70    /**
71     * Optimizing value while CFB-encrypting
72     *
73     * @see \phpseclib3\Crypt\Common\SymmetricKey::cfb_init_len
74     * @var int
75     * @access private
76     */
77    protected $cfb_init_len = 500;
78
79    /**
80     * The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each
81     *
82     * S-Box 0
83     *
84     * @access private
85     * @var    array
86     */
87    private static $sbox0 = [
88        0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
89        0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
90        0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
91        0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
92        0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
93        0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
94        0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
95        0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
96        0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
97        0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
98        0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
99        0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
100        0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
101        0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
102        0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
103        0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
104        0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
105        0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
106        0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
107        0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
108        0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
109        0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
110        0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
111        0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
112        0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
113        0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
114        0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
115        0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
116        0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
117        0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
118        0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
119        0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
120    ];
121
122    /**
123     * S-Box 1
124     *
125     * @access private
126     * @var    array
127     */
128    private static $sbox1 = [
129        0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
130        0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
131        0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
132        0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
133        0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
134        0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
135        0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
136        0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
137        0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
138        0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
139        0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
140        0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
141        0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
142        0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
143        0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
144        0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
145        0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
146        0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
147        0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
148        0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
149        0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
150        0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
151        0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
152        0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
153        0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
154        0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
155        0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
156        0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
157        0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
158        0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
159        0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
160        0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
161    ];
162
163    /**
164     * S-Box 2
165     *
166     * @access private
167     * @var    array
168     */
169    private static $sbox2 = [
170        0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
171        0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
172        0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
173        0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
174        0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
175        0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
176        0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
177        0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
178        0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
179        0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
180        0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
181        0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
182        0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
183        0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
184        0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
185        0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
186        0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
187        0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
188        0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
189        0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
190        0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
191        0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
192        0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
193        0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
194        0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
195        0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
196        0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
197        0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
198        0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
199        0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
200        0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
201        0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
202    ];
203
204    /**
205     * S-Box 3
206     *
207     * @access private
208     * @var    array
209     */
210    private static $sbox3 = [
211        0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
212        0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
213        0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
214        0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
215        0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
216        0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
217        0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
218        0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
219        0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
220        0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
221        0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
222        0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
223        0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
224        0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
225        0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
226        0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
227        0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
228        0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
229        0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
230        0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
231        0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
232        0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
233        0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
234        0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
235        0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
236        0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
237        0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
238        0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
239        0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
240        0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
241        0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
242        0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
243    ];
244
245    /**
246     * P-Array consists of 18 32-bit subkeys
247     *
248     * @var array
249     * @access private
250     */
251    private static $parray = [
252        0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
253        0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
254        0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
255    ];
256
257    /**
258     * The BCTX-working Array
259     *
260     * Holds the expanded key [p] and the key-depended s-boxes [sb]
261     *
262     * @var array
263     * @access private
264     */
265    private $bctx;
266
267    /**
268     * Holds the last used key
269     *
270     * @var array
271     * @access private
272     */
273    private $kl;
274
275    /**
276     * The Key Length (in bytes)
277     * {@internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16.  Exists in conjunction with $Nk
278     *    because the encryption / decryption / key schedule creation requires this number and not $key_length.  We could
279     *    derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
280     *    of that, we'll just precompute it once.}
281     *
282     * @see \phpseclib3\Crypt\Common\SymmetricKey::setKeyLength()
283     * @var int
284     * @access private
285     */
286    protected $key_length = 16;
287
288    /**
289     * Default Constructor.
290     *
291     * @param string $mode
292     * @access public
293     * @throws \InvalidArgumentException if an invalid / unsupported mode is provided
294     */
295    public function __construct($mode)
296    {
297        parent::__construct($mode);
298
299        if ($this->mode == self::MODE_STREAM) {
300            throw new \InvalidArgumentException('Block ciphers cannot be ran in stream mode');
301        }
302    }
303
304    /**
305     * Sets the key length.
306     *
307     * Key lengths can be between 32 and 448 bits.
308     *
309     * @access public
310     * @param int $length
311     */
312    public function setKeyLength($length)
313    {
314        if ($length < 32 || $length > 448) {
315                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');
316        }
317
318        $this->key_length = $length >> 3;
319
320        parent::setKeyLength($length);
321    }
322
323    /**
324     * Test for engine validity
325     *
326     * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
327     *
328     * @see \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
329     * @param int $engine
330     * @access protected
331     * @return bool
332     */
333    protected function isValidEngineHelper($engine)
334    {
335        if ($engine == self::ENGINE_OPENSSL) {
336            if (version_compare(PHP_VERSION, '5.3.7') < 0 && $this->key_length != 16) {
337                return false;
338            }
339            if ($this->key_length < 16) {
340                return false;
341            }
342            $this->cipher_name_openssl_ecb = 'bf-ecb';
343            $this->cipher_name_openssl = 'bf-' . $this->openssl_translate_mode();
344        }
345
346        return parent::isValidEngineHelper($engine);
347    }
348
349    /**
350     * Setup the key (expansion)
351     *
352     * @see \phpseclib3\Crypt\Common\SymmetricKey::_setupKey()
353     * @access private
354     */
355    protected function setupKey()
356    {
357        if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
358            // already expanded
359            return;
360        }
361        $this->kl = ['key' => $this->key];
362
363        /* key-expanding p[] and S-Box building sb[] */
364        $this->bctx = [
365            'p'  => [],
366            'sb' => [
367                self::$sbox0,
368                self::$sbox1,
369                self::$sbox2,
370                self::$sbox3
371            ]
372        ];
373
374        // unpack binary string in unsigned chars
375        $key  = array_values(unpack('C*', $this->key));
376        $keyl = count($key);
377        for ($j = 0, $i = 0; $i < 18; ++$i) {
378            // xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ...
379            for ($data = 0, $k = 0; $k < 4; ++$k) {
380                $data = ($data << 8) | $key[$j];
381                if (++$j >= $keyl) {
382                    $j = 0;
383                }
384            }
385            $this->bctx['p'][] = self::$parray[$i] ^ $data;
386        }
387
388        // encrypt the zero-string, replace P1 and P2 with the encrypted data,
389        // encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys
390        $data = "\0\0\0\0\0\0\0\0";
391        for ($i = 0; $i < 18; $i += 2) {
392            list($l, $r) = array_values(unpack('N*', $data = $this->encryptBlock($data)));
393            $this->bctx['p'][$i    ] = $l;
394            $this->bctx['p'][$i + 1] = $r;
395        }
396        for ($i = 0; $i < 4; ++$i) {
397            for ($j = 0; $j < 256; $j += 2) {
398                list($l, $r) = array_values(unpack('N*', $data = $this->encryptBlock($data)));
399                $this->bctx['sb'][$i][$j    ] = $l;
400                $this->bctx['sb'][$i][$j + 1] = $r;
401            }
402        }
403    }
404
405    /**
406     * Encrypts a block
407     *
408     * @access private
409     * @param string $in
410     * @return string
411     */
412    protected function encryptBlock($in)
413    {
414        $p = $this->bctx['p'];
415        // extract($this->bctx['sb'], EXTR_PREFIX_ALL, 'sb'); // slower
416        $sb_0 = $this->bctx['sb'][0];
417        $sb_1 = $this->bctx['sb'][1];
418        $sb_2 = $this->bctx['sb'][2];
419        $sb_3 = $this->bctx['sb'][3];
420
421        $in = unpack('N*', $in);
422        $l = $in[1];
423        $r = $in[2];
424
425        for ($i = 0; $i < 16; $i += 2) {
426            $l ^= $p[$i];
427            $r ^= self::safe_intval((self::safe_intval($sb_0[$l >> 24 & 0xff]  + $sb_1[$l >> 16 & 0xff]) ^
428                  $sb_2[$l >>  8 & 0xff]) +
429                  $sb_3[$l       & 0xff]);
430
431            $r ^= $p[$i + 1];
432            $l ^= self::safe_intval((self::safe_intval($sb_0[$r >> 24 & 0xff]  + $sb_1[$r >> 16 & 0xff]) ^
433                  $sb_2[$r >>  8 & 0xff]) +
434                  $sb_3[$r       & 0xff]);
435        }
436        return pack('N*', $r ^ $p[17], $l ^ $p[16]);
437    }
438
439    /**
440     * Decrypts a block
441     *
442     * @access private
443     * @param string $in
444     * @return string
445     */
446    protected function decryptBlock($in)
447    {
448        $p = $this->bctx['p'];
449        $sb_0 = $this->bctx['sb'][0];
450        $sb_1 = $this->bctx['sb'][1];
451        $sb_2 = $this->bctx['sb'][2];
452        $sb_3 = $this->bctx['sb'][3];
453
454        $in = unpack('N*', $in);
455        $l = $in[1];
456        $r = $in[2];
457
458        for ($i = 17; $i > 2; $i -= 2) {
459            $l ^= $p[$i];
460            $r ^= self::safe_intval((self::safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
461                  $sb_2[$l >>  8 & 0xff]) +
462                  $sb_3[$l       & 0xff]);
463
464            $r ^= $p[$i - 1];
465            $l ^= self::safe_intval((self::safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
466                  $sb_2[$r >>  8 & 0xff]) +
467                  $sb_3[$r       & 0xff]);
468        }
469        return pack('N*', $r ^ $p[0], $l ^ $p[1]);
470    }
471
472    /**
473     * Setup the performance-optimized function for de/encrypt()
474     *
475     * @see \phpseclib3\Crypt\Common\SymmetricKey::_setupInlineCrypt()
476     * @access private
477     */
478    protected function setupInlineCrypt()
479    {
480        $p = $this->bctx['p'];
481        $init_crypt = '
482            static $sb_0, $sb_1, $sb_2, $sb_3;
483            if (!$sb_0) {
484                $sb_0 = $this->bctx["sb"][0];
485                $sb_1 = $this->bctx["sb"][1];
486                $sb_2 = $this->bctx["sb"][2];
487                $sb_3 = $this->bctx["sb"][3];
488            }
489        ';
490
491        $safeint = self::safe_intval_inline();
492
493        // Generating encrypt code:
494        $encrypt_block = '
495            $in = unpack("N*", $in);
496            $l = $in[1];
497            $r = $in[2];
498        ';
499        for ($i = 0; $i < 16; $i += 2) {
500            $encrypt_block .= '
501                $l^= ' . $p[$i] . ';
502                $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
503                      $sb_2[$l >>  8 & 0xff]) +
504                      $sb_3[$l       & 0xff]') . ';
505
506                $r^= ' . $p[$i + 1] . ';
507                $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . '  ^
508                      $sb_2[$r >>  8 & 0xff]) +
509                      $sb_3[$r       & 0xff]') . ';
510            ';
511        }
512        $encrypt_block .= '
513            $in = pack("N*",
514                $r ^ ' . $p[17] . ',
515                $l ^ ' . $p[16] . '
516            );
517        ';
518         // Generating decrypt code:
519        $decrypt_block = '
520            $in = unpack("N*", $in);
521            $l = $in[1];
522            $r = $in[2];
523        ';
524
525        for ($i = 17; $i > 2; $i -= 2) {
526            $decrypt_block .= '
527                $l^= ' . $p[$i] . ';
528                $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
529                      $sb_2[$l >>  8 & 0xff]) +
530                      $sb_3[$l       & 0xff]') . ';
531
532                $r^= ' . $p[$i - 1] . ';
533                $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
534                      $sb_2[$r >>  8 & 0xff]) +
535                      $sb_3[$r       & 0xff]') . ';
536            ';
537        }
538
539        $decrypt_block .= '
540            $in = pack("N*",
541                $r ^ ' . $p[0] . ',
542                $l ^ ' . $p[1] . '
543            );
544        ';
545
546        $this->inline_crypt = $this->createInlineCryptFunction(
547            [
548               'init_crypt'    => $init_crypt,
549               'init_encrypt'  => '',
550               'init_decrypt'  => '',
551               'encrypt_block' => $encrypt_block,
552               'decrypt_block' => $decrypt_block
553            ]
554        );
555    }
556}
557