1<?php
2
3/**
4 * Pure-PHP implementation of DES.
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/DES_supplementary_material Wikipedia: DES supplementary material}
13 *  - {@link http://www.itl.nist.gov/fipspubs/fip46-2.htm FIPS 46-2 - (DES), Data Encryption Standard}
14 *  - {@link http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-DES.html JavaScript DES Example}
15 *
16 * Here's a short example of how to use this library:
17 * <code>
18 * <?php
19 *    include 'vendor/autoload.php';
20 *
21 *    $des = new \phpseclib3\Crypt\DES('ctr');
22 *
23 *    $des->setKey('abcdefgh');
24 *
25 *    $size = 10 * 1024;
26 *    $plaintext = '';
27 *    for ($i = 0; $i < $size; $i++) {
28 *        $plaintext.= 'a';
29 *    }
30 *
31 *    echo $des->decrypt($des->encrypt($plaintext));
32 * ?>
33 * </code>
34 *
35 * @author    Jim Wigginton <terrafrost@php.net>
36 * @copyright 2007 Jim Wigginton
37 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
38 * @link      http://phpseclib.sourceforge.net
39 */
40
41namespace phpseclib3\Crypt;
42
43use phpseclib3\Crypt\Common\BlockCipher;
44use phpseclib3\Exception\BadModeException;
45
46/**
47 * Pure-PHP implementation of DES.
48 *
49 * @author  Jim Wigginton <terrafrost@php.net>
50 */
51class DES extends BlockCipher
52{
53    /**
54     * Contains $keys[self::ENCRYPT]
55     *
56     * @see \phpseclib3\Crypt\DES::setupKey()
57     * @see \phpseclib3\Crypt\DES::processBlock()
58     */
59    const ENCRYPT = 0;
60    /**
61     * Contains $keys[self::DECRYPT]
62     *
63     * @see \phpseclib3\Crypt\DES::setupKey()
64     * @see \phpseclib3\Crypt\DES::processBlock()
65     */
66    const DECRYPT = 1;
67
68    /**
69     * Block Length of the cipher
70     *
71     * @see \phpseclib3\Crypt\Common\SymmetricKey::block_size
72     * @var int
73     */
74    protected $block_size = 8;
75
76    /**
77     * Key Length (in bytes)
78     *
79     * @see \phpseclib3\Crypt\Common\SymmetricKey::setKeyLength()
80     * @var int
81     */
82    protected $key_length = 8;
83
84    /**
85     * The mcrypt specific name of the cipher
86     *
87     * @see \phpseclib3\Crypt\Common\SymmetricKey::cipher_name_mcrypt
88     * @var string
89     */
90    protected $cipher_name_mcrypt = 'des';
91
92    /**
93     * The OpenSSL names of the cipher / modes
94     *
95     * @see \phpseclib3\Crypt\Common\SymmetricKey::openssl_mode_names
96     * @var array
97     */
98    protected $openssl_mode_names = [
99        self::MODE_ECB => 'des-ecb',
100        self::MODE_CBC => 'des-cbc',
101        self::MODE_CFB => 'des-cfb',
102        self::MODE_OFB => 'des-ofb'
103        // self::MODE_CTR is undefined for DES
104    ];
105
106    /**
107     * Optimizing value while CFB-encrypting
108     *
109     * @see \phpseclib3\Crypt\Common\SymmetricKey::cfb_init_len
110     * @var int
111     */
112    protected $cfb_init_len = 500;
113
114    /**
115     * Switch for DES/3DES encryption
116     *
117     * Used only if $engine == self::ENGINE_INTERNAL
118     *
119     * @see self::setupKey()
120     * @see self::processBlock()
121     * @var int
122     */
123    protected $des_rounds = 1;
124
125    /**
126     * max possible size of $key
127     *
128     * @see self::setKey()
129     * @var string
130     */
131    protected $key_length_max = 8;
132
133    /**
134     * The Key Schedule
135     *
136     * @see self::setupKey()
137     * @var array
138     */
139    private $keys;
140
141    /**
142     * Key Cache "key"
143     *
144     * @see self::setupKey()
145     * @var array
146     */
147    private $kl;
148
149    /**
150     * Shuffle table.
151     *
152     * For each byte value index, the entry holds an 8-byte string
153     * with each byte containing all bits in the same state as the
154     * corresponding bit in the index value.
155     *
156     * @see self::processBlock()
157     * @see self::setupKey()
158     * @var array
159     */
160    protected static $shuffle = [
161        "\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\xFF",
162        "\x00\x00\x00\x00\x00\x00\xFF\x00", "\x00\x00\x00\x00\x00\x00\xFF\xFF",
163        "\x00\x00\x00\x00\x00\xFF\x00\x00", "\x00\x00\x00\x00\x00\xFF\x00\xFF",
164        "\x00\x00\x00\x00\x00\xFF\xFF\x00", "\x00\x00\x00\x00\x00\xFF\xFF\xFF",
165        "\x00\x00\x00\x00\xFF\x00\x00\x00", "\x00\x00\x00\x00\xFF\x00\x00\xFF",
166        "\x00\x00\x00\x00\xFF\x00\xFF\x00", "\x00\x00\x00\x00\xFF\x00\xFF\xFF",
167        "\x00\x00\x00\x00\xFF\xFF\x00\x00", "\x00\x00\x00\x00\xFF\xFF\x00\xFF",
168        "\x00\x00\x00\x00\xFF\xFF\xFF\x00", "\x00\x00\x00\x00\xFF\xFF\xFF\xFF",
169        "\x00\x00\x00\xFF\x00\x00\x00\x00", "\x00\x00\x00\xFF\x00\x00\x00\xFF",
170        "\x00\x00\x00\xFF\x00\x00\xFF\x00", "\x00\x00\x00\xFF\x00\x00\xFF\xFF",
171        "\x00\x00\x00\xFF\x00\xFF\x00\x00", "\x00\x00\x00\xFF\x00\xFF\x00\xFF",
172        "\x00\x00\x00\xFF\x00\xFF\xFF\x00", "\x00\x00\x00\xFF\x00\xFF\xFF\xFF",
173        "\x00\x00\x00\xFF\xFF\x00\x00\x00", "\x00\x00\x00\xFF\xFF\x00\x00\xFF",
174        "\x00\x00\x00\xFF\xFF\x00\xFF\x00", "\x00\x00\x00\xFF\xFF\x00\xFF\xFF",
175        "\x00\x00\x00\xFF\xFF\xFF\x00\x00", "\x00\x00\x00\xFF\xFF\xFF\x00\xFF",
176        "\x00\x00\x00\xFF\xFF\xFF\xFF\x00", "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF",
177        "\x00\x00\xFF\x00\x00\x00\x00\x00", "\x00\x00\xFF\x00\x00\x00\x00\xFF",
178        "\x00\x00\xFF\x00\x00\x00\xFF\x00", "\x00\x00\xFF\x00\x00\x00\xFF\xFF",
179        "\x00\x00\xFF\x00\x00\xFF\x00\x00", "\x00\x00\xFF\x00\x00\xFF\x00\xFF",
180        "\x00\x00\xFF\x00\x00\xFF\xFF\x00", "\x00\x00\xFF\x00\x00\xFF\xFF\xFF",
181        "\x00\x00\xFF\x00\xFF\x00\x00\x00", "\x00\x00\xFF\x00\xFF\x00\x00\xFF",
182        "\x00\x00\xFF\x00\xFF\x00\xFF\x00", "\x00\x00\xFF\x00\xFF\x00\xFF\xFF",
183        "\x00\x00\xFF\x00\xFF\xFF\x00\x00", "\x00\x00\xFF\x00\xFF\xFF\x00\xFF",
184        "\x00\x00\xFF\x00\xFF\xFF\xFF\x00", "\x00\x00\xFF\x00\xFF\xFF\xFF\xFF",
185        "\x00\x00\xFF\xFF\x00\x00\x00\x00", "\x00\x00\xFF\xFF\x00\x00\x00\xFF",
186        "\x00\x00\xFF\xFF\x00\x00\xFF\x00", "\x00\x00\xFF\xFF\x00\x00\xFF\xFF",
187        "\x00\x00\xFF\xFF\x00\xFF\x00\x00", "\x00\x00\xFF\xFF\x00\xFF\x00\xFF",
188        "\x00\x00\xFF\xFF\x00\xFF\xFF\x00", "\x00\x00\xFF\xFF\x00\xFF\xFF\xFF",
189        "\x00\x00\xFF\xFF\xFF\x00\x00\x00", "\x00\x00\xFF\xFF\xFF\x00\x00\xFF",
190        "\x00\x00\xFF\xFF\xFF\x00\xFF\x00", "\x00\x00\xFF\xFF\xFF\x00\xFF\xFF",
191        "\x00\x00\xFF\xFF\xFF\xFF\x00\x00", "\x00\x00\xFF\xFF\xFF\xFF\x00\xFF",
192        "\x00\x00\xFF\xFF\xFF\xFF\xFF\x00", "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF",
193        "\x00\xFF\x00\x00\x00\x00\x00\x00", "\x00\xFF\x00\x00\x00\x00\x00\xFF",
194        "\x00\xFF\x00\x00\x00\x00\xFF\x00", "\x00\xFF\x00\x00\x00\x00\xFF\xFF",
195        "\x00\xFF\x00\x00\x00\xFF\x00\x00", "\x00\xFF\x00\x00\x00\xFF\x00\xFF",
196        "\x00\xFF\x00\x00\x00\xFF\xFF\x00", "\x00\xFF\x00\x00\x00\xFF\xFF\xFF",
197        "\x00\xFF\x00\x00\xFF\x00\x00\x00", "\x00\xFF\x00\x00\xFF\x00\x00\xFF",
198        "\x00\xFF\x00\x00\xFF\x00\xFF\x00", "\x00\xFF\x00\x00\xFF\x00\xFF\xFF",
199        "\x00\xFF\x00\x00\xFF\xFF\x00\x00", "\x00\xFF\x00\x00\xFF\xFF\x00\xFF",
200        "\x00\xFF\x00\x00\xFF\xFF\xFF\x00", "\x00\xFF\x00\x00\xFF\xFF\xFF\xFF",
201        "\x00\xFF\x00\xFF\x00\x00\x00\x00", "\x00\xFF\x00\xFF\x00\x00\x00\xFF",
202        "\x00\xFF\x00\xFF\x00\x00\xFF\x00", "\x00\xFF\x00\xFF\x00\x00\xFF\xFF",
203        "\x00\xFF\x00\xFF\x00\xFF\x00\x00", "\x00\xFF\x00\xFF\x00\xFF\x00\xFF",
204        "\x00\xFF\x00\xFF\x00\xFF\xFF\x00", "\x00\xFF\x00\xFF\x00\xFF\xFF\xFF",
205        "\x00\xFF\x00\xFF\xFF\x00\x00\x00", "\x00\xFF\x00\xFF\xFF\x00\x00\xFF",
206        "\x00\xFF\x00\xFF\xFF\x00\xFF\x00", "\x00\xFF\x00\xFF\xFF\x00\xFF\xFF",
207        "\x00\xFF\x00\xFF\xFF\xFF\x00\x00", "\x00\xFF\x00\xFF\xFF\xFF\x00\xFF",
208        "\x00\xFF\x00\xFF\xFF\xFF\xFF\x00", "\x00\xFF\x00\xFF\xFF\xFF\xFF\xFF",
209        "\x00\xFF\xFF\x00\x00\x00\x00\x00", "\x00\xFF\xFF\x00\x00\x00\x00\xFF",
210        "\x00\xFF\xFF\x00\x00\x00\xFF\x00", "\x00\xFF\xFF\x00\x00\x00\xFF\xFF",
211        "\x00\xFF\xFF\x00\x00\xFF\x00\x00", "\x00\xFF\xFF\x00\x00\xFF\x00\xFF",
212        "\x00\xFF\xFF\x00\x00\xFF\xFF\x00", "\x00\xFF\xFF\x00\x00\xFF\xFF\xFF",
213        "\x00\xFF\xFF\x00\xFF\x00\x00\x00", "\x00\xFF\xFF\x00\xFF\x00\x00\xFF",
214        "\x00\xFF\xFF\x00\xFF\x00\xFF\x00", "\x00\xFF\xFF\x00\xFF\x00\xFF\xFF",
215        "\x00\xFF\xFF\x00\xFF\xFF\x00\x00", "\x00\xFF\xFF\x00\xFF\xFF\x00\xFF",
216        "\x00\xFF\xFF\x00\xFF\xFF\xFF\x00", "\x00\xFF\xFF\x00\xFF\xFF\xFF\xFF",
217        "\x00\xFF\xFF\xFF\x00\x00\x00\x00", "\x00\xFF\xFF\xFF\x00\x00\x00\xFF",
218        "\x00\xFF\xFF\xFF\x00\x00\xFF\x00", "\x00\xFF\xFF\xFF\x00\x00\xFF\xFF",
219        "\x00\xFF\xFF\xFF\x00\xFF\x00\x00", "\x00\xFF\xFF\xFF\x00\xFF\x00\xFF",
220        "\x00\xFF\xFF\xFF\x00\xFF\xFF\x00", "\x00\xFF\xFF\xFF\x00\xFF\xFF\xFF",
221        "\x00\xFF\xFF\xFF\xFF\x00\x00\x00", "\x00\xFF\xFF\xFF\xFF\x00\x00\xFF",
222        "\x00\xFF\xFF\xFF\xFF\x00\xFF\x00", "\x00\xFF\xFF\xFF\xFF\x00\xFF\xFF",
223        "\x00\xFF\xFF\xFF\xFF\xFF\x00\x00", "\x00\xFF\xFF\xFF\xFF\xFF\x00\xFF",
224        "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
225        "\xFF\x00\x00\x00\x00\x00\x00\x00", "\xFF\x00\x00\x00\x00\x00\x00\xFF",
226        "\xFF\x00\x00\x00\x00\x00\xFF\x00", "\xFF\x00\x00\x00\x00\x00\xFF\xFF",
227        "\xFF\x00\x00\x00\x00\xFF\x00\x00", "\xFF\x00\x00\x00\x00\xFF\x00\xFF",
228        "\xFF\x00\x00\x00\x00\xFF\xFF\x00", "\xFF\x00\x00\x00\x00\xFF\xFF\xFF",
229        "\xFF\x00\x00\x00\xFF\x00\x00\x00", "\xFF\x00\x00\x00\xFF\x00\x00\xFF",
230        "\xFF\x00\x00\x00\xFF\x00\xFF\x00", "\xFF\x00\x00\x00\xFF\x00\xFF\xFF",
231        "\xFF\x00\x00\x00\xFF\xFF\x00\x00", "\xFF\x00\x00\x00\xFF\xFF\x00\xFF",
232        "\xFF\x00\x00\x00\xFF\xFF\xFF\x00", "\xFF\x00\x00\x00\xFF\xFF\xFF\xFF",
233        "\xFF\x00\x00\xFF\x00\x00\x00\x00", "\xFF\x00\x00\xFF\x00\x00\x00\xFF",
234        "\xFF\x00\x00\xFF\x00\x00\xFF\x00", "\xFF\x00\x00\xFF\x00\x00\xFF\xFF",
235        "\xFF\x00\x00\xFF\x00\xFF\x00\x00", "\xFF\x00\x00\xFF\x00\xFF\x00\xFF",
236        "\xFF\x00\x00\xFF\x00\xFF\xFF\x00", "\xFF\x00\x00\xFF\x00\xFF\xFF\xFF",
237        "\xFF\x00\x00\xFF\xFF\x00\x00\x00", "\xFF\x00\x00\xFF\xFF\x00\x00\xFF",
238        "\xFF\x00\x00\xFF\xFF\x00\xFF\x00", "\xFF\x00\x00\xFF\xFF\x00\xFF\xFF",
239        "\xFF\x00\x00\xFF\xFF\xFF\x00\x00", "\xFF\x00\x00\xFF\xFF\xFF\x00\xFF",
240        "\xFF\x00\x00\xFF\xFF\xFF\xFF\x00", "\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF",
241        "\xFF\x00\xFF\x00\x00\x00\x00\x00", "\xFF\x00\xFF\x00\x00\x00\x00\xFF",
242        "\xFF\x00\xFF\x00\x00\x00\xFF\x00", "\xFF\x00\xFF\x00\x00\x00\xFF\xFF",
243        "\xFF\x00\xFF\x00\x00\xFF\x00\x00", "\xFF\x00\xFF\x00\x00\xFF\x00\xFF",
244        "\xFF\x00\xFF\x00\x00\xFF\xFF\x00", "\xFF\x00\xFF\x00\x00\xFF\xFF\xFF",
245        "\xFF\x00\xFF\x00\xFF\x00\x00\x00", "\xFF\x00\xFF\x00\xFF\x00\x00\xFF",
246        "\xFF\x00\xFF\x00\xFF\x00\xFF\x00", "\xFF\x00\xFF\x00\xFF\x00\xFF\xFF",
247        "\xFF\x00\xFF\x00\xFF\xFF\x00\x00", "\xFF\x00\xFF\x00\xFF\xFF\x00\xFF",
248        "\xFF\x00\xFF\x00\xFF\xFF\xFF\x00", "\xFF\x00\xFF\x00\xFF\xFF\xFF\xFF",
249        "\xFF\x00\xFF\xFF\x00\x00\x00\x00", "\xFF\x00\xFF\xFF\x00\x00\x00\xFF",
250        "\xFF\x00\xFF\xFF\x00\x00\xFF\x00", "\xFF\x00\xFF\xFF\x00\x00\xFF\xFF",
251        "\xFF\x00\xFF\xFF\x00\xFF\x00\x00", "\xFF\x00\xFF\xFF\x00\xFF\x00\xFF",
252        "\xFF\x00\xFF\xFF\x00\xFF\xFF\x00", "\xFF\x00\xFF\xFF\x00\xFF\xFF\xFF",
253        "\xFF\x00\xFF\xFF\xFF\x00\x00\x00", "\xFF\x00\xFF\xFF\xFF\x00\x00\xFF",
254        "\xFF\x00\xFF\xFF\xFF\x00\xFF\x00", "\xFF\x00\xFF\xFF\xFF\x00\xFF\xFF",
255        "\xFF\x00\xFF\xFF\xFF\xFF\x00\x00", "\xFF\x00\xFF\xFF\xFF\xFF\x00\xFF",
256        "\xFF\x00\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF",
257        "\xFF\xFF\x00\x00\x00\x00\x00\x00", "\xFF\xFF\x00\x00\x00\x00\x00\xFF",
258        "\xFF\xFF\x00\x00\x00\x00\xFF\x00", "\xFF\xFF\x00\x00\x00\x00\xFF\xFF",
259        "\xFF\xFF\x00\x00\x00\xFF\x00\x00", "\xFF\xFF\x00\x00\x00\xFF\x00\xFF",
260        "\xFF\xFF\x00\x00\x00\xFF\xFF\x00", "\xFF\xFF\x00\x00\x00\xFF\xFF\xFF",
261        "\xFF\xFF\x00\x00\xFF\x00\x00\x00", "\xFF\xFF\x00\x00\xFF\x00\x00\xFF",
262        "\xFF\xFF\x00\x00\xFF\x00\xFF\x00", "\xFF\xFF\x00\x00\xFF\x00\xFF\xFF",
263        "\xFF\xFF\x00\x00\xFF\xFF\x00\x00", "\xFF\xFF\x00\x00\xFF\xFF\x00\xFF",
264        "\xFF\xFF\x00\x00\xFF\xFF\xFF\x00", "\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF",
265        "\xFF\xFF\x00\xFF\x00\x00\x00\x00", "\xFF\xFF\x00\xFF\x00\x00\x00\xFF",
266        "\xFF\xFF\x00\xFF\x00\x00\xFF\x00", "\xFF\xFF\x00\xFF\x00\x00\xFF\xFF",
267        "\xFF\xFF\x00\xFF\x00\xFF\x00\x00", "\xFF\xFF\x00\xFF\x00\xFF\x00\xFF",
268        "\xFF\xFF\x00\xFF\x00\xFF\xFF\x00", "\xFF\xFF\x00\xFF\x00\xFF\xFF\xFF",
269        "\xFF\xFF\x00\xFF\xFF\x00\x00\x00", "\xFF\xFF\x00\xFF\xFF\x00\x00\xFF",
270        "\xFF\xFF\x00\xFF\xFF\x00\xFF\x00", "\xFF\xFF\x00\xFF\xFF\x00\xFF\xFF",
271        "\xFF\xFF\x00\xFF\xFF\xFF\x00\x00", "\xFF\xFF\x00\xFF\xFF\xFF\x00\xFF",
272        "\xFF\xFF\x00\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF",
273        "\xFF\xFF\xFF\x00\x00\x00\x00\x00", "\xFF\xFF\xFF\x00\x00\x00\x00\xFF",
274        "\xFF\xFF\xFF\x00\x00\x00\xFF\x00", "\xFF\xFF\xFF\x00\x00\x00\xFF\xFF",
275        "\xFF\xFF\xFF\x00\x00\xFF\x00\x00", "\xFF\xFF\xFF\x00\x00\xFF\x00\xFF",
276        "\xFF\xFF\xFF\x00\x00\xFF\xFF\x00", "\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF",
277        "\xFF\xFF\xFF\x00\xFF\x00\x00\x00", "\xFF\xFF\xFF\x00\xFF\x00\x00\xFF",
278        "\xFF\xFF\xFF\x00\xFF\x00\xFF\x00", "\xFF\xFF\xFF\x00\xFF\x00\xFF\xFF",
279        "\xFF\xFF\xFF\x00\xFF\xFF\x00\x00", "\xFF\xFF\xFF\x00\xFF\xFF\x00\xFF",
280        "\xFF\xFF\xFF\x00\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF",
281        "\xFF\xFF\xFF\xFF\x00\x00\x00\x00", "\xFF\xFF\xFF\xFF\x00\x00\x00\xFF",
282        "\xFF\xFF\xFF\xFF\x00\x00\xFF\x00", "\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF",
283        "\xFF\xFF\xFF\xFF\x00\xFF\x00\x00", "\xFF\xFF\xFF\xFF\x00\xFF\x00\xFF",
284        "\xFF\xFF\xFF\xFF\x00\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF",
285        "\xFF\xFF\xFF\xFF\xFF\x00\x00\x00", "\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF",
286        "\xFF\xFF\xFF\xFF\xFF\x00\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF",
287        "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF",
288        "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
289    ];
290
291    /**
292     * IP mapping helper table.
293     *
294     * Indexing this table with each source byte performs the initial bit permutation.
295     *
296     * @var array
297     */
298    protected static $ipmap = [
299        0x00, 0x10, 0x01, 0x11, 0x20, 0x30, 0x21, 0x31,
300        0x02, 0x12, 0x03, 0x13, 0x22, 0x32, 0x23, 0x33,
301        0x40, 0x50, 0x41, 0x51, 0x60, 0x70, 0x61, 0x71,
302        0x42, 0x52, 0x43, 0x53, 0x62, 0x72, 0x63, 0x73,
303        0x04, 0x14, 0x05, 0x15, 0x24, 0x34, 0x25, 0x35,
304        0x06, 0x16, 0x07, 0x17, 0x26, 0x36, 0x27, 0x37,
305        0x44, 0x54, 0x45, 0x55, 0x64, 0x74, 0x65, 0x75,
306        0x46, 0x56, 0x47, 0x57, 0x66, 0x76, 0x67, 0x77,
307        0x80, 0x90, 0x81, 0x91, 0xA0, 0xB0, 0xA1, 0xB1,
308        0x82, 0x92, 0x83, 0x93, 0xA2, 0xB2, 0xA3, 0xB3,
309        0xC0, 0xD0, 0xC1, 0xD1, 0xE0, 0xF0, 0xE1, 0xF1,
310        0xC2, 0xD2, 0xC3, 0xD3, 0xE2, 0xF2, 0xE3, 0xF3,
311        0x84, 0x94, 0x85, 0x95, 0xA4, 0xB4, 0xA5, 0xB5,
312        0x86, 0x96, 0x87, 0x97, 0xA6, 0xB6, 0xA7, 0xB7,
313        0xC4, 0xD4, 0xC5, 0xD5, 0xE4, 0xF4, 0xE5, 0xF5,
314        0xC6, 0xD6, 0xC7, 0xD7, 0xE6, 0xF6, 0xE7, 0xF7,
315        0x08, 0x18, 0x09, 0x19, 0x28, 0x38, 0x29, 0x39,
316        0x0A, 0x1A, 0x0B, 0x1B, 0x2A, 0x3A, 0x2B, 0x3B,
317        0x48, 0x58, 0x49, 0x59, 0x68, 0x78, 0x69, 0x79,
318        0x4A, 0x5A, 0x4B, 0x5B, 0x6A, 0x7A, 0x6B, 0x7B,
319        0x0C, 0x1C, 0x0D, 0x1D, 0x2C, 0x3C, 0x2D, 0x3D,
320        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
321        0x4C, 0x5C, 0x4D, 0x5D, 0x6C, 0x7C, 0x6D, 0x7D,
322        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
323        0x88, 0x98, 0x89, 0x99, 0xA8, 0xB8, 0xA9, 0xB9,
324        0x8A, 0x9A, 0x8B, 0x9B, 0xAA, 0xBA, 0xAB, 0xBB,
325        0xC8, 0xD8, 0xC9, 0xD9, 0xE8, 0xF8, 0xE9, 0xF9,
326        0xCA, 0xDA, 0xCB, 0xDB, 0xEA, 0xFA, 0xEB, 0xFB,
327        0x8C, 0x9C, 0x8D, 0x9D, 0xAC, 0xBC, 0xAD, 0xBD,
328        0x8E, 0x9E, 0x8F, 0x9F, 0xAE, 0xBE, 0xAF, 0xBF,
329        0xCC, 0xDC, 0xCD, 0xDD, 0xEC, 0xFC, 0xED, 0xFD,
330        0xCE, 0xDE, 0xCF, 0xDF, 0xEE, 0xFE, 0xEF, 0xFF
331    ];
332
333    /**
334     * Inverse IP mapping helper table.
335     * Indexing this table with a byte value reverses the bit order.
336     *
337     * @var array
338     */
339    protected static $invipmap = [
340        0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
341        0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
342        0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
343        0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
344        0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
345        0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
346        0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
347        0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
348        0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
349        0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
350        0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
351        0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
352        0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
353        0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
354        0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
355        0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
356        0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
357        0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
358        0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
359        0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
360        0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
361        0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
362        0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
363        0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
364        0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
365        0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
366        0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
367        0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
368        0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
369        0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
370        0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
371        0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
372    ];
373
374    /**
375     * Pre-permuted S-box1
376     *
377     * Each box ($sbox1-$sbox8) has been vectorized, then each value pre-permuted using the
378     * P table: concatenation can then be replaced by exclusive ORs.
379     *
380     * @var array
381     */
382    protected static $sbox1 = [
383        0x00808200, 0x00000000, 0x00008000, 0x00808202,
384        0x00808002, 0x00008202, 0x00000002, 0x00008000,
385        0x00000200, 0x00808200, 0x00808202, 0x00000200,
386        0x00800202, 0x00808002, 0x00800000, 0x00000002,
387        0x00000202, 0x00800200, 0x00800200, 0x00008200,
388        0x00008200, 0x00808000, 0x00808000, 0x00800202,
389        0x00008002, 0x00800002, 0x00800002, 0x00008002,
390        0x00000000, 0x00000202, 0x00008202, 0x00800000,
391        0x00008000, 0x00808202, 0x00000002, 0x00808000,
392        0x00808200, 0x00800000, 0x00800000, 0x00000200,
393        0x00808002, 0x00008000, 0x00008200, 0x00800002,
394        0x00000200, 0x00000002, 0x00800202, 0x00008202,
395        0x00808202, 0x00008002, 0x00808000, 0x00800202,
396        0x00800002, 0x00000202, 0x00008202, 0x00808200,
397        0x00000202, 0x00800200, 0x00800200, 0x00000000,
398        0x00008002, 0x00008200, 0x00000000, 0x00808002
399    ];
400
401    /**
402     * Pre-permuted S-box2
403     *
404     * @var array
405     */
406    protected static $sbox2 = [
407        0x40084010, 0x40004000, 0x00004000, 0x00084010,
408        0x00080000, 0x00000010, 0x40080010, 0x40004010,
409        0x40000010, 0x40084010, 0x40084000, 0x40000000,
410        0x40004000, 0x00080000, 0x00000010, 0x40080010,
411        0x00084000, 0x00080010, 0x40004010, 0x00000000,
412        0x40000000, 0x00004000, 0x00084010, 0x40080000,
413        0x00080010, 0x40000010, 0x00000000, 0x00084000,
414        0x00004010, 0x40084000, 0x40080000, 0x00004010,
415        0x00000000, 0x00084010, 0x40080010, 0x00080000,
416        0x40004010, 0x40080000, 0x40084000, 0x00004000,
417        0x40080000, 0x40004000, 0x00000010, 0x40084010,
418        0x00084010, 0x00000010, 0x00004000, 0x40000000,
419        0x00004010, 0x40084000, 0x00080000, 0x40000010,
420        0x00080010, 0x40004010, 0x40000010, 0x00080010,
421        0x00084000, 0x00000000, 0x40004000, 0x00004010,
422        0x40000000, 0x40080010, 0x40084010, 0x00084000
423    ];
424
425    /**
426     * Pre-permuted S-box3
427     *
428     * @var array
429     */
430    protected static $sbox3 = [
431        0x00000104, 0x04010100, 0x00000000, 0x04010004,
432        0x04000100, 0x00000000, 0x00010104, 0x04000100,
433        0x00010004, 0x04000004, 0x04000004, 0x00010000,
434        0x04010104, 0x00010004, 0x04010000, 0x00000104,
435        0x04000000, 0x00000004, 0x04010100, 0x00000100,
436        0x00010100, 0x04010000, 0x04010004, 0x00010104,
437        0x04000104, 0x00010100, 0x00010000, 0x04000104,
438        0x00000004, 0x04010104, 0x00000100, 0x04000000,
439        0x04010100, 0x04000000, 0x00010004, 0x00000104,
440        0x00010000, 0x04010100, 0x04000100, 0x00000000,
441        0x00000100, 0x00010004, 0x04010104, 0x04000100,
442        0x04000004, 0x00000100, 0x00000000, 0x04010004,
443        0x04000104, 0x00010000, 0x04000000, 0x04010104,
444        0x00000004, 0x00010104, 0x00010100, 0x04000004,
445        0x04010000, 0x04000104, 0x00000104, 0x04010000,
446        0x00010104, 0x00000004, 0x04010004, 0x00010100
447    ];
448
449    /**
450     * Pre-permuted S-box4
451     *
452     * @var array
453     */
454    protected static $sbox4 = [
455        0x80401000, 0x80001040, 0x80001040, 0x00000040,
456        0x00401040, 0x80400040, 0x80400000, 0x80001000,
457        0x00000000, 0x00401000, 0x00401000, 0x80401040,
458        0x80000040, 0x00000000, 0x00400040, 0x80400000,
459        0x80000000, 0x00001000, 0x00400000, 0x80401000,
460        0x00000040, 0x00400000, 0x80001000, 0x00001040,
461        0x80400040, 0x80000000, 0x00001040, 0x00400040,
462        0x00001000, 0x00401040, 0x80401040, 0x80000040,
463        0x00400040, 0x80400000, 0x00401000, 0x80401040,
464        0x80000040, 0x00000000, 0x00000000, 0x00401000,
465        0x00001040, 0x00400040, 0x80400040, 0x80000000,
466        0x80401000, 0x80001040, 0x80001040, 0x00000040,
467        0x80401040, 0x80000040, 0x80000000, 0x00001000,
468        0x80400000, 0x80001000, 0x00401040, 0x80400040,
469        0x80001000, 0x00001040, 0x00400000, 0x80401000,
470        0x00000040, 0x00400000, 0x00001000, 0x00401040
471    ];
472
473    /**
474     * Pre-permuted S-box5
475     *
476     * @var array
477     */
478    protected static $sbox5 = [
479        0x00000080, 0x01040080, 0x01040000, 0x21000080,
480        0x00040000, 0x00000080, 0x20000000, 0x01040000,
481        0x20040080, 0x00040000, 0x01000080, 0x20040080,
482        0x21000080, 0x21040000, 0x00040080, 0x20000000,
483        0x01000000, 0x20040000, 0x20040000, 0x00000000,
484        0x20000080, 0x21040080, 0x21040080, 0x01000080,
485        0x21040000, 0x20000080, 0x00000000, 0x21000000,
486        0x01040080, 0x01000000, 0x21000000, 0x00040080,
487        0x00040000, 0x21000080, 0x00000080, 0x01000000,
488        0x20000000, 0x01040000, 0x21000080, 0x20040080,
489        0x01000080, 0x20000000, 0x21040000, 0x01040080,
490        0x20040080, 0x00000080, 0x01000000, 0x21040000,
491        0x21040080, 0x00040080, 0x21000000, 0x21040080,
492        0x01040000, 0x00000000, 0x20040000, 0x21000000,
493        0x00040080, 0x01000080, 0x20000080, 0x00040000,
494        0x00000000, 0x20040000, 0x01040080, 0x20000080
495    ];
496
497    /**
498     * Pre-permuted S-box6
499     *
500     * @var array
501     */
502    protected static $sbox6 = [
503        0x10000008, 0x10200000, 0x00002000, 0x10202008,
504        0x10200000, 0x00000008, 0x10202008, 0x00200000,
505        0x10002000, 0x00202008, 0x00200000, 0x10000008,
506        0x00200008, 0x10002000, 0x10000000, 0x00002008,
507        0x00000000, 0x00200008, 0x10002008, 0x00002000,
508        0x00202000, 0x10002008, 0x00000008, 0x10200008,
509        0x10200008, 0x00000000, 0x00202008, 0x10202000,
510        0x00002008, 0x00202000, 0x10202000, 0x10000000,
511        0x10002000, 0x00000008, 0x10200008, 0x00202000,
512        0x10202008, 0x00200000, 0x00002008, 0x10000008,
513        0x00200000, 0x10002000, 0x10000000, 0x00002008,
514        0x10000008, 0x10202008, 0x00202000, 0x10200000,
515        0x00202008, 0x10202000, 0x00000000, 0x10200008,
516        0x00000008, 0x00002000, 0x10200000, 0x00202008,
517        0x00002000, 0x00200008, 0x10002008, 0x00000000,
518        0x10202000, 0x10000000, 0x00200008, 0x10002008
519    ];
520
521    /**
522     * Pre-permuted S-box7
523     *
524     * @var array
525     */
526    protected static $sbox7 = [
527        0x00100000, 0x02100001, 0x02000401, 0x00000000,
528        0x00000400, 0x02000401, 0x00100401, 0x02100400,
529        0x02100401, 0x00100000, 0x00000000, 0x02000001,
530        0x00000001, 0x02000000, 0x02100001, 0x00000401,
531        0x02000400, 0x00100401, 0x00100001, 0x02000400,
532        0x02000001, 0x02100000, 0x02100400, 0x00100001,
533        0x02100000, 0x00000400, 0x00000401, 0x02100401,
534        0x00100400, 0x00000001, 0x02000000, 0x00100400,
535        0x02000000, 0x00100400, 0x00100000, 0x02000401,
536        0x02000401, 0x02100001, 0x02100001, 0x00000001,
537        0x00100001, 0x02000000, 0x02000400, 0x00100000,
538        0x02100400, 0x00000401, 0x00100401, 0x02100400,
539        0x00000401, 0x02000001, 0x02100401, 0x02100000,
540        0x00100400, 0x00000000, 0x00000001, 0x02100401,
541        0x00000000, 0x00100401, 0x02100000, 0x00000400,
542        0x02000001, 0x02000400, 0x00000400, 0x00100001
543    ];
544
545    /**
546     * Pre-permuted S-box8
547     *
548     * @var array
549     */
550    protected static $sbox8 = [
551        0x08000820, 0x00000800, 0x00020000, 0x08020820,
552        0x08000000, 0x08000820, 0x00000020, 0x08000000,
553        0x00020020, 0x08020000, 0x08020820, 0x00020800,
554        0x08020800, 0x00020820, 0x00000800, 0x00000020,
555        0x08020000, 0x08000020, 0x08000800, 0x00000820,
556        0x00020800, 0x00020020, 0x08020020, 0x08020800,
557        0x00000820, 0x00000000, 0x00000000, 0x08020020,
558        0x08000020, 0x08000800, 0x00020820, 0x00020000,
559        0x00020820, 0x00020000, 0x08020800, 0x00000800,
560        0x00000020, 0x08020020, 0x00000800, 0x00020820,
561        0x08000800, 0x00000020, 0x08000020, 0x08020000,
562        0x08020020, 0x08000000, 0x00020000, 0x08000820,
563        0x00000000, 0x08020820, 0x00020020, 0x08000020,
564        0x08020000, 0x08000800, 0x08000820, 0x00000000,
565        0x08020820, 0x00020800, 0x00020800, 0x00000820,
566        0x00000820, 0x00020020, 0x08000000, 0x08020800
567    ];
568
569    /**
570     * Default Constructor.
571     *
572     * @param string $mode
573     * @throws BadModeException if an invalid / unsupported mode is provided
574     */
575    public function __construct($mode)
576    {
577        parent::__construct($mode);
578
579        if ($this->mode == self::MODE_STREAM) {
580            throw new BadModeException('Block ciphers cannot be ran in stream mode');
581        }
582    }
583
584    /**
585     * Test for engine validity
586     *
587     * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
588     *
589     * @see \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
590     * @param int $engine
591     * @return bool
592     */
593    protected function isValidEngineHelper($engine)
594    {
595        if ($this->key_length_max == 8) {
596            if ($engine == self::ENGINE_OPENSSL) {
597                // quoting https://www.openssl.org/news/openssl-3.0-notes.html, OpenSSL 3.0.1
598                // "Moved all variations of the EVP ciphers CAST5, BF, IDEA, SEED, RC2, RC4, RC5, and DES to the legacy provider"
599                // in theory openssl_get_cipher_methods() should catch this but, on GitHub Actions, at least, it does not
600                if (defined('OPENSSL_VERSION_TEXT') && version_compare(preg_replace('#OpenSSL (\d+\.\d+\.\d+) .*#', '$1', OPENSSL_VERSION_TEXT), '3.0.1', '>=')) {
601                    return false;
602                }
603                $this->cipher_name_openssl_ecb = 'des-ecb';
604                $this->cipher_name_openssl = 'des-' . $this->openssl_translate_mode();
605            }
606        }
607
608        return parent::isValidEngineHelper($engine);
609    }
610
611    /**
612     * Sets the key.
613     *
614     * Keys must be 64-bits long or 8 bytes long.
615     *
616     * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
617     *
618     * @see \phpseclib3\Crypt\Common\SymmetricKey::setKey()
619     * @param string $key
620     */
621    public function setKey($key)
622    {
623        if (!($this instanceof TripleDES) && strlen($key) != 8) {
624            throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of size 8 are supported');
625        }
626
627        // Sets the key
628        parent::setKey($key);
629    }
630
631    /**
632     * Encrypts a block
633     *
634     * @see \phpseclib3\Crypt\Common\SymmetricKey::encryptBlock()
635     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
636     * @see self::encrypt()
637     * @param string $in
638     * @return string
639     */
640    protected function encryptBlock($in)
641    {
642        return $this->processBlock($in, self::ENCRYPT);
643    }
644
645    /**
646     * Decrypts a block
647     *
648     * @see \phpseclib3\Crypt\Common\SymmetricKey::decryptBlock()
649     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
650     * @see self::decrypt()
651     * @param string $in
652     * @return string
653     */
654    protected function decryptBlock($in)
655    {
656        return $this->processBlock($in, self::DECRYPT);
657    }
658
659    /**
660     * Encrypts or decrypts a 64-bit block
661     *
662     * $mode should be either self::ENCRYPT or self::DECRYPT.  See
663     * {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general
664     * idea of what this function does.
665     *
666     * @see self::encryptBlock()
667     * @see self::decryptBlock()
668     * @param string $block
669     * @param int $mode
670     * @return string
671     */
672    private function processBlock($block, $mode)
673    {
674        static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
675        if (!$sbox1) {
676            $sbox1 = array_map('intval', self::$sbox1);
677            $sbox2 = array_map('intval', self::$sbox2);
678            $sbox3 = array_map('intval', self::$sbox3);
679            $sbox4 = array_map('intval', self::$sbox4);
680            $sbox5 = array_map('intval', self::$sbox5);
681            $sbox6 = array_map('intval', self::$sbox6);
682            $sbox7 = array_map('intval', self::$sbox7);
683            $sbox8 = array_map('intval', self::$sbox8);
684            /* Merge $shuffle with $[inv]ipmap */
685            for ($i = 0; $i < 256; ++$i) {
686                $shuffleip[]    =  self::$shuffle[self::$ipmap[$i]];
687                $shuffleinvip[] =  self::$shuffle[self::$invipmap[$i]];
688            }
689        }
690
691        $keys  = $this->keys[$mode];
692        $ki    = -1;
693
694        // Do the initial IP permutation.
695        $t = unpack('Nl/Nr', $block);
696        list($l, $r) = [$t['l'], $t['r']];
697        $block = ($shuffleip[ $r        & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
698                 ($shuffleip[($r >>  8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
699                 ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
700                 ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
701                 ($shuffleip[ $l        & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
702                 ($shuffleip[($l >>  8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
703                 ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
704                 ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
705
706        // Extract L0 and R0.
707        $t = unpack('Nl/Nr', $block);
708        list($l, $r) = [$t['l'], $t['r']];
709
710        for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {
711            // Perform the 16 steps.
712            for ($i = 0; $i < 16; $i++) {
713                // start of "the Feistel (F) function" - see the following URL:
714                // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
715                // Merge key schedule.
716                $b1 = (($r >>  3) & 0x1FFFFFFF) ^ ($r << 29) ^ $keys[++$ki];
717                $b2 = (($r >> 31) & 0x00000001) ^ ($r <<  1) ^ $keys[++$ki];
718
719                // S-box indexing.
720                $t = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
721                     $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
722                     $sbox5[($b1 >>  8) & 0x3F] ^ $sbox6[($b2 >>  8) & 0x3F] ^
723                     $sbox7[ $b1        & 0x3F] ^ $sbox8[ $b2        & 0x3F] ^ $l;
724                // end of "the Feistel (F) function"
725
726                $l = $r;
727                $r = $t;
728            }
729
730            // Last step should not permute L & R.
731            $t = $l;
732            $l = $r;
733            $r = $t;
734        }
735
736        // Perform the inverse IP permutation.
737        return ($shuffleinvip[($r >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
738               ($shuffleinvip[($l >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
739               ($shuffleinvip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
740               ($shuffleinvip[($l >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
741               ($shuffleinvip[($r >>  8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
742               ($shuffleinvip[($l >>  8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
743               ($shuffleinvip[ $r        & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
744               ($shuffleinvip[ $l        & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
745    }
746
747    /**
748     * Creates the key schedule
749     *
750     * @see \phpseclib3\Crypt\Common\SymmetricKey::setupKey()
751     */
752    protected function setupKey()
753    {
754        if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->des_rounds === $this->kl['des_rounds']) {
755            // already expanded
756            return;
757        }
758        $this->kl = ['key' => $this->key, 'des_rounds' => $this->des_rounds];
759
760        static $shifts = [ // number of key bits shifted per round
761            1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
762        ];
763
764        static $pc1map = [
765            0x00, 0x00, 0x08, 0x08, 0x04, 0x04, 0x0C, 0x0C,
766            0x02, 0x02, 0x0A, 0x0A, 0x06, 0x06, 0x0E, 0x0E,
767            0x10, 0x10, 0x18, 0x18, 0x14, 0x14, 0x1C, 0x1C,
768            0x12, 0x12, 0x1A, 0x1A, 0x16, 0x16, 0x1E, 0x1E,
769            0x20, 0x20, 0x28, 0x28, 0x24, 0x24, 0x2C, 0x2C,
770            0x22, 0x22, 0x2A, 0x2A, 0x26, 0x26, 0x2E, 0x2E,
771            0x30, 0x30, 0x38, 0x38, 0x34, 0x34, 0x3C, 0x3C,
772            0x32, 0x32, 0x3A, 0x3A, 0x36, 0x36, 0x3E, 0x3E,
773            0x40, 0x40, 0x48, 0x48, 0x44, 0x44, 0x4C, 0x4C,
774            0x42, 0x42, 0x4A, 0x4A, 0x46, 0x46, 0x4E, 0x4E,
775            0x50, 0x50, 0x58, 0x58, 0x54, 0x54, 0x5C, 0x5C,
776            0x52, 0x52, 0x5A, 0x5A, 0x56, 0x56, 0x5E, 0x5E,
777            0x60, 0x60, 0x68, 0x68, 0x64, 0x64, 0x6C, 0x6C,
778            0x62, 0x62, 0x6A, 0x6A, 0x66, 0x66, 0x6E, 0x6E,
779            0x70, 0x70, 0x78, 0x78, 0x74, 0x74, 0x7C, 0x7C,
780            0x72, 0x72, 0x7A, 0x7A, 0x76, 0x76, 0x7E, 0x7E,
781            0x80, 0x80, 0x88, 0x88, 0x84, 0x84, 0x8C, 0x8C,
782            0x82, 0x82, 0x8A, 0x8A, 0x86, 0x86, 0x8E, 0x8E,
783            0x90, 0x90, 0x98, 0x98, 0x94, 0x94, 0x9C, 0x9C,
784            0x92, 0x92, 0x9A, 0x9A, 0x96, 0x96, 0x9E, 0x9E,
785            0xA0, 0xA0, 0xA8, 0xA8, 0xA4, 0xA4, 0xAC, 0xAC,
786            0xA2, 0xA2, 0xAA, 0xAA, 0xA6, 0xA6, 0xAE, 0xAE,
787            0xB0, 0xB0, 0xB8, 0xB8, 0xB4, 0xB4, 0xBC, 0xBC,
788            0xB2, 0xB2, 0xBA, 0xBA, 0xB6, 0xB6, 0xBE, 0xBE,
789            0xC0, 0xC0, 0xC8, 0xC8, 0xC4, 0xC4, 0xCC, 0xCC,
790            0xC2, 0xC2, 0xCA, 0xCA, 0xC6, 0xC6, 0xCE, 0xCE,
791            0xD0, 0xD0, 0xD8, 0xD8, 0xD4, 0xD4, 0xDC, 0xDC,
792            0xD2, 0xD2, 0xDA, 0xDA, 0xD6, 0xD6, 0xDE, 0xDE,
793            0xE0, 0xE0, 0xE8, 0xE8, 0xE4, 0xE4, 0xEC, 0xEC,
794            0xE2, 0xE2, 0xEA, 0xEA, 0xE6, 0xE6, 0xEE, 0xEE,
795            0xF0, 0xF0, 0xF8, 0xF8, 0xF4, 0xF4, 0xFC, 0xFC,
796            0xF2, 0xF2, 0xFA, 0xFA, 0xF6, 0xF6, 0xFE, 0xFE
797        ];
798
799        // Mapping tables for the PC-2 transformation.
800        static $pc2mapc1 = [
801            0x00000000, 0x00000400, 0x00200000, 0x00200400,
802            0x00000001, 0x00000401, 0x00200001, 0x00200401,
803            0x02000000, 0x02000400, 0x02200000, 0x02200400,
804            0x02000001, 0x02000401, 0x02200001, 0x02200401
805        ];
806        static $pc2mapc2 = [
807            0x00000000, 0x00000800, 0x08000000, 0x08000800,
808            0x00010000, 0x00010800, 0x08010000, 0x08010800,
809            0x00000000, 0x00000800, 0x08000000, 0x08000800,
810            0x00010000, 0x00010800, 0x08010000, 0x08010800,
811            0x00000100, 0x00000900, 0x08000100, 0x08000900,
812            0x00010100, 0x00010900, 0x08010100, 0x08010900,
813            0x00000100, 0x00000900, 0x08000100, 0x08000900,
814            0x00010100, 0x00010900, 0x08010100, 0x08010900,
815            0x00000010, 0x00000810, 0x08000010, 0x08000810,
816            0x00010010, 0x00010810, 0x08010010, 0x08010810,
817            0x00000010, 0x00000810, 0x08000010, 0x08000810,
818            0x00010010, 0x00010810, 0x08010010, 0x08010810,
819            0x00000110, 0x00000910, 0x08000110, 0x08000910,
820            0x00010110, 0x00010910, 0x08010110, 0x08010910,
821            0x00000110, 0x00000910, 0x08000110, 0x08000910,
822            0x00010110, 0x00010910, 0x08010110, 0x08010910,
823            0x00040000, 0x00040800, 0x08040000, 0x08040800,
824            0x00050000, 0x00050800, 0x08050000, 0x08050800,
825            0x00040000, 0x00040800, 0x08040000, 0x08040800,
826            0x00050000, 0x00050800, 0x08050000, 0x08050800,
827            0x00040100, 0x00040900, 0x08040100, 0x08040900,
828            0x00050100, 0x00050900, 0x08050100, 0x08050900,
829            0x00040100, 0x00040900, 0x08040100, 0x08040900,
830            0x00050100, 0x00050900, 0x08050100, 0x08050900,
831            0x00040010, 0x00040810, 0x08040010, 0x08040810,
832            0x00050010, 0x00050810, 0x08050010, 0x08050810,
833            0x00040010, 0x00040810, 0x08040010, 0x08040810,
834            0x00050010, 0x00050810, 0x08050010, 0x08050810,
835            0x00040110, 0x00040910, 0x08040110, 0x08040910,
836            0x00050110, 0x00050910, 0x08050110, 0x08050910,
837            0x00040110, 0x00040910, 0x08040110, 0x08040910,
838            0x00050110, 0x00050910, 0x08050110, 0x08050910,
839            0x01000000, 0x01000800, 0x09000000, 0x09000800,
840            0x01010000, 0x01010800, 0x09010000, 0x09010800,
841            0x01000000, 0x01000800, 0x09000000, 0x09000800,
842            0x01010000, 0x01010800, 0x09010000, 0x09010800,
843            0x01000100, 0x01000900, 0x09000100, 0x09000900,
844            0x01010100, 0x01010900, 0x09010100, 0x09010900,
845            0x01000100, 0x01000900, 0x09000100, 0x09000900,
846            0x01010100, 0x01010900, 0x09010100, 0x09010900,
847            0x01000010, 0x01000810, 0x09000010, 0x09000810,
848            0x01010010, 0x01010810, 0x09010010, 0x09010810,
849            0x01000010, 0x01000810, 0x09000010, 0x09000810,
850            0x01010010, 0x01010810, 0x09010010, 0x09010810,
851            0x01000110, 0x01000910, 0x09000110, 0x09000910,
852            0x01010110, 0x01010910, 0x09010110, 0x09010910,
853            0x01000110, 0x01000910, 0x09000110, 0x09000910,
854            0x01010110, 0x01010910, 0x09010110, 0x09010910,
855            0x01040000, 0x01040800, 0x09040000, 0x09040800,
856            0x01050000, 0x01050800, 0x09050000, 0x09050800,
857            0x01040000, 0x01040800, 0x09040000, 0x09040800,
858            0x01050000, 0x01050800, 0x09050000, 0x09050800,
859            0x01040100, 0x01040900, 0x09040100, 0x09040900,
860            0x01050100, 0x01050900, 0x09050100, 0x09050900,
861            0x01040100, 0x01040900, 0x09040100, 0x09040900,
862            0x01050100, 0x01050900, 0x09050100, 0x09050900,
863            0x01040010, 0x01040810, 0x09040010, 0x09040810,
864            0x01050010, 0x01050810, 0x09050010, 0x09050810,
865            0x01040010, 0x01040810, 0x09040010, 0x09040810,
866            0x01050010, 0x01050810, 0x09050010, 0x09050810,
867            0x01040110, 0x01040910, 0x09040110, 0x09040910,
868            0x01050110, 0x01050910, 0x09050110, 0x09050910,
869            0x01040110, 0x01040910, 0x09040110, 0x09040910,
870            0x01050110, 0x01050910, 0x09050110, 0x09050910
871        ];
872        static $pc2mapc3 = [
873            0x00000000, 0x00000004, 0x00001000, 0x00001004,
874            0x00000000, 0x00000004, 0x00001000, 0x00001004,
875            0x10000000, 0x10000004, 0x10001000, 0x10001004,
876            0x10000000, 0x10000004, 0x10001000, 0x10001004,
877            0x00000020, 0x00000024, 0x00001020, 0x00001024,
878            0x00000020, 0x00000024, 0x00001020, 0x00001024,
879            0x10000020, 0x10000024, 0x10001020, 0x10001024,
880            0x10000020, 0x10000024, 0x10001020, 0x10001024,
881            0x00080000, 0x00080004, 0x00081000, 0x00081004,
882            0x00080000, 0x00080004, 0x00081000, 0x00081004,
883            0x10080000, 0x10080004, 0x10081000, 0x10081004,
884            0x10080000, 0x10080004, 0x10081000, 0x10081004,
885            0x00080020, 0x00080024, 0x00081020, 0x00081024,
886            0x00080020, 0x00080024, 0x00081020, 0x00081024,
887            0x10080020, 0x10080024, 0x10081020, 0x10081024,
888            0x10080020, 0x10080024, 0x10081020, 0x10081024,
889            0x20000000, 0x20000004, 0x20001000, 0x20001004,
890            0x20000000, 0x20000004, 0x20001000, 0x20001004,
891            0x30000000, 0x30000004, 0x30001000, 0x30001004,
892            0x30000000, 0x30000004, 0x30001000, 0x30001004,
893            0x20000020, 0x20000024, 0x20001020, 0x20001024,
894            0x20000020, 0x20000024, 0x20001020, 0x20001024,
895            0x30000020, 0x30000024, 0x30001020, 0x30001024,
896            0x30000020, 0x30000024, 0x30001020, 0x30001024,
897            0x20080000, 0x20080004, 0x20081000, 0x20081004,
898            0x20080000, 0x20080004, 0x20081000, 0x20081004,
899            0x30080000, 0x30080004, 0x30081000, 0x30081004,
900            0x30080000, 0x30080004, 0x30081000, 0x30081004,
901            0x20080020, 0x20080024, 0x20081020, 0x20081024,
902            0x20080020, 0x20080024, 0x20081020, 0x20081024,
903            0x30080020, 0x30080024, 0x30081020, 0x30081024,
904            0x30080020, 0x30080024, 0x30081020, 0x30081024,
905            0x00000002, 0x00000006, 0x00001002, 0x00001006,
906            0x00000002, 0x00000006, 0x00001002, 0x00001006,
907            0x10000002, 0x10000006, 0x10001002, 0x10001006,
908            0x10000002, 0x10000006, 0x10001002, 0x10001006,
909            0x00000022, 0x00000026, 0x00001022, 0x00001026,
910            0x00000022, 0x00000026, 0x00001022, 0x00001026,
911            0x10000022, 0x10000026, 0x10001022, 0x10001026,
912            0x10000022, 0x10000026, 0x10001022, 0x10001026,
913            0x00080002, 0x00080006, 0x00081002, 0x00081006,
914            0x00080002, 0x00080006, 0x00081002, 0x00081006,
915            0x10080002, 0x10080006, 0x10081002, 0x10081006,
916            0x10080002, 0x10080006, 0x10081002, 0x10081006,
917            0x00080022, 0x00080026, 0x00081022, 0x00081026,
918            0x00080022, 0x00080026, 0x00081022, 0x00081026,
919            0x10080022, 0x10080026, 0x10081022, 0x10081026,
920            0x10080022, 0x10080026, 0x10081022, 0x10081026,
921            0x20000002, 0x20000006, 0x20001002, 0x20001006,
922            0x20000002, 0x20000006, 0x20001002, 0x20001006,
923            0x30000002, 0x30000006, 0x30001002, 0x30001006,
924            0x30000002, 0x30000006, 0x30001002, 0x30001006,
925            0x20000022, 0x20000026, 0x20001022, 0x20001026,
926            0x20000022, 0x20000026, 0x20001022, 0x20001026,
927            0x30000022, 0x30000026, 0x30001022, 0x30001026,
928            0x30000022, 0x30000026, 0x30001022, 0x30001026,
929            0x20080002, 0x20080006, 0x20081002, 0x20081006,
930            0x20080002, 0x20080006, 0x20081002, 0x20081006,
931            0x30080002, 0x30080006, 0x30081002, 0x30081006,
932            0x30080002, 0x30080006, 0x30081002, 0x30081006,
933            0x20080022, 0x20080026, 0x20081022, 0x20081026,
934            0x20080022, 0x20080026, 0x20081022, 0x20081026,
935            0x30080022, 0x30080026, 0x30081022, 0x30081026,
936            0x30080022, 0x30080026, 0x30081022, 0x30081026
937        ];
938        static $pc2mapc4 = [
939            0x00000000, 0x00100000, 0x00000008, 0x00100008,
940            0x00000200, 0x00100200, 0x00000208, 0x00100208,
941            0x00000000, 0x00100000, 0x00000008, 0x00100008,
942            0x00000200, 0x00100200, 0x00000208, 0x00100208,
943            0x04000000, 0x04100000, 0x04000008, 0x04100008,
944            0x04000200, 0x04100200, 0x04000208, 0x04100208,
945            0x04000000, 0x04100000, 0x04000008, 0x04100008,
946            0x04000200, 0x04100200, 0x04000208, 0x04100208,
947            0x00002000, 0x00102000, 0x00002008, 0x00102008,
948            0x00002200, 0x00102200, 0x00002208, 0x00102208,
949            0x00002000, 0x00102000, 0x00002008, 0x00102008,
950            0x00002200, 0x00102200, 0x00002208, 0x00102208,
951            0x04002000, 0x04102000, 0x04002008, 0x04102008,
952            0x04002200, 0x04102200, 0x04002208, 0x04102208,
953            0x04002000, 0x04102000, 0x04002008, 0x04102008,
954            0x04002200, 0x04102200, 0x04002208, 0x04102208,
955            0x00000000, 0x00100000, 0x00000008, 0x00100008,
956            0x00000200, 0x00100200, 0x00000208, 0x00100208,
957            0x00000000, 0x00100000, 0x00000008, 0x00100008,
958            0x00000200, 0x00100200, 0x00000208, 0x00100208,
959            0x04000000, 0x04100000, 0x04000008, 0x04100008,
960            0x04000200, 0x04100200, 0x04000208, 0x04100208,
961            0x04000000, 0x04100000, 0x04000008, 0x04100008,
962            0x04000200, 0x04100200, 0x04000208, 0x04100208,
963            0x00002000, 0x00102000, 0x00002008, 0x00102008,
964            0x00002200, 0x00102200, 0x00002208, 0x00102208,
965            0x00002000, 0x00102000, 0x00002008, 0x00102008,
966            0x00002200, 0x00102200, 0x00002208, 0x00102208,
967            0x04002000, 0x04102000, 0x04002008, 0x04102008,
968            0x04002200, 0x04102200, 0x04002208, 0x04102208,
969            0x04002000, 0x04102000, 0x04002008, 0x04102008,
970            0x04002200, 0x04102200, 0x04002208, 0x04102208,
971            0x00020000, 0x00120000, 0x00020008, 0x00120008,
972            0x00020200, 0x00120200, 0x00020208, 0x00120208,
973            0x00020000, 0x00120000, 0x00020008, 0x00120008,
974            0x00020200, 0x00120200, 0x00020208, 0x00120208,
975            0x04020000, 0x04120000, 0x04020008, 0x04120008,
976            0x04020200, 0x04120200, 0x04020208, 0x04120208,
977            0x04020000, 0x04120000, 0x04020008, 0x04120008,
978            0x04020200, 0x04120200, 0x04020208, 0x04120208,
979            0x00022000, 0x00122000, 0x00022008, 0x00122008,
980            0x00022200, 0x00122200, 0x00022208, 0x00122208,
981            0x00022000, 0x00122000, 0x00022008, 0x00122008,
982            0x00022200, 0x00122200, 0x00022208, 0x00122208,
983            0x04022000, 0x04122000, 0x04022008, 0x04122008,
984            0x04022200, 0x04122200, 0x04022208, 0x04122208,
985            0x04022000, 0x04122000, 0x04022008, 0x04122008,
986            0x04022200, 0x04122200, 0x04022208, 0x04122208,
987            0x00020000, 0x00120000, 0x00020008, 0x00120008,
988            0x00020200, 0x00120200, 0x00020208, 0x00120208,
989            0x00020000, 0x00120000, 0x00020008, 0x00120008,
990            0x00020200, 0x00120200, 0x00020208, 0x00120208,
991            0x04020000, 0x04120000, 0x04020008, 0x04120008,
992            0x04020200, 0x04120200, 0x04020208, 0x04120208,
993            0x04020000, 0x04120000, 0x04020008, 0x04120008,
994            0x04020200, 0x04120200, 0x04020208, 0x04120208,
995            0x00022000, 0x00122000, 0x00022008, 0x00122008,
996            0x00022200, 0x00122200, 0x00022208, 0x00122208,
997            0x00022000, 0x00122000, 0x00022008, 0x00122008,
998            0x00022200, 0x00122200, 0x00022208, 0x00122208,
999            0x04022000, 0x04122000, 0x04022008, 0x04122008,
1000            0x04022200, 0x04122200, 0x04022208, 0x04122208,
1001            0x04022000, 0x04122000, 0x04022008, 0x04122008,
1002            0x04022200, 0x04122200, 0x04022208, 0x04122208
1003        ];
1004        static $pc2mapd1 = [
1005            0x00000000, 0x00000001, 0x08000000, 0x08000001,
1006            0x00200000, 0x00200001, 0x08200000, 0x08200001,
1007            0x00000002, 0x00000003, 0x08000002, 0x08000003,
1008            0x00200002, 0x00200003, 0x08200002, 0x08200003
1009        ];
1010        static $pc2mapd2 = [
1011            0x00000000, 0x00100000, 0x00000800, 0x00100800,
1012            0x00000000, 0x00100000, 0x00000800, 0x00100800,
1013            0x04000000, 0x04100000, 0x04000800, 0x04100800,
1014            0x04000000, 0x04100000, 0x04000800, 0x04100800,
1015            0x00000004, 0x00100004, 0x00000804, 0x00100804,
1016            0x00000004, 0x00100004, 0x00000804, 0x00100804,
1017            0x04000004, 0x04100004, 0x04000804, 0x04100804,
1018            0x04000004, 0x04100004, 0x04000804, 0x04100804,
1019            0x00000000, 0x00100000, 0x00000800, 0x00100800,
1020            0x00000000, 0x00100000, 0x00000800, 0x00100800,
1021            0x04000000, 0x04100000, 0x04000800, 0x04100800,
1022            0x04000000, 0x04100000, 0x04000800, 0x04100800,
1023            0x00000004, 0x00100004, 0x00000804, 0x00100804,
1024            0x00000004, 0x00100004, 0x00000804, 0x00100804,
1025            0x04000004, 0x04100004, 0x04000804, 0x04100804,
1026            0x04000004, 0x04100004, 0x04000804, 0x04100804,
1027            0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1028            0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1029            0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1030            0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1031            0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1032            0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1033            0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1034            0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1035            0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1036            0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1037            0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1038            0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1039            0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1040            0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1041            0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1042            0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1043            0x00020000, 0x00120000, 0x00020800, 0x00120800,
1044            0x00020000, 0x00120000, 0x00020800, 0x00120800,
1045            0x04020000, 0x04120000, 0x04020800, 0x04120800,
1046            0x04020000, 0x04120000, 0x04020800, 0x04120800,
1047            0x00020004, 0x00120004, 0x00020804, 0x00120804,
1048            0x00020004, 0x00120004, 0x00020804, 0x00120804,
1049            0x04020004, 0x04120004, 0x04020804, 0x04120804,
1050            0x04020004, 0x04120004, 0x04020804, 0x04120804,
1051            0x00020000, 0x00120000, 0x00020800, 0x00120800,
1052            0x00020000, 0x00120000, 0x00020800, 0x00120800,
1053            0x04020000, 0x04120000, 0x04020800, 0x04120800,
1054            0x04020000, 0x04120000, 0x04020800, 0x04120800,
1055            0x00020004, 0x00120004, 0x00020804, 0x00120804,
1056            0x00020004, 0x00120004, 0x00020804, 0x00120804,
1057            0x04020004, 0x04120004, 0x04020804, 0x04120804,
1058            0x04020004, 0x04120004, 0x04020804, 0x04120804,
1059            0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1060            0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1061            0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1062            0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1063            0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1064            0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1065            0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
1066            0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
1067            0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1068            0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1069            0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1070            0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1071            0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1072            0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1073            0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
1074            0x04020204, 0x04120204, 0x04020A04, 0x04120A04
1075        ];
1076        static $pc2mapd3 = [
1077            0x00000000, 0x00010000, 0x02000000, 0x02010000,
1078            0x00000020, 0x00010020, 0x02000020, 0x02010020,
1079            0x00040000, 0x00050000, 0x02040000, 0x02050000,
1080            0x00040020, 0x00050020, 0x02040020, 0x02050020,
1081            0x00002000, 0x00012000, 0x02002000, 0x02012000,
1082            0x00002020, 0x00012020, 0x02002020, 0x02012020,
1083            0x00042000, 0x00052000, 0x02042000, 0x02052000,
1084            0x00042020, 0x00052020, 0x02042020, 0x02052020,
1085            0x00000000, 0x00010000, 0x02000000, 0x02010000,
1086            0x00000020, 0x00010020, 0x02000020, 0x02010020,
1087            0x00040000, 0x00050000, 0x02040000, 0x02050000,
1088            0x00040020, 0x00050020, 0x02040020, 0x02050020,
1089            0x00002000, 0x00012000, 0x02002000, 0x02012000,
1090            0x00002020, 0x00012020, 0x02002020, 0x02012020,
1091            0x00042000, 0x00052000, 0x02042000, 0x02052000,
1092            0x00042020, 0x00052020, 0x02042020, 0x02052020,
1093            0x00000010, 0x00010010, 0x02000010, 0x02010010,
1094            0x00000030, 0x00010030, 0x02000030, 0x02010030,
1095            0x00040010, 0x00050010, 0x02040010, 0x02050010,
1096            0x00040030, 0x00050030, 0x02040030, 0x02050030,
1097            0x00002010, 0x00012010, 0x02002010, 0x02012010,
1098            0x00002030, 0x00012030, 0x02002030, 0x02012030,
1099            0x00042010, 0x00052010, 0x02042010, 0x02052010,
1100            0x00042030, 0x00052030, 0x02042030, 0x02052030,
1101            0x00000010, 0x00010010, 0x02000010, 0x02010010,
1102            0x00000030, 0x00010030, 0x02000030, 0x02010030,
1103            0x00040010, 0x00050010, 0x02040010, 0x02050010,
1104            0x00040030, 0x00050030, 0x02040030, 0x02050030,
1105            0x00002010, 0x00012010, 0x02002010, 0x02012010,
1106            0x00002030, 0x00012030, 0x02002030, 0x02012030,
1107            0x00042010, 0x00052010, 0x02042010, 0x02052010,
1108            0x00042030, 0x00052030, 0x02042030, 0x02052030,
1109            0x20000000, 0x20010000, 0x22000000, 0x22010000,
1110            0x20000020, 0x20010020, 0x22000020, 0x22010020,
1111            0x20040000, 0x20050000, 0x22040000, 0x22050000,
1112            0x20040020, 0x20050020, 0x22040020, 0x22050020,
1113            0x20002000, 0x20012000, 0x22002000, 0x22012000,
1114            0x20002020, 0x20012020, 0x22002020, 0x22012020,
1115            0x20042000, 0x20052000, 0x22042000, 0x22052000,
1116            0x20042020, 0x20052020, 0x22042020, 0x22052020,
1117            0x20000000, 0x20010000, 0x22000000, 0x22010000,
1118            0x20000020, 0x20010020, 0x22000020, 0x22010020,
1119            0x20040000, 0x20050000, 0x22040000, 0x22050000,
1120            0x20040020, 0x20050020, 0x22040020, 0x22050020,
1121            0x20002000, 0x20012000, 0x22002000, 0x22012000,
1122            0x20002020, 0x20012020, 0x22002020, 0x22012020,
1123            0x20042000, 0x20052000, 0x22042000, 0x22052000,
1124            0x20042020, 0x20052020, 0x22042020, 0x22052020,
1125            0x20000010, 0x20010010, 0x22000010, 0x22010010,
1126            0x20000030, 0x20010030, 0x22000030, 0x22010030,
1127            0x20040010, 0x20050010, 0x22040010, 0x22050010,
1128            0x20040030, 0x20050030, 0x22040030, 0x22050030,
1129            0x20002010, 0x20012010, 0x22002010, 0x22012010,
1130            0x20002030, 0x20012030, 0x22002030, 0x22012030,
1131            0x20042010, 0x20052010, 0x22042010, 0x22052010,
1132            0x20042030, 0x20052030, 0x22042030, 0x22052030,
1133            0x20000010, 0x20010010, 0x22000010, 0x22010010,
1134            0x20000030, 0x20010030, 0x22000030, 0x22010030,
1135            0x20040010, 0x20050010, 0x22040010, 0x22050010,
1136            0x20040030, 0x20050030, 0x22040030, 0x22050030,
1137            0x20002010, 0x20012010, 0x22002010, 0x22012010,
1138            0x20002030, 0x20012030, 0x22002030, 0x22012030,
1139            0x20042010, 0x20052010, 0x22042010, 0x22052010,
1140            0x20042030, 0x20052030, 0x22042030, 0x22052030
1141        ];
1142        static $pc2mapd4 = [
1143            0x00000000, 0x00000400, 0x01000000, 0x01000400,
1144            0x00000000, 0x00000400, 0x01000000, 0x01000400,
1145            0x00000100, 0x00000500, 0x01000100, 0x01000500,
1146            0x00000100, 0x00000500, 0x01000100, 0x01000500,
1147            0x10000000, 0x10000400, 0x11000000, 0x11000400,
1148            0x10000000, 0x10000400, 0x11000000, 0x11000400,
1149            0x10000100, 0x10000500, 0x11000100, 0x11000500,
1150            0x10000100, 0x10000500, 0x11000100, 0x11000500,
1151            0x00080000, 0x00080400, 0x01080000, 0x01080400,
1152            0x00080000, 0x00080400, 0x01080000, 0x01080400,
1153            0x00080100, 0x00080500, 0x01080100, 0x01080500,
1154            0x00080100, 0x00080500, 0x01080100, 0x01080500,
1155            0x10080000, 0x10080400, 0x11080000, 0x11080400,
1156            0x10080000, 0x10080400, 0x11080000, 0x11080400,
1157            0x10080100, 0x10080500, 0x11080100, 0x11080500,
1158            0x10080100, 0x10080500, 0x11080100, 0x11080500,
1159            0x00000008, 0x00000408, 0x01000008, 0x01000408,
1160            0x00000008, 0x00000408, 0x01000008, 0x01000408,
1161            0x00000108, 0x00000508, 0x01000108, 0x01000508,
1162            0x00000108, 0x00000508, 0x01000108, 0x01000508,
1163            0x10000008, 0x10000408, 0x11000008, 0x11000408,
1164            0x10000008, 0x10000408, 0x11000008, 0x11000408,
1165            0x10000108, 0x10000508, 0x11000108, 0x11000508,
1166            0x10000108, 0x10000508, 0x11000108, 0x11000508,
1167            0x00080008, 0x00080408, 0x01080008, 0x01080408,
1168            0x00080008, 0x00080408, 0x01080008, 0x01080408,
1169            0x00080108, 0x00080508, 0x01080108, 0x01080508,
1170            0x00080108, 0x00080508, 0x01080108, 0x01080508,
1171            0x10080008, 0x10080408, 0x11080008, 0x11080408,
1172            0x10080008, 0x10080408, 0x11080008, 0x11080408,
1173            0x10080108, 0x10080508, 0x11080108, 0x11080508,
1174            0x10080108, 0x10080508, 0x11080108, 0x11080508,
1175            0x00001000, 0x00001400, 0x01001000, 0x01001400,
1176            0x00001000, 0x00001400, 0x01001000, 0x01001400,
1177            0x00001100, 0x00001500, 0x01001100, 0x01001500,
1178            0x00001100, 0x00001500, 0x01001100, 0x01001500,
1179            0x10001000, 0x10001400, 0x11001000, 0x11001400,
1180            0x10001000, 0x10001400, 0x11001000, 0x11001400,
1181            0x10001100, 0x10001500, 0x11001100, 0x11001500,
1182            0x10001100, 0x10001500, 0x11001100, 0x11001500,
1183            0x00081000, 0x00081400, 0x01081000, 0x01081400,
1184            0x00081000, 0x00081400, 0x01081000, 0x01081400,
1185            0x00081100, 0x00081500, 0x01081100, 0x01081500,
1186            0x00081100, 0x00081500, 0x01081100, 0x01081500,
1187            0x10081000, 0x10081400, 0x11081000, 0x11081400,
1188            0x10081000, 0x10081400, 0x11081000, 0x11081400,
1189            0x10081100, 0x10081500, 0x11081100, 0x11081500,
1190            0x10081100, 0x10081500, 0x11081100, 0x11081500,
1191            0x00001008, 0x00001408, 0x01001008, 0x01001408,
1192            0x00001008, 0x00001408, 0x01001008, 0x01001408,
1193            0x00001108, 0x00001508, 0x01001108, 0x01001508,
1194            0x00001108, 0x00001508, 0x01001108, 0x01001508,
1195            0x10001008, 0x10001408, 0x11001008, 0x11001408,
1196            0x10001008, 0x10001408, 0x11001008, 0x11001408,
1197            0x10001108, 0x10001508, 0x11001108, 0x11001508,
1198            0x10001108, 0x10001508, 0x11001108, 0x11001508,
1199            0x00081008, 0x00081408, 0x01081008, 0x01081408,
1200            0x00081008, 0x00081408, 0x01081008, 0x01081408,
1201            0x00081108, 0x00081508, 0x01081108, 0x01081508,
1202            0x00081108, 0x00081508, 0x01081108, 0x01081508,
1203            0x10081008, 0x10081408, 0x11081008, 0x11081408,
1204            0x10081008, 0x10081408, 0x11081008, 0x11081408,
1205            0x10081108, 0x10081508, 0x11081108, 0x11081508,
1206            0x10081108, 0x10081508, 0x11081108, 0x11081508
1207        ];
1208
1209        $keys = [];
1210        for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {
1211            // pad the key and remove extra characters as appropriate.
1212            $key = str_pad(substr($this->key, $des_round * 8, 8), 8, "\0");
1213
1214            // Perform the PC/1 transformation and compute C and D.
1215            $t = unpack('Nl/Nr', $key);
1216            list($l, $r) = [$t['l'], $t['r']];
1217            $key = (self::$shuffle[$pc1map[ $r        & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x00") |
1218                   (self::$shuffle[$pc1map[($r >>  8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x00") |
1219                   (self::$shuffle[$pc1map[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x00") |
1220                   (self::$shuffle[$pc1map[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x00") |
1221                   (self::$shuffle[$pc1map[ $l        & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x00") |
1222                   (self::$shuffle[$pc1map[($l >>  8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x00") |
1223                   (self::$shuffle[$pc1map[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x00") |
1224                   (self::$shuffle[$pc1map[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x00");
1225            $key = unpack('Nc/Nd', $key);
1226            $c = ( $key['c'] >> 4) & 0x0FFFFFFF;
1227            $d = (($key['d'] >> 4) & 0x0FFFFFF0) | ($key['c'] & 0x0F);
1228
1229            $keys[$des_round] = [
1230                self::ENCRYPT => [],
1231                self::DECRYPT => array_fill(0, 32, 0)
1232            ];
1233            for ($i = 0, $ki = 31; $i < 16; ++$i, $ki -= 2) {
1234                $c <<= $shifts[$i];
1235                $c = ($c | ($c >> 28)) & 0x0FFFFFFF;
1236                $d <<= $shifts[$i];
1237                $d = ($d | ($d >> 28)) & 0x0FFFFFFF;
1238
1239                // Perform the PC-2 transformation.
1240                $cp = $pc2mapc1[ $c >> 24        ] | $pc2mapc2[($c >> 16) & 0xFF] |
1241                      $pc2mapc3[($c >>  8) & 0xFF] | $pc2mapc4[ $c        & 0xFF];
1242                $dp = $pc2mapd1[ $d >> 24        ] | $pc2mapd2[($d >> 16) & 0xFF] |
1243                      $pc2mapd3[($d >>  8) & 0xFF] | $pc2mapd4[ $d        & 0xFF];
1244
1245                // Reorder: odd bytes/even bytes. Push the result in key schedule.
1246                $val1 = ( $cp        & intval(0xFF000000)) | (($cp <<  8) & 0x00FF0000) |
1247                        (($dp >> 16) & 0x0000FF00) | (($dp >>  8) & 0x000000FF);
1248                $val2 = (($cp <<  8) & intval(0xFF000000)) | (($cp << 16) & 0x00FF0000) |
1249                        (($dp >>  8) & 0x0000FF00) | ( $dp        & 0x000000FF);
1250                $keys[$des_round][self::ENCRYPT][       ] = $val1;
1251                $keys[$des_round][self::DECRYPT][$ki - 1] = $val1;
1252                $keys[$des_round][self::ENCRYPT][       ] = $val2;
1253                $keys[$des_round][self::DECRYPT][$ki    ] = $val2;
1254            }
1255        }
1256
1257        switch ($this->des_rounds) {
1258            case 3: // 3DES keys
1259                $this->keys = [
1260                    self::ENCRYPT => array_merge(
1261                        $keys[0][self::ENCRYPT],
1262                        $keys[1][self::DECRYPT],
1263                        $keys[2][self::ENCRYPT]
1264                    ),
1265                    self::DECRYPT => array_merge(
1266                        $keys[2][self::DECRYPT],
1267                        $keys[1][self::ENCRYPT],
1268                        $keys[0][self::DECRYPT]
1269                    )
1270                ];
1271                break;
1272            // case 1: // DES keys
1273            default:
1274                $this->keys = [
1275                    self::ENCRYPT => $keys[0][self::ENCRYPT],
1276                    self::DECRYPT => $keys[0][self::DECRYPT]
1277                ];
1278        }
1279    }
1280
1281    /**
1282     * Setup the performance-optimized function for de/encrypt()
1283     *
1284     * @see \phpseclib3\Crypt\Common\SymmetricKey::setupInlineCrypt()
1285     */
1286    protected function setupInlineCrypt()
1287    {
1288        // Engine configuration for:
1289        // -  DES ($des_rounds == 1) or
1290        // - 3DES ($des_rounds == 3)
1291        $des_rounds = $this->des_rounds;
1292
1293        $init_crypt = 'static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
1294            if (!$sbox1) {
1295                $sbox1 = array_map("intval", self::$sbox1);
1296                $sbox2 = array_map("intval", self::$sbox2);
1297                $sbox3 = array_map("intval", self::$sbox3);
1298                $sbox4 = array_map("intval", self::$sbox4);
1299                $sbox5 = array_map("intval", self::$sbox5);
1300                $sbox6 = array_map("intval", self::$sbox6);
1301                $sbox7 = array_map("intval", self::$sbox7);
1302                $sbox8 = array_map("intval", self::$sbox8);'
1303                /* Merge $shuffle with $[inv]ipmap */ . '
1304                for ($i = 0; $i < 256; ++$i) {
1305                    $shuffleip[]    =  self::$shuffle[self::$ipmap[$i]];
1306                    $shuffleinvip[] =  self::$shuffle[self::$invipmap[$i]];
1307                }
1308            }
1309        ';
1310
1311        $k = [
1312            self::ENCRYPT => $this->keys[self::ENCRYPT],
1313            self::DECRYPT => $this->keys[self::DECRYPT]
1314        ];
1315        $init_encrypt = '';
1316        $init_decrypt = '';
1317
1318        // Creating code for en- and decryption.
1319        $crypt_block = [];
1320        foreach ([self::ENCRYPT, self::DECRYPT] as $c) {
1321            /* Do the initial IP permutation. */
1322            $crypt_block[$c] = '
1323                $in = unpack("N*", $in);
1324                $l  = $in[1];
1325                $r  = $in[2];
1326                $in = unpack("N*",
1327                    ($shuffleip[ $r        & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
1328                    ($shuffleip[($r >>  8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
1329                    ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
1330                    ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
1331                    ($shuffleip[ $l        & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
1332                    ($shuffleip[($l >>  8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
1333                    ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
1334                    ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01")
1335                );
1336                ' . /* Extract L0 and R0 */ '
1337                $l = $in[1];
1338                $r = $in[2];
1339            ';
1340
1341            $l = '$l';
1342            $r = '$r';
1343
1344            // Perform DES or 3DES.
1345            for ($ki = -1, $des_round = 0; $des_round < $des_rounds; ++$des_round) {
1346                // Perform the 16 steps.
1347                for ($i = 0; $i < 16; ++$i) {
1348                    // start of "the Feistel (F) function" - see the following URL:
1349                    // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
1350                    // Merge key schedule.
1351                    $crypt_block[$c] .= '
1352                        $b1 = ((' . $r . ' >>  3) & 0x1FFFFFFF)  ^ (' . $r . ' << 29) ^ ' . $k[$c][++$ki] . ';
1353                        $b2 = ((' . $r . ' >> 31) & 0x00000001)  ^ (' . $r . ' <<  1) ^ ' . $k[$c][++$ki] . ';' .
1354                        /* S-box indexing. */
1355                        $l . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
1356                                 $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
1357                                 $sbox5[($b1 >>  8) & 0x3F] ^ $sbox6[($b2 >>  8) & 0x3F] ^
1358                                 $sbox7[ $b1        & 0x3F] ^ $sbox8[ $b2        & 0x3F] ^ ' . $l . ';
1359                    ';
1360                    // end of "the Feistel (F) function"
1361
1362                    // swap L & R
1363                    list($l, $r) = [$r, $l];
1364                }
1365                list($l, $r) = [$r, $l];
1366            }
1367
1368            // Perform the inverse IP permutation.
1369            $crypt_block[$c] .= '$in =
1370                ($shuffleinvip[($l >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
1371                ($shuffleinvip[($r >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
1372                ($shuffleinvip[($l >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
1373                ($shuffleinvip[($r >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
1374                ($shuffleinvip[($l >>  8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
1375                ($shuffleinvip[($r >>  8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
1376                ($shuffleinvip[ $l        & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
1377                ($shuffleinvip[ $r        & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
1378            ';
1379        }
1380
1381        // Creates the inline-crypt function
1382        $this->inline_crypt = $this->createInlineCryptFunction(
1383            [
1384               'init_crypt'    => $init_crypt,
1385               'init_encrypt'  => $init_encrypt,
1386               'init_decrypt'  => $init_decrypt,
1387               'encrypt_block' => $crypt_block[self::ENCRYPT],
1388               'decrypt_block' => $crypt_block[self::DECRYPT]
1389            ]
1390        );
1391    }
1392}
1393