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

Quick Search    Search Deep

Source code: cryptix/jce/provider/cipher/RC2.java


1   /* $Id: RC2.java,v 1.5 2000/02/11 21:07:19 gelderen Exp $
2    *
3    * Ported to Java from C code by Peter Gutmann (pgut01@cs.auckland.ac.nz)
4    * and Eric Young (eay@mincom.oz.au).
5    *
6    * Copyright (C) 1995-2000 The Cryptix Foundation Limited.
7    * All rights reserved.
8    *
9    * Use, modification, copying and distribution of this software is subject
10   * the terms and conditions of the Cryptix General Licence. You should have
11   * received a copy of the Cryptix General Licence along with this library;
12   * if not, you can download a copy from http://www.cryptix.org/ .
13   */
14  package cryptix.jce.provider.cipher;
15  
16  
17  import java.security.InvalidKeyException;
18  import java.security.Key;
19  
20  
21  /**
22   * RC2<sup>TM</sup>
23   * <p>
24   * The source code (C version) from which this port was done, and (most of)
25   * the programming notes, are by P. Gutmann (pgut01@cs.auckland.ac.nz) -- as
26   * obtained from Usenet.
27   * <p>
28   * Eric Young (eay@mincom.oz.au) implementation, also based on Gutmann's
29   * work, and included in Eric's colossal SSL library ver 0.6.6 14 Jan 1997,
30   * was also used for the initial key data and the computation of the session
31   * key schedule. Code to tailor the session key for a specified length in
32   * bits is included in this Java implementation but is crippled (commented
33   * out). The current code behaves as if the session key is fixed at 1024-bit.
34   * <p>
35   * The RC2 algorithm is word (16-bit entity) oriented, operating on a block of
36   * 64 bits (or 8 Java bytes) divided into four words, with a key table of 64
37   * words.
38   * <p>
39   * RC2 (TM) was designed by Ron Rivest, and was previously a trade secret of
40   * RSA Data Security, Inc. The algorithm has since been published as an RFC
41   * [reference?]. The name "RC2" is a trademark of RSA Data Security, Inc.
42   *
43   * @version $Revision: 1.5 $
44   * @author  Raif S. Naffah
45   * @author  Edwin Woudt            (edwin@cryptix.org)
46   * @author  Jeroen C. van Gelderen (gelderen@cryptix.org)
47   */
48  public final class RC2
49  extends BlockCipher
50  {
51  
52  // Static variables and constants
53  //............................................................................
54  
55      /** The block size, in bytes, of this cipher. */
56      public static final int BLOCK_SIZE = 8;
57  
58      /**
59       * RC2 uses a single 256-byte S-box derived from the ciphertext contents
60       * of Beale Cipher No.1 XOR'd with a one-time pad. The Beale Ciphers
61       * predate modern cryptography by enough time that there should be no
62       * concerns about trapdoors hidden in the data. They have been published
63       * widely, and the S-box can be easily recreated from the one-time pad
64       * values and the Beale Cipher data taken from a standard source. To
65       * initialise the S-box:
66       * <pre>
67       *   for i = 0 to 255 do
68       *     sBox[ i ] = ( beale[ i ] mod 256 ) ^ pad[ i ];
69       * </pre>
70       * <p>
71       * The following table gives the computed values based on the above.
72       * Thanks Eric :))
73       */
74      private static final int[] S_BOX = {
75          0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
76          0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
77          0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
78          0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
79          0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
80          0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
81          0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
82          0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
83          0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
84          0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
85          0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
86          0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
87          0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
88          0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
89          0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
90          0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
91          0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
92          0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
93          0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
94          0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
95          0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
96          0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
97          0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
98          0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
99          0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
100         0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
101         0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
102         0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
103         0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
104         0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
105         0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
106         0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD
107     };
108 
109 
110 // Instance variables
111 //............................................................................
112 
113     /** The session key. We're using the lower 16 bits of each int only. */
114     private int[] sKey = new int[64];
115 
116 
117     private boolean decrypt;
118 
119 
120 // Constructor
121 //............................................................................
122 
123     public RC2()
124     {
125         super(BLOCK_SIZE);
126     }
127 
128 
129 // Implementation of abstract methods
130 //............................................................................
131 
132 
133     protected void coreInit(Key key, boolean decrypt)
134     throws InvalidKeyException
135     {
136         makeKey(key);
137         this.decrypt = decrypt;
138     }
139 
140 
141     protected void coreCrypt(byte[] in, int inOffset, byte[] out, int outOffset)
142     {
143         if(decrypt)
144             blockDecrypt(in, inOffset, out, outOffset);
145         else
146             blockEncrypt(in, inOffset, out, outOffset);
147     }
148 
149 
150 // Own methods
151 //............................................................................
152 
153     /**
154      * Expands a user key to a working RC2 key.
155      * <p>
156      * The secret key is first expanded to fill 128 bytes (64 words).
157      * The expansion consists of taking the sum of the first and last
158      * bytes in the user key, looking up the sum (modulo 256) in the S-box,
159      * and appending the result to the key. The operation is repeated with
160      * the second byte and new last byte of the key until all 128 bytes
161      * have been generated. Note that the following pseudocode treats the S
162      * array (the session key) as an array of 128 bytes rather than 64 words:
163      * <pre>
164      *   for j = 0 to length-1 do
165      *     S[ j ] = K[ j ];
166      *   for j = length to 127 do
167      *     S[ j ] = sBox[ ( S[ j-length ] + S[ j-1 ] ) mod 256 ];
168      * </pre>
169      */
170     private void makeKey (Key key)
171     throws InvalidKeyException
172     {
173         byte[] userkey = key.getEncoded();
174         if (userkey == null)
175             throw new InvalidKeyException("Null RC2 user key");
176 
177         int len = userkey.length;
178         if (len > 128)
179             throw new InvalidKeyException("Invalid RC2 user key size");
180 
181         // first work with a 128 byte array
182         int[] sk = new int[128];
183         for (int i = 0; i < len; i++)
184             sk[i] = userkey[i] & 0xFF;
185 
186         for (int i = len; i < 128; i++)
187             sk[i] = S_BOX[(sk[i - len] + sk[i - 1]) & 0xFF];
188 
189         // The final phase of the key expansion involves replacing the
190         // first byte of S with the entry selected from the S-box. In fact
191         // this is a special case for tailoring the key to a given length.
192         // sk[0] = S_BOX[sk[0]];
193 
194         // hmm.... key reduction to 'bits' bits
195         sk[128 - len] = S_BOX[sk[128 - len] & 0xFF];
196         for (int i = 127 - len; i >= 0; i--)
197             sk[i] = S_BOX[sk[i + len] ^ sk[i + 1]];
198 
199         // now convert this byte array to the short array session key schedule
200         for (int i = 63; i >= 0; i--)
201             sKey[i] = (sk[i * 2 + 1] << 8 | sk[i * 2]) & 0xFFFF;
202     }
203 
204 
205     /**
206      * Encrypt a single block. Input and output may overlap.
207      * <p>
208      * The cipher has 16 full rounds, each divided into 4 subrounds.
209      * In addition the fifth and eleventh rounds add the contents of
210      * the S-box indexed by one of the data words to another of the
211      * data words following the four subrounds.
212      */
213     private void blockEncrypt (byte[] in, int inOff, byte[] out, int outOff)
214     {
215         int w0 = (in[inOff++] & 0xFF) | (in[inOff++] & 0xFF) << 8;
216         int w1 = (in[inOff++] & 0xFF) | (in[inOff++] & 0xFF) << 8;
217         int w2 = (in[inOff++] & 0xFF) | (in[inOff++] & 0xFF) << 8;
218         int w3 = (in[inOff++] & 0xFF) | (in[inOff  ] & 0xFF) << 8;
219         int j = 0;
220         for (int i = 0; i < 16; i++)
221         {
222             w0 = (w0 + (w1 & ~w3) + (w2 & w3) + sKey[j++]) & 0xFFFF;
223             w0 = w0 << 1 | w0 >>> 15;
224             w1 = (w1 + (w2 & ~w0) + (w3 & w0) + sKey[j++]) & 0xFFFF;
225             w1 = w1 << 2 | w1 >>> 14;
226             w2 = (w2 + (w3 & ~w1) + (w0 & w1) + sKey[j++]) & 0xFFFF;
227             w2 = w2 << 3 | w2 >>> 13;
228             w3 = (w3 + (w0 & ~w2) + (w1 & w2) + sKey[j++]) & 0xFFFF;
229             w3 = w3 << 5 | w3 >>> 11;
230             if ((i == 4) || (i == 10))
231             {
232                 w0 += sKey[w3 & 0x3F];
233                 w1 += sKey[w0 & 0x3F];
234                 w2 += sKey[w1 & 0x3F];
235                 w3 += sKey[w2 & 0x3F];
236             }
237         }
238         out[outOff++] = (byte) w0;
239         out[outOff++] = (byte)(w0 >>> 8);
240         out[outOff++] = (byte) w1;
241         out[outOff++] = (byte)(w1 >>> 8);
242         out[outOff++] = (byte) w2;
243         out[outOff++] = (byte)(w2 >>> 8);
244         out[outOff++] = (byte) w3;
245         out[outOff  ] = (byte)(w3 >>> 8);
246     }
247 
248 
249     /** Decrypt a single block. Input and output may overlap. */
250     private void blockDecrypt (byte[] in, int inOff, byte[] out, int outOff)
251     {
252         int w0 = (in[inOff + 0] & 0xFF) | (in[inOff + 1] & 0xFF) << 8;
253         int w1 = (in[inOff + 2] & 0xFF) | (in[inOff + 3] & 0xFF) << 8;
254         int w2 = (in[inOff + 4] & 0xFF) | (in[inOff + 5] & 0xFF) << 8;
255         int w3 = (in[inOff + 6] & 0xFF) | (in[inOff + 7] & 0xFF) << 8;
256         int j = 63;
257         for (int i = 15; i >= 0; i--)
258         {
259             w3 = (w3 >>> 5 | w3 << 11) & 0xFFFF;
260             w3 = (w3 - (w0 & ~w2) - (w1 & w2) - sKey[j--]) & 0xFFFF;
261             w2 = (w2 >>> 3 | w2 << 13) & 0xFFFF;
262             w2 = (w2 - (w3 & ~w1) - (w0 & w1) - sKey[j--]) & 0xFFFF;
263             w1 = (w1 >>> 2 | w1 << 14) & 0xFFFF;
264             w1 = (w1 - (w2 & ~w0) - (w3 & w0) - sKey[j--]) & 0xFFFF;
265             w0 = (w0 >>> 1 | w0 << 15) & 0xFFFF;
266             w0 = (w0 - (w1 & ~w3) - (w2 & w3) - sKey[j--]) & 0xFFFF;
267             if ((i == 11) || (i == 5))
268             {
269                 w3 = (w3 - sKey[w2 & 0x3F]) & 0xFFFF;
270                 w2 = (w2 - sKey[w1 & 0x3F]) & 0xFFFF;
271                 w1 = (w1 - sKey[w0 & 0x3F]) & 0xFFFF;
272                 w0 = (w0 - sKey[w3 & 0x3F]) & 0xFFFF;
273             }
274         }
275         out[outOff++] = (byte) w0;
276         out[outOff++] = (byte)(w0 >>> 8);
277         out[outOff++] = (byte) w1;
278         out[outOff++] = (byte)(w1 >>> 8);
279         out[outOff++] = (byte) w2;
280         out[outOff++] = (byte)(w2 >>> 8);
281         out[outOff++] = (byte) w3;
282         out[outOff  ] = (byte)(w3 >>> 8);
283     }
284 }