Source code: cryptix/jce/provider/cipher/RC4.java
1 /* $Id: RC4.java,v 1.6 2003/02/15 13:42:36 gelderen Exp $
2 *
3 * Copyright (C) 1995-2000 The Cryptix Foundation Limited.
4 * All rights reserved.
5 *
6 * Use, modification, copying and distribution of this software is subject
7 * the terms and conditions of the Cryptix General Licence. You should have
8 * received a copy of the Cryptix General Licence along with this library;
9 * if not, you can download a copy from http://www.cryptix.org/ .
10 */
11 package cryptix.jce.provider.cipher;
12
13 import java.security.AlgorithmParameters;
14 import java.security.InvalidAlgorithmParameterException;
15
16 import java.security.InvalidKeyException;
17 import java.security.Key;
18 import java.security.NoSuchAlgorithmException;
19 import java.security.SecureRandom;
20 import java.security.spec.AlgorithmParameterSpec;
21
22 import javax.crypto.BadPaddingException;
23 import javax.crypto.CipherSpi;
24 import javax.crypto.IllegalBlockSizeException;
25 import javax.crypto.NoSuchPaddingException;
26 import javax.crypto.ShortBufferException;
27
28
29 /**
30 * This class implements the RC4<sup>TM</sup> stream cipher.
31 * <p>
32 * The source code (C version) from which this port was done, is the one
33 * posted to the sci.crypt, alt.security, comp.security.misc, and
34 * alt.privacy newsgroups on Wed, 14 Sep 1994 06:35:31 GMT by
35 * "David Sterndark" <sterndark@netcom.com>
36 * (Message-ID: <sternCvKL4B.Hyy@netcom.com>)
37 * <p>
38 * RC4 (TM) was designed by Ron Rivest, and was previously a trade secret of
39 * RSA Data Security, Inc. The algorithm is now in the public domain. The name
40 * "RC4" is a trademark of RSA Data Security, Inc.
41 * <p>
42 * References:
43 * <ul>
44 * <li> Bruce Schneier,
45 * "Section 17.1 RC4,"
46 * <cite>Applied Cryptography, 2nd edition</cite>,
47 * John Wiley & Sons, 1996.
48 * </ul>
49 *
50 * @version $Revision: 1.6 $
51 * @author Raif S. Naffah
52 * @author David Hopwood
53 * @since Cryptix 2.2.2
54 */
55 public final class RC4 extends CipherSpi
56 {
57
58 // RC4 constants and variables
59 //............................................................................
60
61 /** Contents of the current set S-box. */
62 private final int[] sBox = new int[256];
63
64 /**
65 * The two indices for the S-box computation referred to as i and j
66 * in Schneier.
67 */
68 private int x, y;
69
70 /**
71 * The block size of this cipher. Being a stream cipher this value
72 * is 1!
73 */
74 private static final int BLOCK_SIZE = 1;
75
76
77 // Constructor
78 //............................................................................
79
80 /**
81 * Constructs an RC4 cipher object, in the UNINITIALIZED state.
82 * This calls the Cipher constructor with <i>implBuffering</i> false,
83 * <i>implPadding</i> false and the provider set to "Cryptix".
84 */
85 public RC4()
86 {
87 super();
88 }
89
90
91 /**
92 * Always throws a CloneNotSupportedException (cloning of ciphers is not
93 * supported for security reasons).
94 */
95 public final Object clone() throws CloneNotSupportedException
96 {
97 throw new CloneNotSupportedException();
98 }
99
100
101 // Implementation of JCE methods
102 //............................................................................
103
104 protected final void engineSetMode(String mode)
105 throws NoSuchAlgorithmException
106 {
107 throw new NoSuchAlgorithmException();
108 }
109
110
111 protected final void engineSetPadding(String padding)
112 throws NoSuchPaddingException
113 {
114 throw new NoSuchPaddingException();
115 }
116
117
118 /**
119 * Returns the length of an input block, in bytes.
120 *
121 * @return the length in bytes of an input block for this cipher.
122 */
123 public int engineGetBlockSize ()
124 {
125 return BLOCK_SIZE;
126 }
127
128
129 protected int engineGetKeySize(Key key)
130 throws InvalidKeyException
131 {
132 if( key==null )
133 throw new IllegalArgumentException("Key missing");
134
135 if( !key.getFormat().equalsIgnoreCase("RAW") )
136 throw new InvalidKeyException("Wrong format: RAW bytes needed");
137
138 byte[] userkey = key.getEncoded();
139 if(userkey == null)
140 throw new InvalidKeyException("RAW bytes missing");
141
142 return (userkey.length * 8);
143 }
144
145
146 protected final int engineGetOutputSize(int inputLen)
147 {
148 return inputLen;
149 }
150
151
152 protected final byte[] engineGetIV()
153 {
154 return null;
155 }
156
157
158 protected final AlgorithmParameters engineGetParameters()
159 {
160 return null;
161 }
162
163
164 protected final void engineInit(int opmode, Key key, SecureRandom random)
165 throws InvalidKeyException
166 {
167 makeKey(key);
168 }
169
170
171 protected final void
172 engineInit(int opmode, Key key, AlgorithmParameterSpec params,
173 SecureRandom random)
174 throws InvalidKeyException, InvalidAlgorithmParameterException
175 {
176 engineInit(opmode, key, random);
177 }
178
179
180 protected final void
181 engineInit(int opmode, Key key, AlgorithmParameters params,
182 SecureRandom random)
183 throws InvalidKeyException, InvalidAlgorithmParameterException
184 {
185 engineInit(opmode, key, random);
186 }
187
188
189 protected final int
190 engineUpdate(byte[] input, int inputOffset, int inputLen,
191 byte[] output, int outputOffset)
192 throws ShortBufferException
193 {
194 int bufSize = output.length - outputOffset;
195 if( bufSize < inputLen )
196 throw new ShortBufferException();
197
198 return privateEngineUpdate(input, inputOffset, inputLen,
199 output, outputOffset);
200 }
201
202
203 protected final byte[]
204 engineUpdate(byte[] input, int inputOffset, int inputLen)
205 {
206 byte[] tmp = new byte[this.engineGetOutputSize(inputLen)];
207 privateEngineUpdate(input, inputOffset, inputLen, tmp, 0);
208 return tmp;
209 }
210
211
212 private final int
213 privateEngineUpdate(byte[] input, int inputOffset, int inputLen,
214 byte[] output, int outputOffset)
215 {
216 rc4(input, inputOffset, inputLen, output, outputOffset);
217 return inputLen;
218 }
219
220
221 protected final int
222 engineDoFinal(byte[] input, int inputOffset, int inputLen,
223 byte[] output, int outputOffset)
224 throws ShortBufferException, IllegalBlockSizeException, BadPaddingException
225 {
226 return engineUpdate(input, inputOffset, inputLen, output, outputOffset);
227 }
228
229
230 protected final byte[]
231 engineDoFinal(byte[] input, int inputOffset, int inputLen)
232 throws IllegalBlockSizeException, BadPaddingException
233 {
234 return engineUpdate(input, inputOffset, inputLen);
235 }
236
237
238 // Own methods
239 //............................................................................
240
241 /**
242 * RC4 encryption/decryption.
243 *
244 * @param in the input data.
245 * @param inOffset the offset into in specifying where the data starts.
246 * @param inLen the length of the subarray.
247 * @param out the output array.
248 * @param outOffset the offset indicating where to start writing into
249 * the out array.
250 */
251 private void rc4(byte[] in, int inOffset, int inLen,
252 byte[] out, int outOffset)
253 {
254 int xorIndex, t;
255
256 for (int i = 0; i < inLen; i++)
257 {
258 x = (x + 1) & 0xFF;
259 y = (sBox[x] + y) & 0xFF;
260
261 t = sBox[x];
262 sBox[x] = sBox[y];
263 sBox[y] = t;
264
265 xorIndex = (sBox[x] + sBox[y]) & 0xFF;
266 out[outOffset++] = (byte)(in[inOffset++] ^ sBox[xorIndex]);
267 }
268 }
269
270 /**
271 * Expands a user-key to a working key schedule.
272 * <p>
273 * The key bytes are first extracted from the user-key and then
274 * used to build the contents of this key schedule.
275 * <p>
276 * The method's only exceptions are when the user-key's contents
277 * are null, or a byte array of zero length.
278 *
279 * @param key the user-key object to use.
280 * @exception InvalidKeyException if one of the following occurs: <ul>
281 * <li> key.getEncoded() == null;
282 * <li> The encoded byte array form of the key is zero-length;
283 * </ul>
284 */
285 private void makeKey(Key key)
286 throws InvalidKeyException
287 {
288 byte[] userkey = key.getEncoded();
289 if (userkey == null)
290 throw new InvalidKeyException("Null user key");
291
292 int len = userkey.length;
293 if (len == 0)
294 throw new InvalidKeyException("Invalid user key length");
295
296 x = y = 0;
297 for (int i = 0; i < 256; i++)
298 sBox[i] = i;
299
300 int i1 = 0, i2 = 0, t;
301
302 for (int i = 0; i < 256; i++)
303 {
304 i2 = ((userkey[i1] & 0xFF) + sBox[i] + i2) & 0xFF;
305
306 t = sBox[i];
307 sBox[i] = sBox[i2];
308 sBox[i2] = t;
309
310 i1 = (i1 + 1) % len;
311 }
312 }
313 }