--- /dev/null
+package org.bouncycastle.crypto.engines;\r
+\r
+import org.bouncycastle.crypto.StreamCipher;\r
+import org.bouncycastle.crypto.CipherParameters;\r
+import org.bouncycastle.crypto.DataLengthException;\r
+import org.bouncycastle.crypto.params.KeyParameter;\r
+\r
+public class RC4Engine implements StreamCipher\r
+{\r
+ private final static int STATE_LENGTH = 256;\r
+\r
+ /*\r
+ * variables to hold the state of the RC4 engine\r
+ * during encryption and decryption\r
+ */\r
+\r
+ private byte[] engineState = null;\r
+ private int x = 0;\r
+ private int y = 0;\r
+ private byte[] workingKey = null;\r
+\r
+ /**\r
+ * initialise a RC4 cipher.\r
+ *\r
+ * @param forEncryption whether or not we are for encryption.\r
+ * @param params the parameters required to set up the cipher.\r
+ * @exception IllegalArgumentException if the params argument is\r
+ * inappropriate.\r
+ */\r
+ public void init(\r
+ boolean forEncryption, \r
+ CipherParameters params\r
+ )\r
+ {\r
+ if (params instanceof KeyParameter)\r
+ {\r
+ /* \r
+ * RC4 encryption and decryption is completely\r
+ * symmetrical, so the 'forEncryption' is \r
+ * irrelevant.\r
+ */\r
+ workingKey = ((KeyParameter)params).getKey();\r
+ setKey(workingKey);\r
+\r
+ return;\r
+ }\r
+\r
+ throw new IllegalArgumentException("invalid parameter passed to RC4 init - " + params.getClass().getName());\r
+ }\r
+\r
+ public String getAlgorithmName()\r
+ {\r
+ return "RC4";\r
+ }\r
+\r
+ public byte returnByte(byte in)\r
+ {\r
+ x = (x + 1) & 0xff;\r
+ y = (engineState[x] + y) & 0xff;\r
+\r
+ // swap\r
+ byte tmp = engineState[x];\r
+ engineState[x] = engineState[y];\r
+ engineState[y] = tmp;\r
+\r
+ // xor\r
+ return (byte)(in ^ engineState[(engineState[x] + engineState[y]) & 0xff]);\r
+ }\r
+\r
+ public void processBytes(\r
+ byte[] in, \r
+ int inOff, \r
+ int len, \r
+ byte[] out, \r
+ int outOff\r
+ )\r
+ {\r
+ if ((inOff + len) > in.length)\r
+ {\r
+ throw new DataLengthException("input buffer too short");\r
+ }\r
+\r
+ if ((outOff + len) > out.length)\r
+ {\r
+ throw new DataLengthException("output buffer too short");\r
+ }\r
+\r
+ for (int i = 0; i < len ; i++)\r
+ {\r
+ x = (x + 1) & 0xff;\r
+ y = (engineState[x] + y) & 0xff;\r
+\r
+ // swap\r
+ byte tmp = engineState[x];\r
+ engineState[x] = engineState[y];\r
+ engineState[y] = tmp;\r
+\r
+ // xor\r
+ out[i+outOff] = (byte)(in[i + inOff]\r
+ ^ engineState[(engineState[x] + engineState[y]) & 0xff]);\r
+ }\r
+ }\r
+\r
+ public void reset()\r
+ {\r
+ setKey(workingKey);\r
+ }\r
+\r
+ // Private implementation\r
+\r
+ private void setKey(byte[] keyBytes)\r
+ {\r
+ workingKey = keyBytes;\r
+\r
+ // System.out.println("the key length is ; "+ workingKey.length);\r
+\r
+ x = 0;\r
+ y = 0;\r
+\r
+ if (engineState == null)\r
+ {\r
+ engineState = new byte[STATE_LENGTH];\r
+ }\r
+\r
+ // reset the state of the engine\r
+ for (int i=0; i < STATE_LENGTH; i++)\r
+ {\r
+ engineState[i] = (byte)i;\r
+ }\r
+ \r
+ int i1 = 0;\r
+ int i2 = 0;\r
+\r
+ for (int i=0; i < STATE_LENGTH; i++)\r
+ {\r
+ i2 = ((keyBytes[i1] & 0xff) + engineState[i] + i2) & 0xff;\r
+ // do the byte-swap inline\r
+ byte tmp = engineState[i];\r
+ engineState[i] = engineState[i2];\r
+ engineState[i2] = tmp;\r
+ i1 = (i1+1) % keyBytes.length; \r
+ }\r
+ }\r
+}\r