001: package org.bouncycastle.crypto.engines;
002:
003: import org.bouncycastle.crypto.CipherParameters;
004: import org.bouncycastle.crypto.DataLengthException;
005: import org.bouncycastle.crypto.StreamCipher;
006: import org.bouncycastle.crypto.params.KeyParameter;
007:
008: public class RC4Engine implements StreamCipher {
009: private final static int STATE_LENGTH = 256;
010:
011: /*
012: * variables to hold the state of the RC4 engine
013: * during encryption and decryption
014: */
015:
016: private byte[] engineState = null;
017: private int x = 0;
018: private int y = 0;
019: private byte[] workingKey = null;
020:
021: /**
022: * initialise a RC4 cipher.
023: *
024: * @param forEncryption whether or not we are for encryption.
025: * @param params the parameters required to set up the cipher.
026: * @exception IllegalArgumentException if the params argument is
027: * inappropriate.
028: */
029: public void init(boolean forEncryption, CipherParameters params) {
030: if (params instanceof KeyParameter) {
031: /*
032: * RC4 encryption and decryption is completely
033: * symmetrical, so the 'forEncryption' is
034: * irrelevant.
035: */
036: workingKey = ((KeyParameter) params).getKey();
037: setKey(workingKey);
038:
039: return;
040: }
041:
042: throw new IllegalArgumentException(
043: "invalid parameter passed to RC4 init - "
044: + params.getClass().getName());
045: }
046:
047: public String getAlgorithmName() {
048: return "RC4";
049: }
050:
051: public byte returnByte(byte in) {
052: x = (x + 1) & 0xff;
053: y = (engineState[x] + y) & 0xff;
054:
055: // swap
056: byte tmp = engineState[x];
057: engineState[x] = engineState[y];
058: engineState[y] = tmp;
059:
060: // xor
061: return (byte) (in ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
062: }
063:
064: public void processBytes(byte[] in, int inOff, int len, byte[] out,
065: int outOff) {
066: if ((inOff + len) > in.length) {
067: throw new DataLengthException("input buffer too short");
068: }
069:
070: if ((outOff + len) > out.length) {
071: throw new DataLengthException("output buffer too short");
072: }
073:
074: for (int i = 0; i < len; i++) {
075: x = (x + 1) & 0xff;
076: y = (engineState[x] + y) & 0xff;
077:
078: // swap
079: byte tmp = engineState[x];
080: engineState[x] = engineState[y];
081: engineState[y] = tmp;
082:
083: // xor
084: out[i + outOff] = (byte) (in[i + inOff] ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
085: }
086: }
087:
088: public void reset() {
089: setKey(workingKey);
090: }
091:
092: // Private implementation
093:
094: private void setKey(byte[] keyBytes) {
095: workingKey = keyBytes;
096:
097: // System.out.println("the key length is ; "+ workingKey.length);
098:
099: x = 0;
100: y = 0;
101:
102: if (engineState == null) {
103: engineState = new byte[STATE_LENGTH];
104: }
105:
106: // reset the state of the engine
107: for (int i = 0; i < STATE_LENGTH; i++) {
108: engineState[i] = (byte) i;
109: }
110:
111: int i1 = 0;
112: int i2 = 0;
113:
114: for (int i = 0; i < STATE_LENGTH; i++) {
115: i2 = ((keyBytes[i1] & 0xff) + engineState[i] + i2) & 0xff;
116: // do the byte-swap inline
117: byte tmp = engineState[i];
118: engineState[i] = engineState[i2];
119: engineState[i2] = tmp;
120: i1 = (i1 + 1) % keyBytes.length;
121: }
122: }
123: }
|