Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

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" &lt;sterndark@netcom.com&gt;
36   * (Message-ID: &lt;sternCvKL4B.Hyy@netcom.com&gt;)
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 &amp; 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 }