1package org.bouncycastle.crypto.engines; 2 3import org.bouncycastle.crypto.CipherParameters; 4import org.bouncycastle.crypto.DataLengthException; 5import org.bouncycastle.crypto.OutputLengthException; 6import org.bouncycastle.crypto.StreamCipher; 7import org.bouncycastle.crypto.params.KeyParameter; 8 9public class RC4Engine implements StreamCipher 10{ 11 private final static int STATE_LENGTH = 256; 12 13 /* 14 * variables to hold the state of the RC4 engine 15 * during encryption and decryption 16 */ 17 18 private byte[] engineState = null; 19 private int x = 0; 20 private int y = 0; 21 private byte[] workingKey = null; 22 23 /** 24 * initialise a RC4 cipher. 25 * 26 * @param forEncryption whether or not we are for encryption. 27 * @param params the parameters required to set up the cipher. 28 * @exception IllegalArgumentException if the params argument is 29 * inappropriate. 30 */ 31 public void init( 32 boolean forEncryption, 33 CipherParameters params 34 ) 35 { 36 if (params instanceof KeyParameter) 37 { 38 /* 39 * RC4 encryption and decryption is completely 40 * symmetrical, so the 'forEncryption' is 41 * irrelevant. 42 */ 43 workingKey = ((KeyParameter)params).getKey(); 44 setKey(workingKey); 45 46 return; 47 } 48 49 throw new IllegalArgumentException("invalid parameter passed to RC4 init - " + params.getClass().getName()); 50 } 51 52 public String getAlgorithmName() 53 { 54 return "RC4"; 55 } 56 57 public byte returnByte(byte in) 58 { 59 x = (x + 1) & 0xff; 60 y = (engineState[x] + y) & 0xff; 61 62 // swap 63 byte tmp = engineState[x]; 64 engineState[x] = engineState[y]; 65 engineState[y] = tmp; 66 67 // xor 68 return (byte)(in ^ engineState[(engineState[x] + engineState[y]) & 0xff]); 69 } 70 71 public int processBytes( 72 byte[] in, 73 int inOff, 74 int len, 75 byte[] out, 76 int outOff) 77 { 78 if ((inOff + len) > in.length) 79 { 80 throw new DataLengthException("input buffer too short"); 81 } 82 83 if ((outOff + len) > out.length) 84 { 85 throw new OutputLengthException("output buffer too short"); 86 } 87 88 for (int i = 0; i < len ; i++) 89 { 90 x = (x + 1) & 0xff; 91 y = (engineState[x] + y) & 0xff; 92 93 // swap 94 byte tmp = engineState[x]; 95 engineState[x] = engineState[y]; 96 engineState[y] = tmp; 97 98 // xor 99 out[i+outOff] = (byte)(in[i + inOff] 100 ^ engineState[(engineState[x] + engineState[y]) & 0xff]); 101 } 102 103 return len; 104 } 105 106 public void reset() 107 { 108 setKey(workingKey); 109 } 110 111 // Private implementation 112 113 private void setKey(byte[] keyBytes) 114 { 115 workingKey = keyBytes; 116 117 // System.out.println("the key length is ; "+ workingKey.length); 118 119 x = 0; 120 y = 0; 121 122 if (engineState == null) 123 { 124 engineState = new byte[STATE_LENGTH]; 125 } 126 127 // reset the state of the engine 128 for (int i=0; i < STATE_LENGTH; i++) 129 { 130 engineState[i] = (byte)i; 131 } 132 133 int i1 = 0; 134 int i2 = 0; 135 136 for (int i=0; i < STATE_LENGTH; i++) 137 { 138 i2 = ((keyBytes[i1] & 0xff) + engineState[i] + i2) & 0xff; 139 // do the byte-swap inline 140 byte tmp = engineState[i]; 141 engineState[i] = engineState[i2]; 142 engineState[i2] = tmp; 143 i1 = (i1+1) % keyBytes.length; 144 } 145 } 146} 147