Subversion Repositories cheapmusic

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
103 - 1
<?php
2
 
3
/**
4
 * Pure-PHP implementation of RC4.
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://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm}
13
 *  - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
14
 *
15
 * RC4 is also known as ARCFOUR or ARC4.  The reason is elaborated upon at Wikipedia.  This class is named RC4 and not
16
 * ARCFOUR or ARC4 because RC4 is how it is referred to in the SSH1 specification.
17
 *
18
 * Here's a short example of how to use this library:
19
 * <code>
20
 * <?php
21
 *    include 'vendor/autoload.php';
22
 *
23
 *    $rc4 = new \phpseclib\Crypt\RC4();
24
 *
25
 *    $rc4->setKey('abcdefgh');
26
 *
27
 *    $size = 10 * 1024;
28
 *    $plaintext = '';
29
 *    for ($i = 0; $i < $size; $i++) {
30
 *        $plaintext.= 'a';
31
 *    }
32
 *
33
 *    echo $rc4->decrypt($rc4->encrypt($plaintext));
34
 * ?>
35
 * </code>
36
 *
37
 * @category  Crypt
38
 * @package   RC4
39
 * @author    Jim Wigginton <terrafrost@php.net>
40
 * @copyright 2007 Jim Wigginton
41
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
42
 * @link      http://phpseclib.sourceforge.net
43
 */
44
 
45
namespace phpseclib\Crypt;
46
 
47
/**
48
 * Pure-PHP implementation of RC4.
49
 *
50
 * @package RC4
51
 * @author  Jim Wigginton <terrafrost@php.net>
52
 * @access  public
53
 */
