Subversion Repositories oidplus

Rev

Rev 874 | Rev 1051 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
827 daniel-mar 1
<?php
2
 
3
/**
4
 * Pure-PHP implementation of RC2.
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://tools.ietf.org/html/rfc2268}
13
 *
14
 * Here's a short example of how to use this library:
15
 * <code>
16
 * <?php
17
 *    include 'vendor/autoload.php';
18
 *
19
 *    $rc2 = new \phpseclib3\Crypt\RC2('ctr');
20
 *
21
 *    $rc2->setKey('abcdefgh');
22
 *
23
 *    $plaintext = str_repeat('a', 1024);
24
 *
25
 *    echo $rc2->decrypt($rc2->encrypt($plaintext));
26
 * ?>
27
 * </code>
28
 *
29
 * @author   Patrick Monnerat <pm@datasphere.ch>
30
 * @license  http://www.opensource.org/licenses/mit-license.html  MIT License
31
 * @link     http://phpseclib.sourceforge.net
32
 */
33
 
34
namespace phpseclib3\Crypt;
35
 
36
use phpseclib3\Crypt\Common\BlockCipher;
37
use phpseclib3\Exception\BadModeException;
38
 
39
/**
40
 * Pure-PHP implementation of RC2.
41
 *
42
 */
43
class RC2 extends BlockCipher
44
{
45
    /**
46
     * Block Length of the cipher
47
     *
48
     * @see \phpseclib3\Crypt\Common\SymmetricKey::block_size
49
     * @var int
50
     */
51
    protected $block_size = 8;
52
 
53
    /**
54
     * The Key
55
     *
56
     * @see \phpseclib3\Crypt\Common\SymmetricKey::key
57
     * @see self::setKey()
58
     * @var string
59
     */
60
    protected $key;
61
 
62
    /**
63
     * The Original (unpadded) Key
64
     *
65
     * @see \phpseclib3\Crypt\Common\SymmetricKey::key
66
     * @see self::setKey()
67
     * @see self::encrypt()
68
     * @see self::decrypt()
69
     * @var string
70
     */
71
    private $orig_key;
72
 
73
    /**
74
     * Key Length (in bytes)
75
     *
76
     * @see \phpseclib3\Crypt\RC2::setKeyLength()
77
     * @var int
78
     */
79
    protected $key_length = 16; // = 128 bits
80
 
81
    /**
82
     * The mcrypt specific name of the cipher
83
     *
84
     * @see \phpseclib3\Crypt\Common\SymmetricKey::cipher_name_mcrypt
85
     * @var string
86
     */
87
    protected $cipher_name_mcrypt = 'rc2';
88
 
89
    /**
90
     * Optimizing value while CFB-encrypting
91
     *
92
     * @see \phpseclib3\Crypt\Common\SymmetricKey::cfb_init_len
93
     * @var int
94
     */
95
    protected $cfb_init_len = 500;
96
 
97
    /**
98
     * The key length in bits.
99
     *
100
     * {@internal Should be in range [1..1024].}
101
     *
102
     * {@internal Changing this value after setting the key has no effect.}
103
     *
104
     * @see self::setKeyLength()
105
     * @see self::setKey()
106
     * @var int
107
     */
108
    private $default_key_length = 1024;
109
 
110
    /**
111
     * The key length in bits.
112
     *
113
     * {@internal Should be in range [1..1024].}
114
     *
115
     * @see self::isValidEnine()
116
     * @see self::setKey()
117
     * @var int
118
     */
119
    private $current_key_length;
120
 
121
    /**
122
     * The Key Schedule
123
     *
124
     * @see self::setupKey()
125
     * @var array
126
     */
127
    private $keys;
128
 
129
    /**
130
     * Key expansion randomization table.
131
     * Twice the same 256-value sequence to save a modulus in key expansion.
132
     *
133
     * @see self::setKey()
134
     * @var array
135
     */
136
    private static $pitable = [
137
        0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
138
        0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
139
        0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
140
        0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
141
        0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
142
        0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
143
        0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
144
        0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
145
        0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
146
        0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
147
        0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
148
        0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
149
        0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
150
        0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
151
        0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
152
        0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
153
        0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
154
        0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
155
        0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
156
        0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
157
        0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
158
        0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
159
        0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
160
        0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
161
        0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
162
        0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
163
        0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
164
        0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
165
        0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
166
        0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
167
        0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
168
        0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD,
169
        0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
170
        0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
171
        0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
172
        0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
173
        0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
174
        0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
175
        0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
176
        0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
177
        0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
178
        0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
179
        0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
180
        0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
181
        0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
182
        0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
183
        0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
184
        0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
185
        0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
186
        0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
187
        0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
188
        0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
189
        0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
190
        0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
191
        0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
192
        0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
193
        0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
194
        0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
195
        0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
196
        0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
197
        0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
198
        0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
199
        0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
200
        0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD
201
    ];
202
 
203
    /**
204
     * Inverse key expansion randomization table.
205
     *
206
     * @see self::setKey()
207
     * @var array
208
     */
209
    private static $invpitable = [
210
        0xD1, 0xDA, 0xB9, 0x6F, 0x9C, 0xC8, 0x78, 0x66,
211
        0x80, 0x2C, 0xF8, 0x37, 0xEA, 0xE0, 0x62, 0xA4,
212
        0xCB, 0x71, 0x50, 0x27, 0x4B, 0x95, 0xD9, 0x20,
213
        0x9D, 0x04, 0x91, 0xE3, 0x47, 0x6A, 0x7E, 0x53,
214
        0xFA, 0x3A, 0x3B, 0xB4, 0xA8, 0xBC, 0x5F, 0x68,
215
        0x08, 0xCA, 0x8F, 0x14, 0xD7, 0xC0, 0xEF, 0x7B,
216
        0x5B, 0xBF, 0x2F, 0xE5, 0xE2, 0x8C, 0xBA, 0x12,
217
        0xE1, 0xAF, 0xB2, 0x54, 0x5D, 0x59, 0x76, 0xDB,
218
        0x32, 0xA2, 0x58, 0x6E, 0x1C, 0x29, 0x64, 0xF3,
219
        0xE9, 0x96, 0x0C, 0x98, 0x19, 0x8D, 0x3E, 0x26,
220
        0xAB, 0xA5, 0x85, 0x16, 0x40, 0xBD, 0x49, 0x67,
221
        0xDC, 0x22, 0x94, 0xBB, 0x3C, 0xC1, 0x9B, 0xEB,
222
        0x45, 0x28, 0x18, 0xD8, 0x1A, 0x42, 0x7D, 0xCC,
223
        0xFB, 0x65, 0x8E, 0x3D, 0xCD, 0x2A, 0xA3, 0x60,
224
        0xAE, 0x93, 0x8A, 0x48, 0x97, 0x51, 0x15, 0xF7,
225
        0x01, 0x0B, 0xB7, 0x36, 0xB1, 0x2E, 0x11, 0xFD,
226
        0x84, 0x2D, 0x3F, 0x13, 0x88, 0xB3, 0x34, 0x24,
227
        0x1B, 0xDE, 0xC5, 0x1D, 0x4D, 0x2B, 0x17, 0x31,
228
        0x74, 0xA9, 0xC6, 0x43, 0x6D, 0x39, 0x90, 0xBE,
229
        0xC3, 0xB0, 0x21, 0x6B, 0xF6, 0x0F, 0xD5, 0x99,
230
        0x0D, 0xAC, 0x1F, 0x5C, 0x9E, 0xF5, 0xF9, 0x4C,
231
        0xD6, 0xDF, 0x89, 0xE4, 0x8B, 0xFF, 0xC7, 0xAA,
232
        0xE7, 0xED, 0x46, 0x25, 0xB6, 0x06, 0x5E, 0x35,
233
        0xB5, 0xEC, 0xCE, 0xE8, 0x6C, 0x30, 0x55, 0x61,
234
        0x4A, 0xFE, 0xA0, 0x79, 0x03, 0xF0, 0x10, 0x72,
235
        0x7C, 0xCF, 0x52, 0xA6, 0xA7, 0xEE, 0x44, 0xD3,
236
        0x9A, 0x57, 0x92, 0xD0, 0x5A, 0x7A, 0x41, 0x7F,
237
        0x0E, 0x00, 0x63, 0xF2, 0x4F, 0x05, 0x83, 0xC9,
238
        0xA1, 0xD4, 0xDD, 0xC4, 0x56, 0xF4, 0xD2, 0x77,
239
        0x81, 0x09, 0x82, 0x33, 0x9F, 0x07, 0x86, 0x75,
240
        0x38, 0x4E, 0x69, 0xF1, 0xAD, 0x23, 0x73, 0x87,
241
        0x70, 0x02, 0xC2, 0x1E, 0xB8, 0x0A, 0xFC, 0xE6
242
    ];
243
 
244
    /**
245
     * Default Constructor.
246
     *
247
     * @param string $mode
248
     * @throws \InvalidArgumentException if an invalid / unsupported mode is provided
249
     */
250
    public function __construct($mode)
251
    {
252
        parent::__construct($mode);
253
 
254
        if ($this->mode == self::MODE_STREAM) {
255
            throw new BadModeException('Block ciphers cannot be ran in stream mode');
256
        }
257
    }
258
 
259
    /**
260
     * Test for engine validity
261
     *
262
     * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
263
     *
264
     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
265
     * @param int $engine
266
     * @return bool
267
     */
268
    protected function isValidEngineHelper($engine)
269
    {
270
        switch ($engine) {
271
            case self::ENGINE_OPENSSL:
272
                if ($this->current_key_length != 128 || strlen($this->orig_key) < 16) {
273
                    return false;
274
                }
275
                $this->cipher_name_openssl_ecb = 'rc2-ecb';
276
                $this->cipher_name_openssl = 'rc2-' . $this->openssl_translate_mode();
277
        }
278
 
279
        return parent::isValidEngineHelper($engine);
280
    }
281
 
282
    /**
283
     * Sets the key length.
284
     *
285
     * Valid key lengths are 8 to 1024.
286
     * Calling this function after setting the key has no effect until the next
287
     *  \phpseclib3\Crypt\RC2::setKey() call.
288
     *
289
     * @param int $length in bits
290
     * @throws \LengthException if the key length isn't supported
291
     */
292
    public function setKeyLength($length)
293
    {
294
        if ($length < 8 || $length > 1024) {
295
            throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 1024 bits, inclusive, are supported');
296
        }
297
 
298
        $this->default_key_length = $this->current_key_length = $length;
299
        $this->explicit_key_length = $length >> 3;
300
    }
301
 
302
    /**
303
     * Returns the current key length
304
     *
305
     * @return int
306
     */
307
    public function getKeyLength()
308
    {
309
        return $this->current_key_length;
310
    }
311
 
312
    /**
313
     * Sets the key.
314
     *
315
     * Keys can be of any length. RC2, itself, uses 8 to 1024 bit keys (eg.
316
     * strlen($key) <= 128), however, we only use the first 128 bytes if $key
317
     * has more then 128 bytes in it, and set $key to a single null byte if
318
     * it is empty.
319
     *
320
     * @see \phpseclib3\Crypt\Common\SymmetricKey::setKey()
321
     * @param string $key
322
     * @param int|boolean $t1 optional Effective key length in bits.
323
     * @throws \LengthException if the key length isn't supported
324
     */
325
    public function setKey($key, $t1 = false)
326
    {
327
        $this->orig_key = $key;
328
 
329
        if ($t1 === false) {
330
            $t1 = $this->default_key_length;
331
        }
332
 
333
        if ($t1 < 1 || $t1 > 1024) {
334
            throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 1024 bits, inclusive, are supported');
335
        }
336
 
337
        $this->current_key_length = $t1;
338
        if (strlen($key) < 1 || strlen($key) > 128) {
339
            throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes between 8 and 1024 bits, inclusive, are supported');
340
        }
341
 
342
        $t = strlen($key);
343
 
344
        // The mcrypt RC2 implementation only supports effective key length
345
        // of 1024 bits. It is however possible to handle effective key
346
        // lengths in range 1..1024 by expanding the key and applying
347
        // inverse pitable mapping to the first byte before submitting it
348
        // to mcrypt.
349
 
350
        // Key expansion.
351
        $l = array_values(unpack('C*', $key));
352
        $t8 = ($t1 + 7) >> 3;
353
        $tm = 0xFF >> (8 * $t8 - $t1);
354
 
355
        // Expand key.
356
        $pitable = self::$pitable;
357
        for ($i = $t; $i < 128; $i++) {
358
            $l[$i] = $pitable[$l[$i - 1] + $l[$i - $t]];
359
        }
360
        $i = 128 - $t8;
361
        $l[$i] = $pitable[$l[$i] & $tm];
362
        while ($i--) {
363
            $l[$i] = $pitable[$l[$i + 1] ^ $l[$i + $t8]];
364
        }
365
 
366
        // Prepare the key for mcrypt.
367
        $l[0] = self::$invpitable[$l[0]];
368
        array_unshift($l, 'C*');
369
 
370
        $this->key = pack(...$l);
371
        $this->key_length = strlen($this->key);
372
        $this->changed = $this->nonIVChanged = true;
373
        $this->setEngine();
374
    }
375
 
376
    /**
377
     * Encrypts a message.
378
     *
379
     * Mostly a wrapper for \phpseclib3\Crypt\Common\SymmetricKey::encrypt, with some additional OpenSSL handling code
380
     *
381
     * @see self::decrypt()
382
     * @param string $plaintext
383
     * @return string $ciphertext
384
     */
385
    public function encrypt($plaintext)
386
    {
387
        if ($this->engine == self::ENGINE_OPENSSL) {
388
            $temp = $this->key;
389
            $this->key = $this->orig_key;
390
            $result = parent::encrypt($plaintext);
391
            $this->key = $temp;
392
            return $result;
393
        }
394
 
395
        return parent::encrypt($plaintext);
396
    }
397
 
398
    /**
399
     * Decrypts a message.
400
     *
401
     * Mostly a wrapper for \phpseclib3\Crypt\Common\SymmetricKey::decrypt, with some additional OpenSSL handling code
402
     *
403
     * @see self::encrypt()
404
     * @param string $ciphertext
405
     * @return string $plaintext
406
     */
407
    public function decrypt($ciphertext)
408
    {
409
        if ($this->engine == self::ENGINE_OPENSSL) {
410
            $temp = $this->key;
411
            $this->key = $this->orig_key;
412
            $result = parent::decrypt($ciphertext);
413
            $this->key = $temp;
414
            return $result;
415
        }
416
 
417
        return parent::decrypt($ciphertext);
418
    }
419
 
420
    /**
421
     * Encrypts a block
422
     *
423
     * @see \phpseclib3\Crypt\Common\SymmetricKey::encryptBlock()
424
     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
425
     * @param string $in
426
     * @return string
427
     */
428
    protected function encryptBlock($in)
429
    {
430
        list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
431
        $keys = $this->keys;
432
        $limit = 20;
433
        $actions = [$limit => 44, 44 => 64];
434
        $j = 0;
435
 
436
        for (;;) {
437
            // Mixing round.
438
            $r0 = (($r0 + $keys[$j++] + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
439
            $r0 |= $r0 >> 16;
440
            $r1 = (($r1 + $keys[$j++] + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
441
            $r1 |= $r1 >> 16;
442
            $r2 = (($r2 + $keys[$j++] + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
443
            $r2 |= $r2 >> 16;
444
            $r3 = (($r3 + $keys[$j++] + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
445
            $r3 |= $r3 >> 16;
446
 
447
            if ($j === $limit) {
448
                if ($limit === 64) {
449
                    break;
450
                }
451
 
452
                // Mashing round.
453
                $r0 += $keys[$r3 & 0x3F];
454
                $r1 += $keys[$r0 & 0x3F];
455
                $r2 += $keys[$r1 & 0x3F];
456
                $r3 += $keys[$r2 & 0x3F];
457
                $limit = $actions[$limit];
458
            }
459
        }
460
 
461
        return pack('vvvv', $r0, $r1, $r2, $r3);
462
    }
463
 
464
    /**
465
     * Decrypts a block
466
     *
467
     * @see \phpseclib3\Crypt\Common\SymmetricKey::decryptBlock()
468
     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
469
     * @param string $in
470
     * @return string
471
     */
472
    protected function decryptBlock($in)
473
    {
474
        list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
475
        $keys = $this->keys;
476
        $limit = 44;
477
        $actions = [$limit => 20, 20 => 0];
478
        $j = 64;
479
 
480
        for (;;) {
481
            // R-mixing round.
482
            $r3 = ($r3 | ($r3 << 16)) >> 5;
483
            $r3 = ($r3 - $keys[--$j] - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
484
            $r2 = ($r2 | ($r2 << 16)) >> 3;
485
            $r2 = ($r2 - $keys[--$j] - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
486
            $r1 = ($r1 | ($r1 << 16)) >> 2;
487
            $r1 = ($r1 - $keys[--$j] - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
488
            $r0 = ($r0 | ($r0 << 16)) >> 1;
489
            $r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;
490
 
491
            if ($j === $limit) {
492
                if ($limit === 0) {
493
                    break;
494
                }
495
 
496
                // R-mashing round.
497
                $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
498
                $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
499
                $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
500
                $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;
501
                $limit = $actions[$limit];
502
            }
503
        }
504
 
505
        return pack('vvvv', $r0, $r1, $r2, $r3);
506
    }
507
 
508
    /**
509
     * Creates the key schedule
510
     *
511
     * @see \phpseclib3\Crypt\Common\SymmetricKey::setupKey()
512
     */
513
    protected function setupKey()
514
    {
515
        if (!isset($this->key)) {
516
            $this->setKey('');
517
        }
518
 
519
        // Key has already been expanded in \phpseclib3\Crypt\RC2::setKey():
520
        // Only the first value must be altered.
521
        $l = unpack('Ca/Cb/v*', $this->key);
522
        array_unshift($l, self::$pitable[$l['a']] | ($l['b'] << 8));
523
        unset($l['a']);
524
        unset($l['b']);
525
        $this->keys = $l;
526
    }
527
 
528
    /**
529
     * Setup the performance-optimized function for de/encrypt()
530
     *
531
     * @see \phpseclib3\Crypt\Common\SymmetricKey::setupInlineCrypt()
532
     */
533
    protected function setupInlineCrypt()
534
    {
535
        // Init code for both, encrypt and decrypt.
536
        $init_crypt = '$keys = $this->keys;';
537
 
538
        $keys = $this->keys;
539
 
540
        // $in is the current 8 bytes block which has to be en/decrypt
541
        $encrypt_block = $decrypt_block = '
542
            $in = unpack("v4", $in);
543
            $r0 = $in[1];
544
            $r1 = $in[2];
545
            $r2 = $in[3];
546
            $r3 = $in[4];
547
        ';
548
 
549
        // Create code for encryption.
550
        $limit = 20;
551
        $actions = [$limit => 44, 44 => 64];
552
        $j = 0;
553
 
554
        for (;;) {
555
            // Mixing round.
556
            $encrypt_block .= '
557
                $r0 = (($r0 + ' . $keys[$j++] . ' +
558
                       ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
559
                $r0 |= $r0 >> 16;
560
                $r1 = (($r1 + ' . $keys[$j++] . ' +
561
                       ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
562
                $r1 |= $r1 >> 16;
563
                $r2 = (($r2 + ' . $keys[$j++] . ' +
564
                       ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
565
                $r2 |= $r2 >> 16;
566
                $r3 = (($r3 + ' . $keys[$j++] . ' +
567
                       ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
568
                $r3 |= $r3 >> 16;';
569
 
570
            if ($j === $limit) {
571
                if ($limit === 64) {
572
                    break;
573
                }
574
 
575
                // Mashing round.
576
                $encrypt_block .= '
577
                    $r0 += $keys[$r3 & 0x3F];
578
                    $r1 += $keys[$r0 & 0x3F];
579
                    $r2 += $keys[$r1 & 0x3F];
580
                    $r3 += $keys[$r2 & 0x3F];';
581
                $limit = $actions[$limit];
582
            }
583
        }
584
 
585
        $encrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
586
 
587
        // Create code for decryption.
588
        $limit = 44;
589
        $actions = [$limit => 20, 20 => 0];
590
        $j = 64;
591
 
592
        for (;;) {
593
            // R-mixing round.
594
            $decrypt_block .= '
595
                $r3 = ($r3 | ($r3 << 16)) >> 5;
596
                $r3 = ($r3 - ' . $keys[--$j] . ' -
597
                       ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
598
                $r2 = ($r2 | ($r2 << 16)) >> 3;
599
                $r2 = ($r2 - ' . $keys[--$j] . ' -
600
                       ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
601
                $r1 = ($r1 | ($r1 << 16)) >> 2;
602
                $r1 = ($r1 - ' . $keys[--$j] . ' -
603
                       ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
604
                $r0 = ($r0 | ($r0 << 16)) >> 1;
605
                $r0 = ($r0 - ' . $keys[--$j] . ' -
606
                       ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;';
607
 
608
            if ($j === $limit) {
609
                if ($limit === 0) {
610
                    break;
611
                }
612
 
613
                // R-mashing round.
614
                $decrypt_block .= '
615
                    $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
616
                    $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
617
                    $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
618
                    $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;';
619
                $limit = $actions[$limit];
620
            }
621
        }
622
 
623
        $decrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
624
 
625
        // Creates the inline-crypt function
626
        $this->inline_crypt = $this->createInlineCryptFunction(
627
            [
628
               'init_crypt'    => $init_crypt,
629
               'encrypt_block' => $encrypt_block,
630
               'decrypt_block' => $decrypt_block
631
            ]
632
        );
633
    }
634
}