1 package org.bouncycastle.crypto.engines; 2 3 import org.bouncycastle.crypto.CipherParameters; 4 import org.bouncycastle.crypto.DataLengthException; 5 import org.bouncycastle.crypto.OutputLengthException; 6 import org.bouncycastle.crypto.StreamCipher; 7 import org.bouncycastle.crypto.params.KeyParameter; 8 9 public 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 void 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 104 public void reset() 105 { 106 setKey(workingKey); 107 } 108 109 // Private implementation 110 111 private void setKey(byte[] keyBytes) 112 { 113 workingKey = keyBytes; 114 115 // System.out.println("the key length is ; "+ workingKey.length); 116 117 x = 0; 118 y = 0; 119 120 if (engineState == null) 121 { 122 engineState = new byte[STATE_LENGTH]; 123 } 124 125 // reset the state of the engine 126 for (int i=0; i < STATE_LENGTH; i++) 127 { 128 engineState[i] = (byte)i; 129 } 130 131 int i1 = 0; 132 int i2 = 0; 133 134 for (int i=0; i < STATE_LENGTH; i++) 135 { 136 i2 = ((keyBytes[i1] & 0xff) + engineState[i] + i2) & 0xff; 137 // do the byte-swap inline 138 byte tmp = engineState[i]; 139 engineState[i] = engineState[i2]; 140 engineState[i2] = tmp; 141 i1 = (i1+1) % keyBytes.length; 142 } 143 } 144 } 145