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