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