RC4.php 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  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 self::_crypt()
  72. */
  73. define('CRYPT_RC4_ENCRYPT', 0);
  74. define('CRYPT_RC4_DECRYPT', 1);
  75. /**#@-*/
  76. /**
  77. * Pure-PHP implementation of RC4.
  78. *
  79. * @package Crypt_RC4
  80. * @author Jim Wigginton <terrafrost@php.net>
  81. * @access public
  82. */
  83. class Crypt_RC4 extends Crypt_Base
  84. {
  85. /**
  86. * Block Length of the cipher
  87. *
  88. * RC4 is a stream cipher
  89. * so we the block_size to 0
  90. *
  91. * @see Crypt_Base::block_size
  92. * @var int
  93. * @access private
  94. */
  95. var $block_size = 0;
  96. /**
  97. * Key Length (in bytes)
  98. *
  99. * @see Crypt_RC4::setKeyLength()
  100. * @var int
  101. * @access private
  102. */
  103. var $key_length = 128; // = 1024 bits
  104. /**
  105. * The namespace used by the cipher for its constants.
  106. *
  107. * @see Crypt_Base::const_namespace
  108. * @var string
  109. * @access private
  110. */
  111. var $const_namespace = 'RC4';
  112. /**
  113. * The mcrypt specific name of the cipher
  114. *
  115. * @see Crypt_Base::cipher_name_mcrypt
  116. * @var string
  117. * @access private
  118. */
  119. var $cipher_name_mcrypt = 'arcfour';
  120. /**
  121. * Holds whether performance-optimized $inline_crypt() can/should be used.
  122. *
  123. * @see Crypt_Base::inline_crypt
  124. * @var mixed
  125. * @access private
  126. */
  127. var $use_inline_crypt = false; // currently not available
  128. /**
  129. * The Key
  130. *
  131. * @see self::setKey()
  132. * @var string
  133. * @access private
  134. */
  135. var $key;
  136. /**
  137. * The Key Stream for decryption and encryption
  138. *
  139. * @see self::setKey()
  140. * @var array
  141. * @access private
  142. */
  143. var $stream;
  144. /**
  145. * Default Constructor.
  146. *
  147. * Determines whether or not the mcrypt extension should be used.
  148. *
  149. * @see Crypt_Base::Crypt_Base()
  150. * @return Crypt_RC4
  151. * @access public
  152. */
  153. function __construct()
  154. {
  155. parent::__construct(CRYPT_MODE_STREAM);
  156. }
  157. /**
  158. * PHP4 compatible Default Constructor.
  159. *
  160. * @see self::__construct()
  161. * @access public
  162. */
  163. function Crypt_RC4()
  164. {
  165. $this->__construct();
  166. }
  167. /**
  168. * Test for engine validity
  169. *
  170. * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
  171. *
  172. * @see Crypt_Base::Crypt_Base()
  173. * @param int $engine
  174. * @access public
  175. * @return bool
  176. */
  177. function isValidEngine($engine)
  178. {
  179. if ($engine == CRYPT_ENGINE_OPENSSL) {
  180. if (version_compare(PHP_VERSION, '5.3.7') >= 0) {
  181. $this->cipher_name_openssl = 'rc4-40';
  182. } else {
  183. switch (strlen($this->key)) {
  184. case 5:
  185. $this->cipher_name_openssl = 'rc4-40';
  186. break;
  187. case 8:
  188. $this->cipher_name_openssl = 'rc4-64';
  189. break;
  190. case 16:
  191. $this->cipher_name_openssl = 'rc4';
  192. break;
  193. default:
  194. return false;
  195. }
  196. }
  197. }
  198. return parent::isValidEngine($engine);
  199. }
  200. /**
  201. * Dummy function.
  202. *
  203. * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
  204. * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
  205. * calling setKey().
  206. *
  207. * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
  208. * the IV's are relatively easy to predict, an attack described by
  209. * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
  210. * can be used to quickly guess at the rest of the key. The following links elaborate:
  211. *
  212. * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
  213. * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
  214. *
  215. * @param string $iv
  216. * @see self::setKey()
  217. * @access public
  218. */
  219. function setIV($iv)
  220. {
  221. }
  222. /**
  223. * Sets the key length
  224. *
  225. * Keys can be between 1 and 256 bytes long.
  226. *
  227. * @access public
  228. * @param int $length
  229. */
  230. function setKeyLength($length)
  231. {
  232. if ($length < 8) {
  233. $this->key_length = 1;
  234. } elseif ($length > 2048) {
  235. $this->key_length = 256;
  236. } else {
  237. $this->key_length = $length >> 3;
  238. }
  239. parent::setKeyLength($length);
  240. }
  241. /**
  242. * Encrypts a message.
  243. *
  244. * @see Crypt_Base::decrypt()
  245. * @see self::_crypt()
  246. * @access public
  247. * @param string $plaintext
  248. * @return string $ciphertext
  249. */
  250. function encrypt($plaintext)
  251. {
  252. if ($this->engine != CRYPT_ENGINE_INTERNAL) {
  253. return parent::encrypt($plaintext);
  254. }
  255. return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
  256. }
  257. /**
  258. * Decrypts a message.
  259. *
  260. * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
  261. * At least if the continuous buffer is disabled.
  262. *
  263. * @see Crypt_Base::encrypt()
  264. * @see self::_crypt()
  265. * @access public
  266. * @param string $ciphertext
  267. * @return string $plaintext
  268. */
  269. function decrypt($ciphertext)
  270. {
  271. if ($this->engine != CRYPT_ENGINE_INTERNAL) {
  272. return parent::decrypt($ciphertext);
  273. }
  274. return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
  275. }
  276. /**
  277. * Setup the key (expansion)
  278. *
  279. * @see Crypt_Base::_setupKey()
  280. * @access private
  281. */
  282. function _setupKey()
  283. {
  284. $key = $this->key;
  285. $keyLength = strlen($key);
  286. $keyStream = range(0, 255);
  287. $j = 0;
  288. for ($i = 0; $i < 256; $i++) {
  289. $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
  290. $temp = $keyStream[$i];
  291. $keyStream[$i] = $keyStream[$j];
  292. $keyStream[$j] = $temp;
  293. }
  294. $this->stream = array();
  295. $this->stream[CRYPT_RC4_DECRYPT] = $this->stream[CRYPT_RC4_ENCRYPT] = array(
  296. 0, // index $i
  297. 0, // index $j
  298. $keyStream
  299. );
  300. }
  301. /**
  302. * Encrypts or decrypts a message.
  303. *
  304. * @see self::encrypt()
  305. * @see self::decrypt()
  306. * @access private
  307. * @param string $text
  308. * @param int $mode
  309. * @return string $text
  310. */
  311. function _crypt($text, $mode)
  312. {
  313. if ($this->changed) {
  314. $this->_setup();
  315. $this->changed = false;
  316. }
  317. $stream = &$this->stream[$mode];
  318. if ($this->continuousBuffer) {
  319. $i = &$stream[0];
  320. $j = &$stream[1];
  321. $keyStream = &$stream[2];
  322. } else {
  323. $i = $stream[0];
  324. $j = $stream[1];
  325. $keyStream = $stream[2];
  326. }
  327. $len = strlen($text);
  328. for ($k = 0; $k < $len; ++$k) {
  329. $i = ($i + 1) & 255;
  330. $ksi = $keyStream[$i];
  331. $j = ($j + $ksi) & 255;
  332. $ksj = $keyStream[$j];
  333. $keyStream[$i] = $ksj;
  334. $keyStream[$j] = $ksi;
  335. $text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
  336. }
  337. return $text;
  338. }
  339. }