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