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 }