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