001: package org.bouncycastle.crypto.engines;
002:
003: import org.bouncycastle.crypto.BlockCipher;
004: import org.bouncycastle.crypto.CipherParameters;
005: import org.bouncycastle.crypto.DataLengthException;
006: import org.bouncycastle.crypto.params.KeyParameter;
007: import org.bouncycastle.crypto.params.RC2Parameters;
008:
009: /**
010: * an implementation of RC2 as described in RFC 2268
011: * "A Description of the RC2(r) Encryption Algorithm" R. Rivest.
012: */
013: public class RC2Engine implements BlockCipher {
014: //
015: // the values we use for key expansion (based on the digits of PI)
016: //
017: private static byte[] piTable = { (byte) 0xd9, (byte) 0x78,
018: (byte) 0xf9, (byte) 0xc4, (byte) 0x19, (byte) 0xdd,
019: (byte) 0xb5, (byte) 0xed, (byte) 0x28, (byte) 0xe9,
020: (byte) 0xfd, (byte) 0x79, (byte) 0x4a, (byte) 0xa0,
021: (byte) 0xd8, (byte) 0x9d, (byte) 0xc6, (byte) 0x7e,
022: (byte) 0x37, (byte) 0x83, (byte) 0x2b, (byte) 0x76,
023: (byte) 0x53, (byte) 0x8e, (byte) 0x62, (byte) 0x4c,
024: (byte) 0x64, (byte) 0x88, (byte) 0x44, (byte) 0x8b,
025: (byte) 0xfb, (byte) 0xa2, (byte) 0x17, (byte) 0x9a,
026: (byte) 0x59, (byte) 0xf5, (byte) 0x87, (byte) 0xb3,
027: (byte) 0x4f, (byte) 0x13, (byte) 0x61, (byte) 0x45,
028: (byte) 0x6d, (byte) 0x8d, (byte) 0x9, (byte) 0x81,
029: (byte) 0x7d, (byte) 0x32, (byte) 0xbd, (byte) 0x8f,
030: (byte) 0x40, (byte) 0xeb, (byte) 0x86, (byte) 0xb7,
031: (byte) 0x7b, (byte) 0xb, (byte) 0xf0, (byte) 0x95,
032: (byte) 0x21, (byte) 0x22, (byte) 0x5c, (byte) 0x6b,
033: (byte) 0x4e, (byte) 0x82, (byte) 0x54, (byte) 0xd6,
034: (byte) 0x65, (byte) 0x93, (byte) 0xce, (byte) 0x60,
035: (byte) 0xb2, (byte) 0x1c, (byte) 0x73, (byte) 0x56,
036: (byte) 0xc0, (byte) 0x14, (byte) 0xa7, (byte) 0x8c,
037: (byte) 0xf1, (byte) 0xdc, (byte) 0x12, (byte) 0x75,
038: (byte) 0xca, (byte) 0x1f, (byte) 0x3b, (byte) 0xbe,
039: (byte) 0xe4, (byte) 0xd1, (byte) 0x42, (byte) 0x3d,
040: (byte) 0xd4, (byte) 0x30, (byte) 0xa3, (byte) 0x3c,
041: (byte) 0xb6, (byte) 0x26, (byte) 0x6f, (byte) 0xbf,
042: (byte) 0xe, (byte) 0xda, (byte) 0x46, (byte) 0x69,
043: (byte) 0x7, (byte) 0x57, (byte) 0x27, (byte) 0xf2,
044: (byte) 0x1d, (byte) 0x9b, (byte) 0xbc, (byte) 0x94,
045: (byte) 0x43, (byte) 0x3, (byte) 0xf8, (byte) 0x11,
046: (byte) 0xc7, (byte) 0xf6, (byte) 0x90, (byte) 0xef,
047: (byte) 0x3e, (byte) 0xe7, (byte) 0x6, (byte) 0xc3,
048: (byte) 0xd5, (byte) 0x2f, (byte) 0xc8, (byte) 0x66,
049: (byte) 0x1e, (byte) 0xd7, (byte) 0x8, (byte) 0xe8,
050: (byte) 0xea, (byte) 0xde, (byte) 0x80, (byte) 0x52,
051: (byte) 0xee, (byte) 0xf7, (byte) 0x84, (byte) 0xaa,
052: (byte) 0x72, (byte) 0xac, (byte) 0x35, (byte) 0x4d,
053: (byte) 0x6a, (byte) 0x2a, (byte) 0x96, (byte) 0x1a,
054: (byte) 0xd2, (byte) 0x71, (byte) 0x5a, (byte) 0x15,
055: (byte) 0x49, (byte) 0x74, (byte) 0x4b, (byte) 0x9f,
056: (byte) 0xd0, (byte) 0x5e, (byte) 0x4, (byte) 0x18,
057: (byte) 0xa4, (byte) 0xec, (byte) 0xc2, (byte) 0xe0,
058: (byte) 0x41, (byte) 0x6e, (byte) 0xf, (byte) 0x51,
059: (byte) 0xcb, (byte) 0xcc, (byte) 0x24, (byte) 0x91,
060: (byte) 0xaf, (byte) 0x50, (byte) 0xa1, (byte) 0xf4,
061: (byte) 0x70, (byte) 0x39, (byte) 0x99, (byte) 0x7c,
062: (byte) 0x3a, (byte) 0x85, (byte) 0x23, (byte) 0xb8,
063: (byte) 0xb4, (byte) 0x7a, (byte) 0xfc, (byte) 0x2,
064: (byte) 0x36, (byte) 0x5b, (byte) 0x25, (byte) 0x55,
065: (byte) 0x97, (byte) 0x31, (byte) 0x2d, (byte) 0x5d,
066: (byte) 0xfa, (byte) 0x98, (byte) 0xe3, (byte) 0x8a,
067: (byte) 0x92, (byte) 0xae, (byte) 0x5, (byte) 0xdf,
068: (byte) 0x29, (byte) 0x10, (byte) 0x67, (byte) 0x6c,
069: (byte) 0xba, (byte) 0xc9, (byte) 0xd3, (byte) 0x0,
070: (byte) 0xe6, (byte) 0xcf, (byte) 0xe1, (byte) 0x9e,
071: (byte) 0xa8, (byte) 0x2c, (byte) 0x63, (byte) 0x16,
072: (byte) 0x1, (byte) 0x3f, (byte) 0x58, (byte) 0xe2,
073: (byte) 0x89, (byte) 0xa9, (byte) 0xd, (byte) 0x38,
074: (byte) 0x34, (byte) 0x1b, (byte) 0xab, (byte) 0x33,
075: (byte) 0xff, (byte) 0xb0, (byte) 0xbb, (byte) 0x48,
076: (byte) 0xc, (byte) 0x5f, (byte) 0xb9, (byte) 0xb1,
077: (byte) 0xcd, (byte) 0x2e, (byte) 0xc5, (byte) 0xf3,
078: (byte) 0xdb, (byte) 0x47, (byte) 0xe5, (byte) 0xa5,
079: (byte) 0x9c, (byte) 0x77, (byte) 0xa, (byte) 0xa6,
080: (byte) 0x20, (byte) 0x68, (byte) 0xfe, (byte) 0x7f,
081: (byte) 0xc1, (byte) 0xad };
082:
083: private static final int BLOCK_SIZE = 8;
084:
085: private int[] workingKey;
086: private boolean encrypting;
087:
088: private int[] generateWorkingKey(byte[] key, int bits) {
089: int x;
090: int[] xKey = new int[128];
091:
092: for (int i = 0; i != key.length; i++) {
093: xKey[i] = key[i] & 0xff;
094: }
095:
096: // Phase 1: Expand input key to 128 bytes
097: int len = key.length;
098:
099: if (len < 128) {
100: int index = 0;
101:
102: x = xKey[len - 1];
103:
104: do {
105: x = piTable[(x + xKey[index++]) & 255] & 0xff;
106: xKey[len++] = x;
107: } while (len < 128);
108: }
109:
110: // Phase 2 - reduce effective key size to "bits"
111: len = (bits + 7) >> 3;
112: x = piTable[xKey[128 - len] & (255 >> (7 & -bits))] & 0xff;
113: xKey[128 - len] = x;
114:
115: for (int i = 128 - len - 1; i >= 0; i--) {
116: x = piTable[x ^ xKey[i + len]] & 0xff;
117: xKey[i] = x;
118: }
119:
120: // Phase 3 - copy to newKey in little-endian order
121: int[] newKey = new int[64];
122:
123: for (int i = 0; i != newKey.length; i++) {
124: newKey[i] = (xKey[2 * i] + (xKey[2 * i + 1] << 8));
125: }
126:
127: return newKey;
128: }
129:
130: /**
131: * initialise a RC2 cipher.
132: *
133: * @param encrypting whether or not we are for encryption.
134: * @param params the parameters required to set up the cipher.
135: * @exception IllegalArgumentException if the params argument is
136: * inappropriate.
137: */
138: public void init(boolean encrypting, CipherParameters params) {
139: this .encrypting = encrypting;
140:
141: if (params instanceof RC2Parameters) {
142: RC2Parameters param = (RC2Parameters) params;
143:
144: workingKey = generateWorkingKey(param.getKey(), param
145: .getEffectiveKeyBits());
146: } else if (params instanceof KeyParameter) {
147: byte[] key = ((KeyParameter) params).getKey();
148:
149: workingKey = generateWorkingKey(key, key.length * 8);
150: } else {
151: throw new IllegalArgumentException(
152: "invalid parameter passed to RC2 init - "
153: + params.getClass().getName());
154: }
155:
156: }
157:
158: public void reset() {
159: }
160:
161: public String getAlgorithmName() {
162: return "RC2";
163: }
164:
165: public int getBlockSize() {
166: return BLOCK_SIZE;
167: }
168:
169: public final int processBlock(byte[] in, int inOff, byte[] out,
170: int outOff) {
171: if (workingKey == null) {
172: throw new IllegalStateException(
173: "RC2 engine not initialised");
174: }
175:
176: if ((inOff + BLOCK_SIZE) > in.length) {
177: throw new DataLengthException("input buffer too short");
178: }
179:
180: if ((outOff + BLOCK_SIZE) > out.length) {
181: throw new DataLengthException("output buffer too short");
182: }
183:
184: if (encrypting) {
185: encryptBlock(in, inOff, out, outOff);
186: } else {
187: decryptBlock(in, inOff, out, outOff);
188: }
189:
190: return BLOCK_SIZE;
191: }
192:
193: /**
194: * return the result rotating the 16 bit number in x left by y
195: */
196: private int rotateWordLeft(int x, int y) {
197: x &= 0xffff;
198: return (x << y) | (x >> (16 - y));
199: }
200:
201: private void encryptBlock(byte[] in, int inOff, byte[] out,
202: int outOff) {
203: int x76, x54, x32, x10;
204:
205: x76 = ((in[inOff + 7] & 0xff) << 8) + (in[inOff + 6] & 0xff);
206: x54 = ((in[inOff + 5] & 0xff) << 8) + (in[inOff + 4] & 0xff);
207: x32 = ((in[inOff + 3] & 0xff) << 8) + (in[inOff + 2] & 0xff);
208: x10 = ((in[inOff + 1] & 0xff) << 8) + (in[inOff + 0] & 0xff);
209:
210: for (int i = 0; i <= 16; i += 4) {
211: x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76)
212: + workingKey[i], 1);
213: x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10)
214: + workingKey[i + 1], 2);
215: x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32)
216: + workingKey[i + 2], 3);
217: x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54)
218: + workingKey[i + 3], 5);
219: }
220:
221: x10 += workingKey[x76 & 63];
222: x32 += workingKey[x10 & 63];
223: x54 += workingKey[x32 & 63];
224: x76 += workingKey[x54 & 63];
225:
226: for (int i = 20; i <= 40; i += 4) {
227: x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76)
228: + workingKey[i], 1);
229: x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10)
230: + workingKey[i + 1], 2);
231: x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32)
232: + workingKey[i + 2], 3);
233: x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54)
234: + workingKey[i + 3], 5);
235: }
236:
237: x10 += workingKey[x76 & 63];
238: x32 += workingKey[x10 & 63];
239: x54 += workingKey[x32 & 63];
240: x76 += workingKey[x54 & 63];
241:
242: for (int i = 44; i < 64; i += 4) {
243: x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76)
244: + workingKey[i], 1);
245: x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10)
246: + workingKey[i + 1], 2);
247: x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32)
248: + workingKey[i + 2], 3);
249: x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54)
250: + workingKey[i + 3], 5);
251: }
252:
253: out[outOff + 0] = (byte) x10;
254: out[outOff + 1] = (byte) (x10 >> 8);
255: out[outOff + 2] = (byte) x32;
256: out[outOff + 3] = (byte) (x32 >> 8);
257: out[outOff + 4] = (byte) x54;
258: out[outOff + 5] = (byte) (x54 >> 8);
259: out[outOff + 6] = (byte) x76;
260: out[outOff + 7] = (byte) (x76 >> 8);
261: }
262:
263: private void decryptBlock(byte[] in, int inOff, byte[] out,
264: int outOff) {
265: int x76, x54, x32, x10;
266:
267: x76 = ((in[inOff + 7] & 0xff) << 8) + (in[inOff + 6] & 0xff);
268: x54 = ((in[inOff + 5] & 0xff) << 8) + (in[inOff + 4] & 0xff);
269: x32 = ((in[inOff + 3] & 0xff) << 8) + (in[inOff + 2] & 0xff);
270: x10 = ((in[inOff + 1] & 0xff) << 8) + (in[inOff + 0] & 0xff);
271:
272: for (int i = 60; i >= 44; i -= 4) {
273: x76 = rotateWordLeft(x76, 11)
274: - ((x10 & ~x54) + (x32 & x54) + workingKey[i + 3]);
275: x54 = rotateWordLeft(x54, 13)
276: - ((x76 & ~x32) + (x10 & x32) + workingKey[i + 2]);
277: x32 = rotateWordLeft(x32, 14)
278: - ((x54 & ~x10) + (x76 & x10) + workingKey[i + 1]);
279: x10 = rotateWordLeft(x10, 15)
280: - ((x32 & ~x76) + (x54 & x76) + workingKey[i]);
281: }
282:
283: x76 -= workingKey[x54 & 63];
284: x54 -= workingKey[x32 & 63];
285: x32 -= workingKey[x10 & 63];
286: x10 -= workingKey[x76 & 63];
287:
288: for (int i = 40; i >= 20; i -= 4) {
289: x76 = rotateWordLeft(x76, 11)
290: - ((x10 & ~x54) + (x32 & x54) + workingKey[i + 3]);
291: x54 = rotateWordLeft(x54, 13)
292: - ((x76 & ~x32) + (x10 & x32) + workingKey[i + 2]);
293: x32 = rotateWordLeft(x32, 14)
294: - ((x54 & ~x10) + (x76 & x10) + workingKey[i + 1]);
295: x10 = rotateWordLeft(x10, 15)
296: - ((x32 & ~x76) + (x54 & x76) + workingKey[i]);
297: }
298:
299: x76 -= workingKey[x54 & 63];
300: x54 -= workingKey[x32 & 63];
301: x32 -= workingKey[x10 & 63];
302: x10 -= workingKey[x76 & 63];
303:
304: for (int i = 16; i >= 0; i -= 4) {
305: x76 = rotateWordLeft(x76, 11)
306: - ((x10 & ~x54) + (x32 & x54) + workingKey[i + 3]);
307: x54 = rotateWordLeft(x54, 13)
308: - ((x76 & ~x32) + (x10 & x32) + workingKey[i + 2]);
309: x32 = rotateWordLeft(x32, 14)
310: - ((x54 & ~x10) + (x76 & x10) + workingKey[i + 1]);
311: x10 = rotateWordLeft(x10, 15)
312: - ((x32 & ~x76) + (x54 & x76) + workingKey[i]);
313: }
314:
315: out[outOff + 0] = (byte) x10;
316: out[outOff + 1] = (byte) (x10 >> 8);
317: out[outOff + 2] = (byte) x32;
318: out[outOff + 3] = (byte) (x32 >> 8);
319: out[outOff + 4] = (byte) x54;
320: out[outOff + 5] = (byte) (x54 >> 8);
321: out[outOff + 6] = (byte) x76;
322: out[outOff + 7] = (byte) (x76 >> 8);
323: }
324: }
|