RC4.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. <?php
  2. /**
  3. * Pure-PHP implementation of RC4.
  4. *
  5. * Uses mcrypt, if available, and an internal implementation, otherwise.
  6. *
  7. * PHP versions 4 and 5
  8. *
  9. * Useful resources are as follows:
  10. *
  11. * - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm}
  12. * - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
  13. *
  14. * RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not
  15. * ARCFOUR or ARC4 because RC4 is how it is referred to in the SSH1 specification.
  16. *
  17. * Here's a short example of how to use this library:
  18. * <code>
  19. * <?php
  20. * include 'Crypt/RC4.php';
  21. *
  22. * $rc4 = new Crypt_RC4();
  23. *
  24. * $rc4->setKey('abcdefgh');
  25. *
  26. * $size = 10 * 1024;
  27. * $plaintext = '';
  28. * for ($i = 0; $i < $size; $i++) {
  29. * $plaintext.= 'a';
  30. * }
  31. *
  32. * echo $rc4->decrypt($rc4->encrypt($plaintext));
  33. * ?>
  34. * </code>
  35. *
  36. * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
  37. * of this software and associated documentation files (the "Software"), to deal
  38. * in the Software without restriction, including without limitation the rights
  39. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  40. * copies of the Software, and to permit persons to whom the Software is
  41. * furnished to do so, subject to the following conditions:
  42. *
  43. * The above copyright notice and this permission notice shall be included in
  44. * all copies or substantial portions of the Software.
  45. *
  46. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  47. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  48. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  49. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  50. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  51. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  52. * THE SOFTWARE.
  53. *
  54. * @category Crypt
  55. * @package Crypt_RC4
  56. * @author Jim Wigginton <terrafrost@php.net>
  57. * @copyright 2007 Jim Wigginton
  58. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  59. * @link http://phpseclib.sourceforge.net
  60. */
  61. /**
  62. * Include Crypt_Base
  63. *
  64. * Base cipher class
  65. */
  66. if (!class_exists('Crypt_Base')) {
  67. include_once 'Base.php';
  68. }
  69. /**#@+
  70. * @access private
  71. * @see Crypt_RC4::Crypt_RC4()
  72. */
  73. /**
  74. * Toggles the internal implementation
  75. */
  76. define('CRYPT_RC4_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
  77. /**
  78. * Toggles the mcrypt implementation
  79. */
  80. define('CRYPT_RC4_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
  81. /**#@-*/
  82. /**#@+
  83. * @access private
  84. * @see Crypt_RC4::_crypt()
  85. */
  86. define('CRYPT_RC4_ENCRYPT', 0);
  87. define('CRYPT_RC4_DECRYPT', 1);
  88. /**#@-*/
  89. /**
  90. * Pure-PHP implementation of RC4.
  91. *
  92. * @package Crypt_RC4
  93. * @author Jim Wigginton <terrafrost@php.net>
  94. * @access public
  95. */
  96. class Crypt_RC4 extends Crypt_Base
  97. {
  98. /**
  99. * Block Length of the cipher
  100. *
  101. * RC4 is a stream cipher
  102. * so we the block_size to 0
  103. *
  104. * @see Crypt_Base::block_size
  105. * @var Integer
  106. * @access private
  107. */
  108. var $block_size = 0;
  109. /**
  110. * The default password key_size used by setPassword()
  111. *
  112. * @see Crypt_Base::password_key_size
  113. * @see Crypt_Base::setPassword()
  114. * @var Integer
  115. * @access private
  116. */
  117. var $password_key_size = 128; // = 1024 bits
  118. /**
  119. * The namespace used by the cipher for its constants.
  120. *
  121. * @see Crypt_Base::const_namespace
  122. * @var String
  123. * @access private
  124. */
  125. var $const_namespace = 'RC4';
  126. /**
  127. * The mcrypt specific name of the cipher
  128. *
  129. * @see Crypt_Base::cipher_name_mcrypt
  130. * @var String
  131. * @access private
  132. */
  133. var $cipher_name_mcrypt = 'arcfour';
  134. /**
  135. * Holds whether performance-optimized $inline_crypt() can/should be used.
  136. *
  137. * @see Crypt_Base::inline_crypt
  138. * @var mixed
  139. * @access private
  140. */
  141. var $use_inline_crypt = false; // currently not available
  142. /**
  143. * The Key
  144. *
  145. * @see Crypt_RC4::setKey()
  146. * @var String
  147. * @access private
  148. */
  149. var $key = "\0";
  150. /**
  151. * The Key Stream for decryption and encryption
  152. *
  153. * @see Crypt_RC4::setKey()
  154. * @var Array
  155. * @access private
  156. */
  157. var $stream;
  158. /**
  159. * Default Constructor.
  160. *
  161. * Determines whether or not the mcrypt extension should be used.
  162. *
  163. * @see Crypt_Base::Crypt_Base()
  164. * @return Crypt_RC4
  165. * @access public
  166. */
  167. function Crypt_RC4()
  168. {
  169. parent::Crypt_Base(CRYPT_MODE_STREAM);
  170. }
  171. /**
  172. * Dummy function.
  173. *
  174. * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
  175. * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
  176. * calling setKey().
  177. *
  178. * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
  179. * the IV's are relatively easy to predict, an attack described by
  180. * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
  181. * can be used to quickly guess at the rest of the key. The following links elaborate:
  182. *
  183. * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
  184. * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
  185. *
  186. * @param String $iv
  187. * @see Crypt_RC4::setKey()
  188. * @access public
  189. */
  190. function setIV($iv)
  191. {
  192. }
  193. /**
  194. * Sets the key.
  195. *
  196. * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will
  197. * be used. If no key is explicitly set, it'll be assumed to be a single null byte.
  198. *
  199. * @access public
  200. * @see Crypt_Base::setKey()
  201. * @param String $key
  202. */
  203. function setKey($key)
  204. {
  205. parent::setKey(substr($key, 0, 256));
  206. }
  207. /**
  208. * Encrypts a message.
  209. *
  210. * @see Crypt_Base::decrypt()
  211. * @see Crypt_RC4::_crypt()
  212. * @access public
  213. * @param String $plaintext
  214. * @return String $ciphertext
  215. */
  216. function encrypt($plaintext)
  217. {
  218. if ($this->engine == CRYPT_MODE_MCRYPT) {
  219. return parent::encrypt($plaintext);
  220. }
  221. return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
  222. }
  223. /**
  224. * Decrypts a message.
  225. *
  226. * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
  227. * At least if the continuous buffer is disabled.
  228. *
  229. * @see Crypt_Base::encrypt()
  230. * @see Crypt_RC4::_crypt()
  231. * @access public
  232. * @param String $ciphertext
  233. * @return String $plaintext
  234. */
  235. function decrypt($ciphertext)
  236. {
  237. if ($this->engine == CRYPT_MODE_MCRYPT) {
  238. return parent::decrypt($ciphertext);
  239. }
  240. return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
  241. }
  242. /**
  243. * Setup the key (expansion)
  244. *
  245. * @see Crypt_Base::_setupKey()
  246. * @access private
  247. */
  248. function _setupKey()
  249. {
  250. $key = $this->key;
  251. $keyLength = strlen($key);
  252. $keyStream = range(0, 255);
  253. $j = 0;
  254. for ($i = 0; $i < 256; $i++) {
  255. $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
  256. $temp = $keyStream[$i];
  257. $keyStream[$i] = $keyStream[$j];
  258. $keyStream[$j] = $temp;
  259. }
  260. $this->stream = array();
  261. $this->stream[CRYPT_RC4_DECRYPT] = $this->stream[CRYPT_RC4_ENCRYPT] = array(
  262. 0, // index $i
  263. 0, // index $j
  264. $keyStream
  265. );
  266. }
  267. /**
  268. * Encrypts or decrypts a message.
  269. *
  270. * @see Crypt_RC4::encrypt()
  271. * @see Crypt_RC4::decrypt()
  272. * @access private
  273. * @param String $text
  274. * @param Integer $mode
  275. * @return String $text
  276. */
  277. function _crypt($text, $mode)
  278. {
  279. if ($this->changed) {
  280. $this->_setup();
  281. $this->changed = false;
  282. }
  283. $stream = &$this->stream[$mode];
  284. if ($this->continuousBuffer) {
  285. $i = &$stream[0];
  286. $j = &$stream[1];
  287. $keyStream = &$stream[2];
  288. } else {
  289. $i = $stream[0];
  290. $j = $stream[1];
  291. $keyStream = $stream[2];
  292. }
  293. $len = strlen($text);
  294. for ($k = 0; $k < $len; ++$k) {
  295. $i = ($i + 1) & 255;
  296. $ksi = $keyStream[$i];
  297. $j = ($j + $ksi) & 255;
  298. $ksj = $keyStream[$j];
  299. $keyStream[$i] = $ksj;
  300. $keyStream[$j] = $ksi;
  301. $text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
  302. }
  303. return $text;
  304. }
  305. }