PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC4.php

https://github.com/sezuan/core
PHP | 519 lines | 185 code | 42 blank | 292 comment | 34 complexity | 1f59dc94952f75d195bee1bf9d14fe19 MD5 | raw file
Possible License(s): AGPL-3.0, AGPL-1.0, MPL-2.0-no-copyleft-exception
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * Pure-PHP implementation of RC4.
  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://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 refered to in the SSH1 specification.
  17. *
  18. * Here's a short example of how to use this library:
  19. * <code>
  20. * <?php
  21. * include('Crypt/RC4.php');
  22. *
  23. * $rc4 = new 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. * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
  38. * of this software and associated documentation files (the "Software"), to deal
  39. * in the Software without restriction, including without limitation the rights
  40. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  41. * copies of the Software, and to permit persons to whom the Software is
  42. * furnished to do so, subject to the following conditions:
  43. *
  44. * The above copyright notice and this permission notice shall be included in
  45. * all copies or substantial portions of the Software.
  46. *
  47. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  48. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  49. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  50. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  51. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  52. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  53. * THE SOFTWARE.
  54. *
  55. * @category Crypt
  56. * @package Crypt_RC4
  57. * @author Jim Wigginton <terrafrost@php.net>
  58. * @copyright MMVII Jim Wigginton
  59. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  60. * @version $Id: RC4.php,v 1.8 2009/06/09 04:00:38 terrafrost Exp $
  61. * @link http://phpseclib.sourceforge.net
  62. */
  63. /**#@+
  64. * @access private
  65. * @see Crypt_RC4::Crypt_RC4()
  66. */
  67. /**
  68. * Toggles the internal implementation
  69. */
  70. define('CRYPT_RC4_MODE_INTERNAL', 1);
  71. /**
  72. * Toggles the mcrypt implementation
  73. */
  74. define('CRYPT_RC4_MODE_MCRYPT', 2);
  75. /**#@-*/
  76. /**#@+
  77. * @access private
  78. * @see Crypt_RC4::_crypt()
  79. */
  80. define('CRYPT_RC4_ENCRYPT', 0);
  81. define('CRYPT_RC4_DECRYPT', 1);
  82. /**#@-*/
  83. /**
  84. * Pure-PHP implementation of RC4.
  85. *
  86. * @author Jim Wigginton <terrafrost@php.net>
  87. * @version 0.1.0
  88. * @access public
  89. * @package Crypt_RC4
  90. */
  91. class Crypt_RC4 {
  92. /**
  93. * The Key
  94. *
  95. * @see Crypt_RC4::setKey()
  96. * @var String
  97. * @access private
  98. */
  99. var $key = "\0";
  100. /**
  101. * The Key Stream for encryption
  102. *
  103. * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
  104. *
  105. * @see Crypt_RC4::setKey()
  106. * @var Array
  107. * @access private
  108. */
  109. var $encryptStream = false;
  110. /**
  111. * The Key Stream for decryption
  112. *
  113. * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
  114. *
  115. * @see Crypt_RC4::setKey()
  116. * @var Array
  117. * @access private
  118. */
  119. var $decryptStream = false;
  120. /**
  121. * The $i and $j indexes for encryption
  122. *
  123. * @see Crypt_RC4::_crypt()
  124. * @var Integer
  125. * @access private
  126. */
  127. var $encryptIndex = 0;
  128. /**
  129. * The $i and $j indexes for decryption
  130. *
  131. * @see Crypt_RC4::_crypt()
  132. * @var Integer
  133. * @access private
  134. */
  135. var $decryptIndex = 0;
  136. /**
  137. * The Encryption Algorithm
  138. *
  139. * Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR.
  140. *
  141. * @see Crypt_RC4::Crypt_RC4()
  142. * @var Integer
  143. * @access private
  144. */
  145. var $mode;
  146. /**
  147. * Continuous Buffer status
  148. *
  149. * @see Crypt_RC4::enableContinuousBuffer()
  150. * @var Boolean
  151. * @access private
  152. */
  153. var $continuousBuffer = false;
  154. /**
  155. * Default Constructor.
  156. *
  157. * Determines whether or not the mcrypt extension should be used.
  158. *
  159. * @return Crypt_RC4
  160. * @access public
  161. */
  162. function Crypt_RC4()
  163. {
  164. if ( !defined('CRYPT_RC4_MODE') ) {
  165. switch (true) {
  166. case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')) && in_array('arcfour', mcrypt_list_algorithms()):
  167. define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT);
  168. break;
  169. default:
  170. define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL);
  171. }
  172. }
  173. switch ( CRYPT_RC4_MODE ) {
  174. case CRYPT_RC4_MODE_MCRYPT:
  175. switch (true) {
  176. case defined('MCRYPT_ARCFOUR'):
  177. $this->mode = MCRYPT_ARCFOUR;
  178. break;
  179. case defined('MCRYPT_RC4');
  180. $this->mode = MCRYPT_RC4;
  181. }
  182. $this->encryptStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, '');
  183. $this->decryptStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, '');
  184. }
  185. }
  186. /**
  187. * Sets the key.
  188. *
  189. * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will
  190. * be used. If no key is explicitly set, it'll be assumed to be a single null byte.
  191. *
  192. * @access public
  193. * @param String $key
  194. */
  195. function setKey($key)
  196. {
  197. $this->key = $key;
  198. if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
  199. mcrypt_generic_init($this->encryptStream, $this->key, '');
  200. mcrypt_generic_init($this->decryptStream, $this->key, '');
  201. return;
  202. }
  203. $keyLength = strlen($key);
  204. $keyStream = array();
  205. for ($i = 0; $i < 256; $i++) {
  206. $keyStream[$i] = $i;
  207. }
  208. $j = 0;
  209. for ($i = 0; $i < 256; $i++) {
  210. $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
  211. $temp = $keyStream[$i];
  212. $keyStream[$i] = $keyStream[$j];
  213. $keyStream[$j] = $temp;
  214. }
  215. $this->encryptIndex = $this->decryptIndex = array(0, 0);
  216. $this->encryptStream = $this->decryptStream = $keyStream;
  217. }
  218. /**
  219. * Sets the password.
  220. *
  221. * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
  222. * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
  223. * $hash, $salt, $count, $dkLen
  224. *
  225. * @param String $password
  226. * @param optional String $method
  227. * @access public
  228. */
  229. function setPassword($password, $method = 'pbkdf2')
  230. {
  231. $key = '';
  232. switch ($method) {
  233. default: // 'pbkdf2'
  234. list(, , $hash, $salt, $count) = func_get_args();
  235. if (!isset($hash)) {
  236. $hash = 'sha1';
  237. }
  238. // WPA and WPA2 use the SSID as the salt
  239. if (!isset($salt)) {
  240. $salt = 'phpseclib/salt';
  241. }
  242. // RFC2898#section-4.2 uses 1,000 iterations by default
  243. // WPA and WPA2 use 4,096.
  244. if (!isset($count)) {
  245. $count = 1000;
  246. }
  247. if (!isset($dkLen)) {
  248. $dkLen = 128;
  249. }
  250. if (!class_exists('Crypt_Hash')) {
  251. require_once('Crypt/Hash.php');
  252. }
  253. $i = 1;
  254. while (strlen($key) < $dkLen) {
  255. //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
  256. $hmac = new Crypt_Hash();
  257. $hmac->setHash($hash);
  258. $hmac->setKey($password);
  259. $f = $u = $hmac->hash($salt . pack('N', $i++));
  260. for ($j = 2; $j <= $count; $j++) {
  261. $u = $hmac->hash($u);
  262. $f^= $u;
  263. }
  264. $key.= $f;
  265. }
  266. }
  267. $this->setKey(substr($key, 0, $dkLen));
  268. }
  269. /**
  270. * Dummy function.
  271. *
  272. * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
  273. * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
  274. * calling setKey().
  275. *
  276. * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
  277. * the IV's are relatively easy to predict, an attack described by
  278. * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
  279. * can be used to quickly guess at the rest of the key. The following links elaborate:
  280. *
  281. * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
  282. * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
  283. *
  284. * @param String $iv
  285. * @see Crypt_RC4::setKey()
  286. * @access public
  287. */
  288. function setIV($iv)
  289. {
  290. }
  291. /**
  292. * Encrypts a message.
  293. *
  294. * @see Crypt_RC4::_crypt()
  295. * @access public
  296. * @param String $plaintext
  297. */
  298. function encrypt($plaintext)
  299. {
  300. return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
  301. }
  302. /**
  303. * Decrypts a message.
  304. *
  305. * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
  306. * Atleast if the continuous buffer is disabled.
  307. *
  308. * @see Crypt_RC4::_crypt()
  309. * @access public
  310. * @param String $ciphertext
  311. */
  312. function decrypt($ciphertext)
  313. {
  314. return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
  315. }
  316. /**
  317. * Encrypts or decrypts a message.
  318. *
  319. * @see Crypt_RC4::encrypt()
  320. * @see Crypt_RC4::decrypt()
  321. * @access private
  322. * @param String $text
  323. * @param Integer $mode
  324. */
  325. function _crypt($text, $mode)
  326. {
  327. if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
  328. $keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream';
  329. if (!$this->continuousBuffer) {
  330. mcrypt_generic_init($this->$keyStream, $this->key, '');
  331. }
  332. return mcrypt_generic($this->$keyStream, $text);
  333. }
  334. if ($this->encryptStream === false) {
  335. $this->setKey($this->key);
  336. }
  337. switch ($mode) {
  338. case CRYPT_RC4_ENCRYPT:
  339. $keyStream = $this->encryptStream;
  340. list($i, $j) = $this->encryptIndex;
  341. break;
  342. case CRYPT_RC4_DECRYPT:
  343. $keyStream = $this->decryptStream;
  344. list($i, $j) = $this->decryptIndex;
  345. }
  346. $newText = '';
  347. for ($k = 0; $k < strlen($text); $k++) {
  348. $i = ($i + 1) & 255;
  349. $j = ($j + $keyStream[$i]) & 255;
  350. $temp = $keyStream[$i];
  351. $keyStream[$i] = $keyStream[$j];
  352. $keyStream[$j] = $temp;
  353. $temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255];
  354. $newText.= chr(ord($text[$k]) ^ $temp);
  355. }
  356. if ($this->continuousBuffer) {
  357. switch ($mode) {
  358. case CRYPT_RC4_ENCRYPT:
  359. $this->encryptStream = $keyStream;
  360. $this->encryptIndex = array($i, $j);
  361. break;
  362. case CRYPT_RC4_DECRYPT:
  363. $this->decryptStream = $keyStream;
  364. $this->decryptIndex = array($i, $j);
  365. }
  366. }
  367. return $newText;
  368. }
  369. /**
  370. * Treat consecutive "packets" as if they are a continuous buffer.
  371. *
  372. * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
  373. * will yield different outputs:
  374. *
  375. * <code>
  376. * echo $rc4->encrypt(substr($plaintext, 0, 8));
  377. * echo $rc4->encrypt(substr($plaintext, 8, 8));
  378. * </code>
  379. * <code>
  380. * echo $rc4->encrypt($plaintext);
  381. * </code>
  382. *
  383. * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
  384. * another, as demonstrated with the following:
  385. *
  386. * <code>
  387. * $rc4->encrypt(substr($plaintext, 0, 8));
  388. * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
  389. * </code>
  390. * <code>
  391. * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
  392. * </code>
  393. *
  394. * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
  395. * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
  396. * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
  397. *
  398. * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
  399. * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
  400. * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
  401. * however, they are also less intuitive and more likely to cause you problems.
  402. *
  403. * @see Crypt_RC4::disableContinuousBuffer()
  404. * @access public
  405. */
  406. function enableContinuousBuffer()
  407. {
  408. if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
  409. mcrypt_generic_init($this->encryptStream, $this->key, '');
  410. mcrypt_generic_init($this->decryptStream, $this->key, '');
  411. }
  412. $this->continuousBuffer = true;
  413. }
  414. /**
  415. * Treat consecutive packets as if they are a discontinuous buffer.
  416. *
  417. * The default behavior.
  418. *
  419. * @see Crypt_RC4::enableContinuousBuffer()
  420. * @access public
  421. */
  422. function disableContinuousBuffer()
  423. {
  424. if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) {
  425. $this->encryptIndex = $this->decryptIndex = array(0, 0);
  426. $this->encryptStream = $this->decryptStream = false;
  427. }
  428. $this->continuousBuffer = false;
  429. }
  430. /**
  431. * Dummy function.
  432. *
  433. * Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is
  434. * included is so that you can switch between a block cipher and a stream cipher transparently.
  435. *
  436. * @see Crypt_RC4::disablePadding()
  437. * @access public
  438. */
  439. function enablePadding()
  440. {
  441. }
  442. /**
  443. * Dummy function.
  444. *
  445. * @see Crypt_RC4::enablePadding()
  446. * @access public
  447. */
  448. function disablePadding()
  449. {
  450. }
  451. /**
  452. * Class destructor.
  453. *
  454. * Will be called, automatically, if you're using PHP5. If you're using PHP4, call it yourself. Only really
  455. * needs to be called if mcrypt is being used.
  456. *
  457. * @access public
  458. */
  459. function __destruct()
  460. {
  461. if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
  462. $this->_closeMCrypt();
  463. }
  464. }
  465. /**
  466. * Properly close the MCrypt objects.
  467. *
  468. * @access prviate
  469. */
  470. function _closeMCrypt()
  471. {
  472. mcrypt_module_close($this->encryptStream);
  473. mcrypt_module_close($this->decryptStream);
  474. }
  475. }
  476. // vim: ts=4:sw=4:et:
  477. // vim6: fdl=1: