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