Subversion Repositories oidplus

Rev

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