54
class RC4 extends Base
55
{
56
    /**#@+
57
     * @access private
58
     * @see \phpseclib\Crypt\RC4::_crypt()
59
    */
60
    const ENCRYPT = 0;
61
    const DECRYPT = 1;
62
    /**#@-*/
63
 
64
    /**
65
     * Block Length of the cipher
66
     *
67
     * RC4 is a stream cipher
68
     * so we the block_size to 0
69
     *
70
     * @see \phpseclib\Crypt\Base::block_size
71
     * @var int
72
     * @access private
73
     */
74
    var $block_size = 0;
75
 
76
    /**
77
     * Key Length (in bytes)
78
     *
79
     * @see \phpseclib\Crypt\RC4::setKeyLength()
80
     * @var int
81
     * @access private
82
     */
83
    var $key_length = 128; // = 1024 bits
84
 
85
    /**
86
     * The mcrypt specific name of the cipher
87
     *
88
     * @see \phpseclib\Crypt\Base::cipher_name_mcrypt
89
     * @var string
90
     * @access private
91
     */
92
    var $cipher_name_mcrypt = 'arcfour';
93
 
94
    /**
95
     * Holds whether performance-optimized $inline_crypt() can/should be used.
96
     *
97
     * @see \phpseclib\Crypt\Base::inline_crypt
98
     * @var mixed
99
     * @access private
100
     */
101
    var $use_inline_crypt = false; // currently not available
102
 
103
    /**
104
     * The Key
105
     *
106
     * @see self::setKey()
107
     * @var string
108
     * @access private
109
     */
110
    var $key = "\0";
111
 
112
    /**
113
     * The Key Stream for decryption and encryption
114
     *
115
     * @see self::setKey()
116
     * @var array
117
     * @access private
118
     */
119
    var $stream;
120
 
121
    /**
122
     * Default Constructor.
123
     *
124
     * Determines whether or not the mcrypt extension should be used.
125
     *
126
     * @see \phpseclib\Crypt\Base::__construct()
127
     * @return \phpseclib\Crypt\RC4
128
     * @access public
129
     */
130
    function __construct()
131
    {
132
        parent::__construct(Base::MODE_STREAM);
133
    }
134
 
135
    /**
136
     * Test for engine validity
137
     *
138
     * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Base::isValidEngine()
139
     *
140
     * @see \phpseclib\Crypt\Base::__construct()
141
     * @param int $engine
142
     * @access public
143
     * @return bool
144
     */
145
    function isValidEngine($engine)
146
    {
147
        switch ($engine) {
148
            case Base::ENGINE_OPENSSL:
149
                switch (strlen($this->key)) {
150
                    case 5:
151
                        $this->cipher_name_openssl = 'rc4-40';
152
                        break;
153
                    case 8:
154
                        $this->cipher_name_openssl = 'rc4-64';
155
                        break;
156
                    case 16:
157
                        $this->cipher_name_openssl = 'rc4';
158
                        break;
159
                    default:
160
                        return false;
161
                }
162
        }
163
 
164
        return parent::isValidEngine($engine);
165
    }
166
 
167
    /**
168
     * Dummy function.
169
     *
170
     * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
171
     * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
172
     * calling setKey().
173
     *
174
     * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way.  Since, in that protocol,
175
     * the IV's are relatively easy to predict, an attack described by
176
     * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
177
     * can be used to quickly guess at the rest of the key.  The following links elaborate:
178
     *
179
     * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
180
     * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
181
     *
182
     * @param string $iv
183
     * @see self::setKey()
184
     * @access public
185
     */
186
    function setIV($iv)
187
    {
188
    }
189
 
190
    /**
191
     * Sets the key length
192
     *
193
     * Keys can be between 1 and 256 bytes long.
194
     *
195
     * @access public
196
     * @param int $length
197
     */
198
    function setKeyLength($length)
199
    {
200
        if ($length < 8) {
201
            $this->key_length = 1;
202
        } elseif ($length > 2048) {
203
            $this->key_length = 256;
204
        } else {
205
            $this->key_length = $length >> 3;
206
        }
207
 
208
        parent::setKeyLength($length);
209
    }
210
 
211
    /**
212
     * Encrypts a message.
213
     *
214
     * @see \phpseclib\Crypt\Base::decrypt()
215
     * @see self::_crypt()
216
     * @access public
217
     * @param string $plaintext
218
     * @return string $ciphertext
219
     */
220
    function encrypt($plaintext)
221
    {
222
        if ($this->engine != Base::ENGINE_INTERNAL) {
223
            return parent::encrypt($plaintext);
224
        }
225
        return $this->_crypt($plaintext, self::ENCRYPT);
226
    }
227
 
228
    /**
229
     * Decrypts a message.
230
     *
231
     * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
232
     * At least if the continuous buffer is disabled.
233
     *
234
     * @see \phpseclib\Crypt\Base::encrypt()
235
     * @see self::_crypt()
236
     * @access public
237
     * @param string $ciphertext
238
     * @return string $plaintext
239
     */
240
    function decrypt($ciphertext)
241
    {
242
        if ($this->engine != Base::ENGINE_INTERNAL) {
243
            return parent::decrypt($ciphertext);
244
        }
245
        return $this->_crypt($ciphertext, self::DECRYPT);
246
    }
247
 
248
    /**
249
     * Encrypts a block
250
     *
251
     * @access private
252
     * @param string $in
253
     */
254
    function _encryptBlock($in)
255
    {
256
        // RC4 does not utilize this method
257
    }
258
 
259
    /**
260
     * Decrypts a block
261
     *
262
     * @access private
263
     * @param string $in
264
     */
265
    function _decryptBlock($in)
266
    {
267
        // RC4 does not utilize this method
268
    }
269
 
270
    /**
271
     * Setup the key (expansion)
272
     *
273
     * @see \phpseclib\Crypt\Base::_setupKey()
274
     * @access private
275
     */
276
    function _setupKey()
277
    {
278
        $key = $this->key;
279
        $keyLength = strlen($key);
280
        $keyStream = range(0, 255);
281
        $j = 0;
282
        for ($i = 0; $i < 256; $i++) {
283
            $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
284
            $temp = $keyStream[$i];
285
            $keyStream[$i] = $keyStream[$j];
286
            $keyStream[$j] = $temp;
287
        }
288
 
289
        $this->stream = array();
290
        $this->stream[self::DECRYPT] = $this->stream[self::ENCRYPT] = array(
291
            0, // index $i
292
            0, // index $j
293
            $keyStream
294
        );
295
    }
296
 
297
    /**
298
     * Encrypts or decrypts a message.
299
     *
300
     * @see self::encrypt()
301
     * @see self::decrypt()
302
     * @access private
303
     * @param string $text
304
     * @param int $mode
305
     * @return string $text
306
     */
307
    function _crypt($text, $mode)
308
    {
309
        if ($this->changed) {
310
            $this->_setup();
311
            $this->changed = false;
312
        }
313
 
314
        $stream = &$this->stream[$mode];
315
        if ($this->continuousBuffer) {
316
            $i = &$stream[0];
317
            $j = &$stream[1];
318
            $keyStream = &$stream[2];
319
        } else {
320
            $i = $stream[0];
321
            $j = $stream[1];
322
            $keyStream = $stream[2];
323
        }
324
 
325
        $len = strlen($text);
326
        for ($k = 0; $k < $len; ++$k) {
327
            $i = ($i + 1) & 255;
328
            $ksi = $keyStream[$i];
329
            $j = ($j + $ksi) & 255;
330
            $ksj = $keyStream[$j];
331
 
332
            $keyStream[$i] = $ksj;
333
            $keyStream[$j] = $ksi;
334
            $text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
335
        }
336
 
337
        return $text;
338
    }
339
}