1 package org.bouncycastle.crypto.engines;
2
3 import org.bouncycastle.crypto.StreamCipher;
4 import org.bouncycastle.crypto.CipherParameters;
5 import org.bouncycastle.crypto.DataLengthException;
6 import org.bouncycastle.crypto.params.KeyParameter;
7
8 public class RC4Engine implements StreamCipher
9 {
10 private final static int STATE_LENGTH = 256;
11
12
16
17 private byte[] engineState = null;
18 private int x = 0;
19 private int y = 0;
20 private byte[] workingKey = null;
21
22
30 public void init(
31 boolean forEncryption,
32 CipherParameters params
33 )
34 {
35 if (params instanceof KeyParameter)
36 {
37
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
62 byte tmp = engineState[x];
63 engineState[x] = engineState[y];
64 engineState[y] = tmp;
65
66
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 {
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 DataLengthException("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
94 byte tmp = engineState[x];
95 engineState[x] = engineState[y];
96 engineState[y] = tmp;
97
98
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
110
111 private void setKey(byte[] keyBytes)
112 {
113 workingKey = keyBytes;
114
115
116
117 x = 0;
118 y = 0;
119
120 if (engineState == null)
121 {
122 engineState = new byte[STATE_LENGTH];
123 }
124
125
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
138 byte tmp = engineState[i];
139 engineState[i] = engineState[i2];
140 engineState[i2] = tmp;
141 i1 = (i1+1) % keyBytes.length;
142 }
143 }
144 }
145