]> git.mxchange.org Git - friendica-addons.git/blob - securemail/vendor/phpseclib/phpseclib/phpseclib/Crypt/RC2.php
securemail: update pgp library
[friendica-addons.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 versions 4 and 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 'Crypt/RC2.php';
18  *
19  *    $rc2 = new 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  * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
30  * of this software and associated documentation files (the "Software"), to deal
31  * in the Software without restriction, including without limitation the rights
32  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33  * copies of the Software, and to permit persons to whom the Software is
34  * furnished to do so, subject to the following conditions:
35  *
36  * The above copyright notice and this permission notice shall be included in
37  * all copies or substantial portions of the Software.
38  *
39  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45  * THE SOFTWARE.
46  *
47  * @category Crypt
48  * @package  Crypt_RC2
49  * @author   Patrick Monnerat <pm@datasphere.ch>
50  * @license  http://www.opensource.org/licenses/mit-license.html  MIT License
51  * @link     http://phpseclib.sourceforge.net
52  */
53
54 /**
55  * Include Crypt_Base
56  *
57  * Base cipher class
58  */
59 if (!class_exists('Crypt_Base')) {
60     include_once 'Base.php';
61 }
62
63 /**#@+
64  * @access public
65  * @see Crypt_RC2::encrypt()
66  * @see Crypt_RC2::decrypt()
67  */
68 /**
69  * Encrypt / decrypt using the Counter mode.
70  *
71  * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
72  *
73  * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
74  */
75 define('CRYPT_RC2_MODE_CTR', CRYPT_MODE_CTR);
76 /**
77  * Encrypt / decrypt using the Electronic Code Book mode.
78  *
79  * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
80  */
81 define('CRYPT_RC2_MODE_ECB', CRYPT_MODE_ECB);
82 /**
83  * Encrypt / decrypt using the Code Book Chaining mode.
84  *
85  * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
86  */
87 define('CRYPT_RC2_MODE_CBC', CRYPT_MODE_CBC);
88 /**
89  * Encrypt / decrypt using the Cipher Feedback mode.
90  *
91  * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
92  */
93 define('CRYPT_RC2_MODE_CFB', CRYPT_MODE_CFB);
94 /**
95  * Encrypt / decrypt using the Cipher Feedback mode.
96  *
97  * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
98  */
99 define('CRYPT_RC2_MODE_OFB', CRYPT_MODE_OFB);
100 /**#@-*/
101
102 /**#@+
103  * @access private
104  * @see Crypt_RC2::Crypt_RC2()
105  */
106 /**
107  * Toggles the internal implementation
108  */
109 define('CRYPT_RC2_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
110 /**
111  * Toggles the mcrypt implementation
112  */
113 define('CRYPT_RC2_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
114 /**#@-*/
115
116 /**
117  * Pure-PHP implementation of RC2.
118  *
119  * @package Crypt_RC2
120  * @access  public
121  */
122 class Crypt_RC2 extends Crypt_Base
123 {
124     /**
125      * Block Length of the cipher
126      *
127      * @see Crypt_Base::block_size
128      * @var Integer
129      * @access private
130      */
131     var $block_size = 8;
132
133     /**
134      * The Key
135      *
136      * @see Crypt_Base::key
137      * @see setKey()
138      * @var String
139      * @access private
140      */
141     var $key = "\0";
142
143     /**
144      * The default password key_size used by setPassword()
145      *
146      * @see Crypt_Base::password_key_size
147      * @see Crypt_Base::setPassword()
148      * @var Integer
149      * @access private
150      */
151     var $password_key_size = 16; // = 128 bits
152
153     /**
154      * The namespace used by the cipher for its constants.
155      *
156      * @see Crypt_Base::const_namespace
157      * @var String
158      * @access private
159      */
160     var $const_namespace = 'RC2';
161
162     /**
163      * The mcrypt specific name of the cipher
164      *
165      * @see Crypt_Base::cipher_name_mcrypt
166      * @var String
167      * @access private
168      */
169     var $cipher_name_mcrypt = 'rc2';
170
171     /**
172      * Optimizing value while CFB-encrypting
173      *
174      * @see Crypt_Base::cfb_init_len
175      * @var Integer
176      * @access private
177      */
178     var $cfb_init_len = 500;
179
180     /**
181      * The key length in bits.
182      *
183      * @see Crypt_RC2::setKeyLength()
184      * @see Crypt_RC2::setKey()
185      * @var Integer
186      * @access private
187      * @internal Should be in range [1..1024].
188      * @internal Changing this value after setting the key has no effect.
189      */
190     var $default_key_length = 1024;
191
192     /**
193      * The Key Schedule
194      *
195      * @see Crypt_RC2::_setupKey()
196      * @var Array
197      * @access private
198      */
199     var $keys;
200
201     /**
202      * Key expansion randomization table.
203      * Twice the same 256-value sequence to save a modulus in key expansion.
204      *
205      * @see Crypt_RC2::setKey()
206      * @var Array
207      * @access private
208      */
209     var $pitable = array(
210         0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
211         0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
212         0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
213         0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
214         0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
215         0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
216         0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
217         0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
218         0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
219         0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
220         0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
221         0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
222         0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
223         0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
224         0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
225         0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
226         0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
227         0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
228         0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
229         0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
230         0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
231         0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
232         0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
233         0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
234         0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
235         0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
236         0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
237         0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
238         0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
239         0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
240         0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
241         0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD,
242         0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
243         0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
244         0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
245         0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
246         0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
247         0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
248         0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
249         0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
250         0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
251         0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
252         0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
253         0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
254         0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
255         0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
256         0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
257         0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
258         0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
259         0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
260         0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
261         0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
262         0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
263         0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
264         0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
265         0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
266         0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
267         0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
268         0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
269         0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
270         0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
271         0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
272         0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
273         0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD
274     );
275
276     /**
277      * Inverse key expansion randomization table.
278      *
279      * @see Crypt_RC2::setKey()
280      * @var Array
281      * @access private
282      */
283     var $invpitable = array(
284         0xD1, 0xDA, 0xB9, 0x6F, 0x9C, 0xC8, 0x78, 0x66,
285         0x80, 0x2C, 0xF8, 0x37, 0xEA, 0xE0, 0x62, 0xA4,
286         0xCB, 0x71, 0x50, 0x27, 0x4B, 0x95, 0xD9, 0x20,
287         0x9D, 0x04, 0x91, 0xE3, 0x47, 0x6A, 0x7E, 0x53,
288         0xFA, 0x3A, 0x3B, 0xB4, 0xA8, 0xBC, 0x5F, 0x68,
289         0x08, 0xCA, 0x8F, 0x14, 0xD7, 0xC0, 0xEF, 0x7B,
290         0x5B, 0xBF, 0x2F, 0xE5, 0xE2, 0x8C, 0xBA, 0x12,
291         0xE1, 0xAF, 0xB2, 0x54, 0x5D, 0x59, 0x76, 0xDB,
292         0x32, 0xA2, 0x58, 0x6E, 0x1C, 0x29, 0x64, 0xF3,
293         0xE9, 0x96, 0x0C, 0x98, 0x19, 0x8D, 0x3E, 0x26,
294         0xAB, 0xA5, 0x85, 0x16, 0x40, 0xBD, 0x49, 0x67,
295         0xDC, 0x22, 0x94, 0xBB, 0x3C, 0xC1, 0x9B, 0xEB,
296         0x45, 0x28, 0x18, 0xD8, 0x1A, 0x42, 0x7D, 0xCC,
297         0xFB, 0x65, 0x8E, 0x3D, 0xCD, 0x2A, 0xA3, 0x60,
298         0xAE, 0x93, 0x8A, 0x48, 0x97, 0x51, 0x15, 0xF7,
299         0x01, 0x0B, 0xB7, 0x36, 0xB1, 0x2E, 0x11, 0xFD,
300         0x84, 0x2D, 0x3F, 0x13, 0x88, 0xB3, 0x34, 0x24,
301         0x1B, 0xDE, 0xC5, 0x1D, 0x4D, 0x2B, 0x17, 0x31,
302         0x74, 0xA9, 0xC6, 0x43, 0x6D, 0x39, 0x90, 0xBE,
303         0xC3, 0xB0, 0x21, 0x6B, 0xF6, 0x0F, 0xD5, 0x99,
304         0x0D, 0xAC, 0x1F, 0x5C, 0x9E, 0xF5, 0xF9, 0x4C,
305         0xD6, 0xDF, 0x89, 0xE4, 0x8B, 0xFF, 0xC7, 0xAA,
306         0xE7, 0xED, 0x46, 0x25, 0xB6, 0x06, 0x5E, 0x35,
307         0xB5, 0xEC, 0xCE, 0xE8, 0x6C, 0x30, 0x55, 0x61,
308         0x4A, 0xFE, 0xA0, 0x79, 0x03, 0xF0, 0x10, 0x72,
309         0x7C, 0xCF, 0x52, 0xA6, 0xA7, 0xEE, 0x44, 0xD3,
310         0x9A, 0x57, 0x92, 0xD0, 0x5A, 0x7A, 0x41, 0x7F,
311         0x0E, 0x00, 0x63, 0xF2, 0x4F, 0x05, 0x83, 0xC9,
312         0xA1, 0xD4, 0xDD, 0xC4, 0x56, 0xF4, 0xD2, 0x77,
313         0x81, 0x09, 0x82, 0x33, 0x9F, 0x07, 0x86, 0x75,
314         0x38, 0x4E, 0x69, 0xF1, 0xAD, 0x23, 0x73, 0x87,
315         0x70, 0x02, 0xC2, 0x1E, 0xB8, 0x0A, 0xFC, 0xE6
316     );
317
318     /**
319      * Default Constructor.
320      *
321      * Determines whether or not the mcrypt extension should be used.
322      *
323      * $mode could be:
324      *
325      * - CRYPT_RC2_MODE_ECB
326      *
327      * - CRYPT_RC2_MODE_CBC
328      *
329      * - CRYPT_RC2_MODE_CTR
330      *
331      * - CRYPT_RC2_MODE_CFB
332      *
333      * - CRYPT_RC2_MODE_OFB
334      *
335      * If not explicitly set, CRYPT_RC2_MODE_CBC will be used.
336      *
337      * @see Crypt_Base::Crypt_Base()
338      * @param optional Integer $mode
339      * @access public
340      */
341     function Crypt_RC2($mode = CRYPT_RC2_MODE_CBC)
342     {
343         parent::Crypt_Base($mode);
344         $this->setKey('');
345     }
346
347     /**
348      * Sets the key length
349      *
350      * Valid key lengths are 1 to 1024.
351      * Calling this function after setting the key has no effect until the next
352      *  Crypt_RC2::setKey() call.
353      *
354      * @access public
355      * @param Integer $length in bits
356      */
357     function setKeyLength($length)
358     {
359         if ($length >= 1 && $length <= 1024) {
360             $this->default_key_length = $length;
361         }
362     }
363
364     /**
365      * Sets the key.
366      *
367      * Keys can be of any length. RC2, itself, uses 1 to 1024 bit keys (eg.
368      * strlen($key) <= 128), however, we only use the first 128 bytes if $key
369      * has more then 128 bytes in it, and set $key to a single null byte if
370      * it is empty.
371      *
372      * If the key is not explicitly set, it'll be assumed to be a single
373      * null byte.
374      *
375      * @see Crypt_Base::setKey()
376      * @access public
377      * @param String $key
378      * @param Integer $t1 optional          Effective key length in bits.
379      */
380     function setKey($key, $t1 = 0)
381     {
382         if ($t1 <= 0) {
383             $t1 = $this->default_key_length;
384         } else if ($t1 > 1024) {
385             $t1 = 1024;
386         }
387         // Key byte count should be 1..128.
388         $key = strlen($key) ? substr($key, 0, 128) : "\x00";
389         $t = strlen($key);
390
391         // The mcrypt RC2 implementation only supports effective key length
392         // of 1024 bits. It is however possible to handle effective key
393         // lengths in range 1..1024 by expanding the key and applying
394         // inverse pitable mapping to the first byte before submitting it
395         // to mcrypt.
396
397         // Key expansion.
398         $l = array_values(unpack('C*', $key));
399         $t8 = ($t1 + 7) >> 3;
400         $tm = 0xFF >> (8 * $t8 - $t1);
401
402         // Expand key.
403         $pitable = $this->pitable;
404         for ($i = $t; $i < 128; $i++) {
405             $l[$i] = $pitable[$l[$i - 1] + $l[$i - $t]];
406         }
407         $i = 128 - $t8;
408         $l[$i] = $pitable[$l[$i] & $tm];
409         while ($i--) {
410             $l[$i] = $pitable[$l[$i + 1] ^ $l[$i + $t8]];
411         }
412
413         // Prepare the key for mcrypt.
414         $l[0] = $this->invpitable[$l[0]];
415         array_unshift($l, 'C*');
416         parent::setKey(call_user_func_array('pack', $l));
417     }
418
419     /**
420      * Encrypts a block
421      *
422      * @see Crypt_Base::_encryptBlock()
423      * @see Crypt_Base::encrypt()
424      * @access private
425      * @param String $in
426      * @return String
427      */
428     function _encryptBlock($in)
429     {
430         list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
431         $keys = $this->keys;
432         $limit = 20;
433         $actions = array($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 Crypt_Base::_decryptBlock()
468      * @see Crypt_Base::decrypt()
469      * @access private
470      * @param String $in
471      * @return String
472      */
473     function _decryptBlock($in)
474     {
475         list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
476         $keys = $this->keys;
477         $limit = 44;
478         $actions = array($limit => 20, 20 => 0);
479         $j = 64;
480
481         for (;;) {
482             // R-mixing round.
483             $r3 = ($r3 | ($r3 << 16)) >> 5;
484             $r3 = ($r3 - $keys[--$j] - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
485             $r2 = ($r2 | ($r2 << 16)) >> 3;
486             $r2 = ($r2 - $keys[--$j] - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
487             $r1 = ($r1 | ($r1 << 16)) >> 2;
488             $r1 = ($r1 - $keys[--$j] - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
489             $r0 = ($r0 | ($r0 << 16)) >> 1;
490             $r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;
491
492             if ($j === $limit) {
493                 if ($limit === 0) {
494                     break;
495                 }
496
497                 // R-mashing round.
498                 $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
499                 $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
500                 $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
501                 $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;
502                 $limit = $actions[$limit];
503             }
504         }
505
506         return pack('vvvv', $r0, $r1, $r2, $r3);
507     }
508
509     /**
510      * Creates the key schedule
511      *
512      * @see Crypt_Base::_setupKey()
513      * @access private
514      */
515     function _setupKey()
516     {
517         // Key has already been expanded in Crypt_RC2::setKey():
518         // Only the first value must be altered.
519         $l = unpack('Ca/Cb/v*', $this->key);
520         array_unshift($l, $this->pitable[$l['a']] | ($l['b'] << 8));
521         unset($l['a']);
522         unset($l['b']);
523         $this->keys = $l;
524     }
525
526     /**
527      * Setup the performance-optimized function for de/encrypt()
528      *
529      * @see Crypt_Base::_setupInlineCrypt()
530      * @access private
531      */
532     function _setupInlineCrypt()
533     {
534         $lambda_functions = &Crypt_RC2::_getLambdaFunctions();
535
536         // The first 10 generated $lambda_functions will use the $keys hardcoded as integers
537         // for the mixing rounds, for better inline crypt performance [~20% faster].
538         // But for memory reason we have to limit those ultra-optimized $lambda_functions to an amount of 10.
539         $keys = $this->keys;
540         if (count($lambda_functions) >= 10) {
541             foreach ($this->keys as $k => $v) {
542                 $keys[$k] = '$keys[' . $k . ']';
543             }
544         }
545
546         $code_hash = md5(str_pad("Crypt_RC2, {$this->mode}, ", 32, "\0") . implode(',', $keys));
547
548         // Is there a re-usable $lambda_functions in there?
549         // If not, we have to create it.
550         if (!isset($lambda_functions[$code_hash])) {
551             // Init code for both, encrypt and decrypt.
552             $init_crypt = '$keys = $self->keys;';
553
554             // $in is the current 8 bytes block which has to be en/decrypt
555             $encrypt_block = $decrypt_block = '
556                 $in = unpack("v4", $in);
557                 $r0 = $in[1];
558                 $r1 = $in[2];
559                 $r2 = $in[3];
560                 $r3 = $in[4];
561             ';
562
563             // Create code for encryption.
564             $limit = 20;
565             $actions = array($limit => 44, 44 => 64);
566             $j = 0;
567
568             for (;;) {
569                 // Mixing round.
570                 $encrypt_block .= '
571                     $r0 = (($r0 + ' . $keys[$j++] . ' +
572                            ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
573                     $r0 |= $r0 >> 16;
574                     $r1 = (($r1 + ' . $keys[$j++] . ' +
575                            ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
576                     $r1 |= $r1 >> 16;
577                     $r2 = (($r2 + ' . $keys[$j++] . ' +
578                            ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
579                     $r2 |= $r2 >> 16;
580                     $r3 = (($r3 + ' . $keys[$j++] . ' +
581                            ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
582                     $r3 |= $r3 >> 16;';
583
584                 if ($j === $limit) {
585                     if ($limit === 64) {
586                         break;
587                     }
588
589                     // Mashing round.
590                     $encrypt_block .= '
591                         $r0 += $keys[$r3 & 0x3F];
592                         $r1 += $keys[$r0 & 0x3F];
593                         $r2 += $keys[$r1 & 0x3F];
594                         $r3 += $keys[$r2 & 0x3F];';
595                     $limit = $actions[$limit];
596                 }
597             }
598
599             $encrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
600
601             // Create code for decryption.
602             $limit = 44;
603             $actions = array($limit => 20, 20 => 0);
604             $j = 64;
605
606             for (;;) {
607                 // R-mixing round.
608                 $decrypt_block .= '
609                     $r3 = ($r3 | ($r3 << 16)) >> 5;
610                     $r3 = ($r3 - ' . $keys[--$j] . ' -
611                            ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
612                     $r2 = ($r2 | ($r2 << 16)) >> 3;
613                     $r2 = ($r2 - ' . $keys[--$j] . ' -
614                            ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
615                     $r1 = ($r1 | ($r1 << 16)) >> 2;
616                     $r1 = ($r1 - ' . $keys[--$j] . ' -
617                            ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
618                     $r0 = ($r0 | ($r0 << 16)) >> 1;
619                     $r0 = ($r0 - ' . $keys[--$j] . ' -
620                            ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;';
621
622                 if ($j === $limit) {
623                     if ($limit === 0) {
624                         break;
625                     }
626
627                     // R-mashing round.
628                     $decrypt_block .= '
629                         $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
630                         $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
631                         $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
632                         $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;';
633                     $limit = $actions[$limit];
634                 }
635             }
636
637             $decrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
638
639             // Creates the inline-crypt function
640             $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
641                 array(
642                    'init_crypt'    => $init_crypt,
643                    'encrypt_block' => $encrypt_block,
644                    'decrypt_block' => $decrypt_block
645                 )
646             );
647         }
648
649         // Set the inline-crypt function as callback in: $this->inline_crypt
650         $this->inline_crypt = $lambda_functions[$code_hash];
651     }
652 }