PHPSECLIB 0.3.1 added to the project to support SFTP transfers of lab orders and...
[openemr.git] / library / phpseclib / Crypt / RC4.php
blob94cb691734a4f313daa088203ba25034706d29f3
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4 /**
5 * Pure-PHP implementation of RC4.
7 * Uses mcrypt, if available, and an internal implementation, otherwise.
9 * PHP versions 4 and 5
11 * Useful resources are as follows:
13 * - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm}
14 * - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
16 * RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not
17 * ARCFOUR or ARC4 because RC4 is how it is refered to in the SSH1 specification.
19 * Here's a short example of how to use this library:
20 * <code>
21 * <?php
22 * include('Crypt/RC4.php');
24 * $rc4 = new Crypt_RC4();
26 * $rc4->setKey('abcdefgh');
28 * $size = 10 * 1024;
29 * $plaintext = '';
30 * for ($i = 0; $i < $size; $i++) {
31 * $plaintext.= 'a';
32 * }
34 * echo $rc4->decrypt($rc4->encrypt($plaintext));
35 * ?>
36 * </code>
38 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
39 * of this software and associated documentation files (the "Software"), to deal
40 * in the Software without restriction, including without limitation the rights
41 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
42 * copies of the Software, and to permit persons to whom the Software is
43 * furnished to do so, subject to the following conditions:
45 * The above copyright notice and this permission notice shall be included in
46 * all copies or substantial portions of the Software.
48 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
51 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
52 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
53 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
54 * THE SOFTWARE.
56 * @category Crypt
57 * @package Crypt_RC4
58 * @author Jim Wigginton <terrafrost@php.net>
59 * @copyright MMVII Jim Wigginton
60 * @license http://www.opensource.org/licenses/mit-license.html MIT License
61 * @version $Id: RC4.php,v 1.8 2009/06/09 04:00:38 terrafrost Exp $
62 * @link http://phpseclib.sourceforge.net
65 /**#@+
66 * @access private
67 * @see Crypt_RC4::Crypt_RC4()
69 /**
70 * Toggles the internal implementation
72 define('CRYPT_RC4_MODE_INTERNAL', 1);
73 /**
74 * Toggles the mcrypt implementation
76 define('CRYPT_RC4_MODE_MCRYPT', 2);
77 /**#@-*/
79 /**#@+
80 * @access private
81 * @see Crypt_RC4::_crypt()
83 define('CRYPT_RC4_ENCRYPT', 0);
84 define('CRYPT_RC4_DECRYPT', 1);
85 /**#@-*/
87 /**
88 * Pure-PHP implementation of RC4.
90 * @author Jim Wigginton <terrafrost@php.net>
91 * @version 0.1.0
92 * @access public
93 * @package Crypt_RC4
95 class Crypt_RC4 {
96 /**
97 * The Key
99 * @see Crypt_RC4::setKey()
100 * @var String
101 * @access private
103 var $key = "\0";
106 * The Key Stream for encryption
108 * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
110 * @see Crypt_RC4::setKey()
111 * @var Array
112 * @access private
114 var $encryptStream = false;
117 * The Key Stream for decryption
119 * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
121 * @see Crypt_RC4::setKey()
122 * @var Array
123 * @access private
125 var $decryptStream = false;
128 * The $i and $j indexes for encryption
130 * @see Crypt_RC4::_crypt()
131 * @var Integer
132 * @access private
134 var $encryptIndex = 0;
137 * The $i and $j indexes for decryption
139 * @see Crypt_RC4::_crypt()
140 * @var Integer
141 * @access private
143 var $decryptIndex = 0;
146 * The Encryption Algorithm
148 * Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR.
150 * @see Crypt_RC4::Crypt_RC4()
151 * @var Integer
152 * @access private
154 var $mode;
157 * Continuous Buffer status
159 * @see Crypt_RC4::enableContinuousBuffer()
160 * @var Boolean
161 * @access private
163 var $continuousBuffer = false;
166 * Default Constructor.
168 * Determines whether or not the mcrypt extension should be used.
170 * @param optional Integer $mode
171 * @return Crypt_RC4
172 * @access public
174 function Crypt_RC4()
176 if ( !defined('CRYPT_RC4_MODE') ) {
177 switch (true) {
178 case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')) && in_array('arcfour', mcrypt_list_algorithms()):
179 define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT);
180 break;
181 default:
182 define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL);
186 switch ( CRYPT_RC4_MODE ) {
187 case CRYPT_RC4_MODE_MCRYPT:
188 switch (true) {
189 case defined('MCRYPT_ARCFOUR'):
190 $this->mode = MCRYPT_ARCFOUR;
191 break;
192 case defined('MCRYPT_RC4');
193 $this->mode = MCRYPT_RC4;
199 * Sets the key.
201 * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will
202 * be used. If no key is explicitly set, it'll be assumed to be a single null byte.
204 * @access public
205 * @param String $key
207 function setKey($key)
209 $this->key = $key;
211 if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
212 return;
215 $keyLength = strlen($key);
216 $keyStream = array();
217 for ($i = 0; $i < 256; $i++) {
218 $keyStream[$i] = $i;
220 $j = 0;
221 for ($i = 0; $i < 256; $i++) {
222 $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
223 $temp = $keyStream[$i];
224 $keyStream[$i] = $keyStream[$j];
225 $keyStream[$j] = $temp;
228 $this->encryptIndex = $this->decryptIndex = array(0, 0);
229 $this->encryptStream = $this->decryptStream = $keyStream;
233 * Sets the password.
235 * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
236 * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
237 * $hash, $salt, $count, $dkLen
239 * @param String $password
240 * @param optional String $method
241 * @access public
243 function setPassword($password, $method = 'pbkdf2')
245 $key = '';
247 switch ($method) {
248 default: // 'pbkdf2'
249 list(, , $hash, $salt, $count) = func_get_args();
250 if (!isset($hash)) {
251 $hash = 'sha1';
253 // WPA and WPA use the SSID as the salt
254 if (!isset($salt)) {
255 $salt = 'phpseclib/salt';
257 // RFC2898#section-4.2 uses 1,000 iterations by default
258 // WPA and WPA2 use 4,096.
259 if (!isset($count)) {
260 $count = 1000;
262 if (!isset($dkLen)) {
263 $dkLen = 128;
266 if (!class_exists('Crypt_Hash')) {
267 require_once('Crypt/Hash.php');
270 $i = 1;
271 while (strlen($key) < $dkLen) {
272 //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
273 $hmac = new Crypt_Hash();
274 $hmac->setHash($hash);
275 $hmac->setKey($password);
276 $f = $u = $hmac->hash($salt . pack('N', $i++));
277 for ($j = 2; $j <= $count; $j++) {
278 $u = $hmac->hash($u);
279 $f^= $u;
281 $key.= $f;
285 $this->setKey(substr($key, 0, $dkLen));
289 * Dummy function.
291 * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
292 * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
293 * calling setKey().
295 * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
296 * the IV's are relatively easy to predict, an attack described by
297 * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
298 * can be used to quickly guess at the rest of the key. The following links elaborate:
300 * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
301 * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
303 * @param String $iv
304 * @see Crypt_RC4::setKey()
305 * @access public
307 function setIV($iv)
312 * Encrypts a message.
314 * @see Crypt_RC4::_crypt()
315 * @access public
316 * @param String $plaintext
318 function encrypt($plaintext)
320 return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
324 * Decrypts a message.
326 * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
327 * Atleast if the continuous buffer is disabled.
329 * @see Crypt_RC4::_crypt()
330 * @access public
331 * @param String $ciphertext
333 function decrypt($ciphertext)
335 return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
339 * Encrypts or decrypts a message.
341 * @see Crypt_RC4::encrypt()
342 * @see Crypt_RC4::decrypt()
343 * @access private
344 * @param String $text
345 * @param Integer $mode
347 function _crypt($text, $mode)
349 if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
350 $keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream';
352 if ($this->$keyStream === false) {
353 $this->$keyStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, '');
354 mcrypt_generic_init($this->$keyStream, $this->key, '');
355 } else if (!$this->continuousBuffer) {
356 mcrypt_generic_init($this->$keyStream, $this->key, '');
358 $newText = mcrypt_generic($this->$keyStream, $text);
359 if (!$this->continuousBuffer) {
360 mcrypt_generic_deinit($this->$keyStream);
363 return $newText;
366 if ($this->encryptStream === false) {
367 $this->setKey($this->key);
370 switch ($mode) {
371 case CRYPT_RC4_ENCRYPT:
372 $keyStream = $this->encryptStream;
373 list($i, $j) = $this->encryptIndex;
374 break;
375 case CRYPT_RC4_DECRYPT:
376 $keyStream = $this->decryptStream;
377 list($i, $j) = $this->decryptIndex;
380 $newText = '';
381 for ($k = 0; $k < strlen($text); $k++) {
382 $i = ($i + 1) & 255;
383 $j = ($j + $keyStream[$i]) & 255;
384 $temp = $keyStream[$i];
385 $keyStream[$i] = $keyStream[$j];
386 $keyStream[$j] = $temp;
387 $temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255];
388 $newText.= chr(ord($text[$k]) ^ $temp);
391 if ($this->continuousBuffer) {
392 switch ($mode) {
393 case CRYPT_RC4_ENCRYPT:
394 $this->encryptStream = $keyStream;
395 $this->encryptIndex = array($i, $j);
396 break;
397 case CRYPT_RC4_DECRYPT:
398 $this->decryptStream = $keyStream;
399 $this->decryptIndex = array($i, $j);
403 return $newText;
407 * Treat consecutive "packets" as if they are a continuous buffer.
409 * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
410 * will yield different outputs:
412 * <code>
413 * echo $rc4->encrypt(substr($plaintext, 0, 8));
414 * echo $rc4->encrypt(substr($plaintext, 8, 8));
415 * </code>
416 * <code>
417 * echo $rc4->encrypt($plaintext);
418 * </code>
420 * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
421 * another, as demonstrated with the following:
423 * <code>
424 * $rc4->encrypt(substr($plaintext, 0, 8));
425 * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
426 * </code>
427 * <code>
428 * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
429 * </code>
431 * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
432 * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
433 * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
435 * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
436 * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
437 * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
438 * however, they are also less intuitive and more likely to cause you problems.
440 * @see Crypt_RC4::disableContinuousBuffer()
441 * @access public
443 function enableContinuousBuffer()
445 $this->continuousBuffer = true;
449 * Treat consecutive packets as if they are a discontinuous buffer.
451 * The default behavior.
453 * @see Crypt_RC4::enableContinuousBuffer()
454 * @access public
456 function disableContinuousBuffer()
458 if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) {
459 $this->encryptIndex = $this->decryptIndex = array(0, 0);
460 $this->setKey($this->key);
463 $this->continuousBuffer = false;
467 * Dummy function.
469 * Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is
470 * included is so that you can switch between a block cipher and a stream cipher transparently.
472 * @see Crypt_RC4::disablePadding()
473 * @access public
475 function enablePadding()
480 * Dummy function.
482 * @see Crypt_RC4::enablePadding()
483 * @access public
485 function disablePadding()
490 * Class destructor.
492 * Will be called, automatically, if you're using PHP5. If you're using PHP4, call it yourself. Only really
493 * needs to be called if mcrypt is being used.
495 * @access public
497 function __destruct()
499 if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
500 $this->_closeMCrypt();
505 * Properly close the MCrypt objects.
507 * @access prviate
509 function _closeMCrypt()
511 if ( $this->encryptStream !== false ) {
512 if ( $this->continuousBuffer ) {
513 mcrypt_generic_deinit($this->encryptStream);
516 mcrypt_module_close($this->encryptStream);
518 $this->encryptStream = false;
521 if ( $this->decryptStream !== false ) {
522 if ( $this->continuousBuffer ) {
523 mcrypt_generic_deinit($this->decryptStream);
526 mcrypt_module_close($this->decryptStream);
528 $this->decryptStream = false;