RC4.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. <?php
  2. /**
  3. * Pure-PHP implementation of RC4.
  4. *
  5. * Uses mcrypt, if available, and an internal implementation, otherwise.
  6. *
  7. * PHP version 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 'vendor/autoload.php';
  21. *
  22. * $rc4 = new \phpseclib\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. * @category Crypt
  37. * @package RC4
  38. * @author Jim Wigginton <terrafrost@php.net>
  39. * @copyright 2007 Jim Wigginton
  40. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  41. * @link http://phpseclib.sourceforge.net
  42. */
  43. namespace phpseclib\Crypt;
  44. use phpseclib\Crypt\Common\StreamCipher;
  45. /**
  46. * Pure-PHP implementation of RC4.
  47. *
  48. * @package RC4
  49. * @author Jim Wigginton <terrafrost@php.net>
  50. * @access public
  51. */
  52. class RC4 extends StreamCipher
  53. {
  54. /**#@+
  55. * @access private
  56. * @see \phpseclib\Crypt\RC4::_crypt()
  57. */
  58. const ENCRYPT = 0;
  59. const DECRYPT = 1;
  60. /**#@-*/
  61. /**
  62. * Block Length of the cipher
  63. *
  64. * RC4 is a stream cipher
  65. * so we the block_size to 0
  66. *
  67. * @see \phpseclib\Crypt\Common\SymmetricKey::block_size
  68. * @var int
  69. * @access private
  70. */
  71. protected $block_size = 0;
  72. /**
  73. * Key Length (in bytes)
  74. *
  75. * @see \phpseclib\Crypt\RC4::setKeyLength()
  76. * @var int
  77. * @access private
  78. */
  79. protected $key_length = 128; // = 1024 bits
  80. /**
  81. * The mcrypt specific name of the cipher
  82. *
  83. * @see \phpseclib\Crypt\Common\SymmetricKey::cipher_name_mcrypt
  84. * @var string
  85. * @access private
  86. */
  87. protected $cipher_name_mcrypt = 'arcfour';
  88. /**
  89. * Holds whether performance-optimized $inline_crypt() can/should be used.
  90. *
  91. * @see \phpseclib\Crypt\Common\SymmetricKey::inline_crypt
  92. * @var mixed
  93. * @access private
  94. */
  95. protected $use_inline_crypt = false; // currently not available
  96. /**
  97. * The Key
  98. *
  99. * @see self::setKey()
  100. * @var string
  101. * @access private
  102. */
  103. protected $key;
  104. /**
  105. * The Key Stream for decryption and encryption
  106. *
  107. * @see self::setKey()
  108. * @var array
  109. * @access private
  110. */
  111. private $stream;
  112. /**
  113. * Default Constructor.
  114. *
  115. * @see \phpseclib\Crypt\Common\SymmetricKey::__construct()
  116. * @return \phpseclib\Crypt\RC4
  117. * @access public
  118. */
  119. public function __construct()
  120. {
  121. parent::__construct(self::MODE_STREAM);
  122. }
  123. /**
  124. * Test for engine validity
  125. *
  126. * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Common\SymmetricKey::isValidEngine()
  127. *
  128. * @see \phpseclib\Crypt\Common\SymmetricKey::__construct()
  129. * @param int $engine
  130. * @access public
  131. * @return bool
  132. */
  133. public function isValidEngine($engine)
  134. {
  135. if ($engine == self::ENGINE_OPENSSL) {
  136. $this->cipher_name_openssl = 'rc4-40';
  137. }
  138. return parent::isValidEngine($engine);
  139. }
  140. /**
  141. * RC4 does not use an IV
  142. *
  143. * @access public
  144. * @return bool
  145. */
  146. public function usesIV()
  147. {
  148. return false;
  149. }
  150. /**
  151. * Sets the key length
  152. *
  153. * Keys can be between 1 and 256 bytes long.
  154. *
  155. * @access public
  156. * @param int $length
  157. * @throws \LengthException if the key length is invalid
  158. */
  159. public function setKeyLength($length)
  160. {
  161. if ($length < 8 || $length > 2048) {
  162. throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 256 bytes are supported');
  163. }
  164. $this->key_length = $length >> 3;
  165. parent::setKeyLength($length);
  166. }
  167. /**
  168. * Sets the key length
  169. *
  170. * Keys can be between 1 and 256 bytes long.
  171. *
  172. * @access public
  173. * @param int $length
  174. * @throws \LengthException if the key length is invalid
  175. */
  176. public function setKey($key)
  177. {
  178. $length = strlen($key);
  179. if ($length < 1 || $length > 256) {
  180. throw new \LengthException('Key size of ' . $length . ' bytes is not supported by RC4. Keys must be between 1 and 256 bytes long');
  181. }
  182. parent::setKey($key);
  183. }
  184. /**
  185. * Encrypts a message.
  186. *
  187. * @see \phpseclib\Crypt\Common\SymmetricKey::decrypt()
  188. * @see self::crypt()
  189. * @access public
  190. * @param string $plaintext
  191. * @return string $ciphertext
  192. */
  193. public function encrypt($plaintext)
  194. {
  195. if ($this->engine != self::ENGINE_INTERNAL) {
  196. return parent::encrypt($plaintext);
  197. }
  198. return $this->crypt($plaintext, self::ENCRYPT);
  199. }
  200. /**
  201. * Decrypts a message.
  202. *
  203. * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
  204. * At least if the continuous buffer is disabled.
  205. *
  206. * @see \phpseclib\Crypt\Common\SymmetricKey::encrypt()
  207. * @see self::crypt()
  208. * @access public
  209. * @param string $ciphertext
  210. * @return string $plaintext
  211. */
  212. public function decrypt($ciphertext)
  213. {
  214. if ($this->engine != self::ENGINE_INTERNAL) {
  215. return parent::decrypt($ciphertext);
  216. }
  217. return $this->crypt($ciphertext, self::DECRYPT);
  218. }
  219. /**
  220. * Encrypts a block
  221. *
  222. * @access private
  223. * @param string $in
  224. */
  225. protected function encryptBlock($in)
  226. {
  227. // RC4 does not utilize this method
  228. }
  229. /**
  230. * Decrypts a block
  231. *
  232. * @access private
  233. * @param string $in
  234. */
  235. protected function decryptBlock($in)
  236. {
  237. // RC4 does not utilize this method
  238. }
  239. /**
  240. * Setup the key (expansion)
  241. *
  242. * @see \phpseclib\Crypt\Common\SymmetricKey::_setupKey()
  243. * @access private
  244. */
  245. protected function setupKey()
  246. {
  247. $key = $this->key;
  248. $keyLength = strlen($key);
  249. $keyStream = range(0, 255);
  250. $j = 0;
  251. for ($i = 0; $i < 256; $i++) {
  252. $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
  253. $temp = $keyStream[$i];
  254. $keyStream[$i] = $keyStream[$j];
  255. $keyStream[$j] = $temp;
  256. }
  257. $this->stream = [];
  258. $this->stream[self::DECRYPT] = $this->stream[self::ENCRYPT] = [
  259. 0, // index $i
  260. 0, // index $j
  261. $keyStream
  262. ];
  263. }
  264. /**
  265. * Encrypts or decrypts a message.
  266. *
  267. * @see self::encrypt()
  268. * @see self::decrypt()
  269. * @access private
  270. * @param string $text
  271. * @param int $mode
  272. * @return string $text
  273. */
  274. private function crypt($text, $mode)
  275. {
  276. if ($this->changed) {
  277. $this->setup();
  278. $this->changed = false;
  279. }
  280. $stream = &$this->stream[$mode];
  281. if ($this->continuousBuffer) {
  282. $i = &$stream[0];
  283. $j = &$stream[1];
  284. $keyStream = &$stream[2];
  285. } else {
  286. $i = $stream[0];
  287. $j = $stream[1];
  288. $keyStream = $stream[2];
  289. }
  290. $len = strlen($text);
  291. for ($k = 0; $k < $len; ++$k) {
  292. $i = ($i + 1) & 255;
  293. $ksi = $keyStream[$i];
  294. $j = ($j + $ksi) & 255;
  295. $ksj = $keyStream[$j];
  296. $keyStream[$i] = $ksj;
  297. $keyStream[$j] = $ksi;
  298. $text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
  299. }
  300. return $text;
  301. }
  302. }