1package org.bouncycastle.crypto.engines;
2
3import org.bouncycastle.crypto.BlockCipher;
4import org.bouncycastle.crypto.CipherParameters;
5import org.bouncycastle.crypto.DataLengthException;
6import org.bouncycastle.crypto.params.KeyParameter;
7
8/**
9 * a class that provides a basic DES engine.
10 */
11public class DESEngine
12    implements BlockCipher
13{
14    protected static final int  BLOCK_SIZE = 8;
15
16    private int[]               workingKey = null;
17
18    /**
19     * standard constructor.
20     */
21    public DESEngine()
22    {
23    }
24
25    /**
26     * initialise a DES cipher.
27     *
28     * @param encrypting whether or not we are for encryption.
29     * @param params the parameters required to set up the cipher.
30     * @exception IllegalArgumentException if the params argument is
31     * inappropriate.
32     */
33    public void init(
34        boolean           encrypting,
35        CipherParameters  params)
36    {
37        if (params instanceof KeyParameter)
38        {
39            if (((KeyParameter)params).getKey().length > 8)
40            {
41                throw new IllegalArgumentException("DES key too long - should be 8 bytes");
42            }
43
44            workingKey = generateWorkingKey(encrypting,
45                                  ((KeyParameter)params).getKey());
46
47            return;
48        }
49
50        throw new IllegalArgumentException("invalid parameter passed to DES init - " + params.getClass().getName());
51    }
52
53    public String getAlgorithmName()
54    {
55        return "DES";
56    }
57
58    public int getBlockSize()
59    {
60        return BLOCK_SIZE;
61    }
62
63    public int processBlock(
64        byte[] in,
65        int inOff,
66        byte[] out,
67        int outOff)
68    {
69        if (workingKey == null)
70        {
71            throw new IllegalStateException("DES engine not initialised");
72        }
73
74        if ((inOff + BLOCK_SIZE) > in.length)
75        {
76            throw new DataLengthException("input buffer too short");
77        }
78
79        if ((outOff + BLOCK_SIZE) > out.length)
80        {
81            throw new DataLengthException("output buffer too short");
82        }
83
84        desFunc(workingKey, in, inOff, out, outOff);
85
86        return BLOCK_SIZE;
87    }
88
89    public void reset()
90    {
91    }
92
93    /**
94     * what follows is mainly taken from "Applied Cryptography", by
95     * Bruce Schneier, however it also bears great resemblance to Richard
96     * Outerbridge's D3DES...
97     */
98
99    static short[]    Df_Key =
100        {
101            0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
102            0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,
103            0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67
104        };
105
106    static short[]    bytebit =
107        {
108            0200, 0100, 040, 020, 010, 04, 02, 01
109        };
110
111    static int[]    bigbyte =
112        {
113            0x800000, 0x400000, 0x200000, 0x100000,
114            0x80000,  0x40000,  0x20000,  0x10000,
115            0x8000,      0x4000,   0x2000,   0x1000,
116            0x800,    0x400,    0x200,    0x100,
117            0x80,      0x40,        0x20,     0x10,
118            0x8,      0x4,      0x2,      0x1
119        };
120
121    /*
122     * Use the key schedule specified in the Standard (ANSI X3.92-1981).
123     */
124
125    static byte[]    pc1 =
126        {
127            56, 48, 40, 32, 24, 16,  8,   0, 57, 49, 41, 33, 25, 17,
128             9,  1, 58, 50, 42, 34, 26,  18, 10,  2, 59, 51, 43, 35,
129            62, 54, 46, 38, 30, 22, 14,   6, 61, 53, 45, 37, 29, 21,
130            13,  5, 60, 52, 44, 36, 28,  20, 12,  4, 27, 19, 11,  3
131        };
132
133    static byte[] totrot =
134        {
135            1, 2, 4, 6, 8, 10, 12, 14,
136            15, 17, 19, 21, 23, 25, 27, 28
137        };
138
139    static byte[] pc2 =
140        {
141            13, 16, 10, 23,  0,  4,  2, 27, 14,  5, 20,  9,
142            22, 18, 11,  3, 25,  7, 15,  6, 26, 19, 12,  1,
143            40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
144            43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31
145        };
146
147    static int[] SP1 = {
148        0x01010400, 0x00000000, 0x00010000, 0x01010404,
149        0x01010004, 0x00010404, 0x00000004, 0x00010000,
150        0x00000400, 0x01010400, 0x01010404, 0x00000400,
151        0x01000404, 0x01010004, 0x01000000, 0x00000004,
152        0x00000404, 0x01000400, 0x01000400, 0x00010400,
153        0x00010400, 0x01010000, 0x01010000, 0x01000404,
154        0x00010004, 0x01000004, 0x01000004, 0x00010004,
155        0x00000000, 0x00000404, 0x00010404, 0x01000000,
156        0x00010000, 0x01010404, 0x00000004, 0x01010000,
157        0x01010400, 0x01000000, 0x01000000, 0x00000400,
158        0x01010004, 0x00010000, 0x00010400, 0x01000004,
159        0x00000400, 0x00000004, 0x01000404, 0x00010404,
160        0x01010404, 0x00010004, 0x01010000, 0x01000404,
161        0x01000004, 0x00000404, 0x00010404, 0x01010400,
162        0x00000404, 0x01000400, 0x01000400, 0x00000000,
163        0x00010004, 0x00010400, 0x00000000, 0x01010004
164    };
165
166    static int[] SP2 = {
167        0x80108020, 0x80008000, 0x00008000, 0x00108020,
168        0x00100000, 0x00000020, 0x80100020, 0x80008020,
169        0x80000020, 0x80108020, 0x80108000, 0x80000000,
170        0x80008000, 0x00100000, 0x00000020, 0x80100020,
171        0x00108000, 0x00100020, 0x80008020, 0x00000000,
172        0x80000000, 0x00008000, 0x00108020, 0x80100000,
173        0x00100020, 0x80000020, 0x00000000, 0x00108000,
174        0x00008020, 0x80108000, 0x80100000, 0x00008020,
175        0x00000000, 0x00108020, 0x80100020, 0x00100000,
176        0x80008020, 0x80100000, 0x80108000, 0x00008000,
177        0x80100000, 0x80008000, 0x00000020, 0x80108020,
178        0x00108020, 0x00000020, 0x00008000, 0x80000000,
179        0x00008020, 0x80108000, 0x00100000, 0x80000020,
180        0x00100020, 0x80008020, 0x80000020, 0x00100020,
181        0x00108000, 0x00000000, 0x80008000, 0x00008020,
182        0x80000000, 0x80100020, 0x80108020, 0x00108000
183    };
184
185    static int[] SP3 = {
186        0x00000208, 0x08020200, 0x00000000, 0x08020008,
187        0x08000200, 0x00000000, 0x00020208, 0x08000200,
188        0x00020008, 0x08000008, 0x08000008, 0x00020000,
189        0x08020208, 0x00020008, 0x08020000, 0x00000208,
190        0x08000000, 0x00000008, 0x08020200, 0x00000200,
191        0x00020200, 0x08020000, 0x08020008, 0x00020208,
192        0x08000208, 0x00020200, 0x00020000, 0x08000208,
193        0x00000008, 0x08020208, 0x00000200, 0x08000000,
194        0x08020200, 0x08000000, 0x00020008, 0x00000208,
195        0x00020000, 0x08020200, 0x08000200, 0x00000000,
196        0x00000200, 0x00020008, 0x08020208, 0x08000200,
197        0x08000008, 0x00000200, 0x00000000, 0x08020008,
198        0x08000208, 0x00020000, 0x08000000, 0x08020208,
199        0x00000008, 0x00020208, 0x00020200, 0x08000008,
200        0x08020000, 0x08000208, 0x00000208, 0x08020000,
201        0x00020208, 0x00000008, 0x08020008, 0x00020200
202    };
203
204    static int[] SP4 = {
205        0x00802001, 0x00002081, 0x00002081, 0x00000080,
206        0x00802080, 0x00800081, 0x00800001, 0x00002001,
207        0x00000000, 0x00802000, 0x00802000, 0x00802081,
208        0x00000081, 0x00000000, 0x00800080, 0x00800001,
209        0x00000001, 0x00002000, 0x00800000, 0x00802001,
210        0x00000080, 0x00800000, 0x00002001, 0x00002080,
211        0x00800081, 0x00000001, 0x00002080, 0x00800080,
212        0x00002000, 0x00802080, 0x00802081, 0x00000081,
213        0x00800080, 0x00800001, 0x00802000, 0x00802081,
214        0x00000081, 0x00000000, 0x00000000, 0x00802000,
215        0x00002080, 0x00800080, 0x00800081, 0x00000001,
216        0x00802001, 0x00002081, 0x00002081, 0x00000080,
217        0x00802081, 0x00000081, 0x00000001, 0x00002000,
218        0x00800001, 0x00002001, 0x00802080, 0x00800081,
219        0x00002001, 0x00002080, 0x00800000, 0x00802001,
220        0x00000080, 0x00800000, 0x00002000, 0x00802080
221    };
222
223    static int[] SP5 = {
224        0x00000100, 0x02080100, 0x02080000, 0x42000100,
225        0x00080000, 0x00000100, 0x40000000, 0x02080000,
226        0x40080100, 0x00080000, 0x02000100, 0x40080100,
227        0x42000100, 0x42080000, 0x00080100, 0x40000000,
228        0x02000000, 0x40080000, 0x40080000, 0x00000000,
229        0x40000100, 0x42080100, 0x42080100, 0x02000100,
230        0x42080000, 0x40000100, 0x00000000, 0x42000000,
231        0x02080100, 0x02000000, 0x42000000, 0x00080100,
232        0x00080000, 0x42000100, 0x00000100, 0x02000000,
233        0x40000000, 0x02080000, 0x42000100, 0x40080100,
234        0x02000100, 0x40000000, 0x42080000, 0x02080100,
235        0x40080100, 0x00000100, 0x02000000, 0x42080000,
236        0x42080100, 0x00080100, 0x42000000, 0x42080100,
237        0x02080000, 0x00000000, 0x40080000, 0x42000000,
238        0x00080100, 0x02000100, 0x40000100, 0x00080000,
239        0x00000000, 0x40080000, 0x02080100, 0x40000100
240    };
241
242    static int[] SP6 = {
243        0x20000010, 0x20400000, 0x00004000, 0x20404010,
244        0x20400000, 0x00000010, 0x20404010, 0x00400000,
245        0x20004000, 0x00404010, 0x00400000, 0x20000010,
246        0x00400010, 0x20004000, 0x20000000, 0x00004010,
247        0x00000000, 0x00400010, 0x20004010, 0x00004000,
248        0x00404000, 0x20004010, 0x00000010, 0x20400010,
249        0x20400010, 0x00000000, 0x00404010, 0x20404000,
250        0x00004010, 0x00404000, 0x20404000, 0x20000000,
251        0x20004000, 0x00000010, 0x20400010, 0x00404000,
252        0x20404010, 0x00400000, 0x00004010, 0x20000010,
253        0x00400000, 0x20004000, 0x20000000, 0x00004010,
254        0x20000010, 0x20404010, 0x00404000, 0x20400000,
255        0x00404010, 0x20404000, 0x00000000, 0x20400010,
256        0x00000010, 0x00004000, 0x20400000, 0x00404010,
257        0x00004000, 0x00400010, 0x20004010, 0x00000000,
258        0x20404000, 0x20000000, 0x00400010, 0x20004010
259    };
260
261    static int[] SP7 = {
262        0x00200000, 0x04200002, 0x04000802, 0x00000000,
263        0x00000800, 0x04000802, 0x00200802, 0x04200800,
264        0x04200802, 0x00200000, 0x00000000, 0x04000002,
265        0x00000002, 0x04000000, 0x04200002, 0x00000802,
266        0x04000800, 0x00200802, 0x00200002, 0x04000800,
267        0x04000002, 0x04200000, 0x04200800, 0x00200002,
268        0x04200000, 0x00000800, 0x00000802, 0x04200802,
269        0x00200800, 0x00000002, 0x04000000, 0x00200800,
270        0x04000000, 0x00200800, 0x00200000, 0x04000802,
271        0x04000802, 0x04200002, 0x04200002, 0x00000002,
272        0x00200002, 0x04000000, 0x04000800, 0x00200000,
273        0x04200800, 0x00000802, 0x00200802, 0x04200800,
274        0x00000802, 0x04000002, 0x04200802, 0x04200000,
275        0x00200800, 0x00000000, 0x00000002, 0x04200802,
276        0x00000000, 0x00200802, 0x04200000, 0x00000800,
277        0x04000002, 0x04000800, 0x00000800, 0x00200002
278    };
279
280    static int[] SP8 = {
281        0x10001040, 0x00001000, 0x00040000, 0x10041040,
282        0x10000000, 0x10001040, 0x00000040, 0x10000000,
283        0x00040040, 0x10040000, 0x10041040, 0x00041000,
284        0x10041000, 0x00041040, 0x00001000, 0x00000040,
285        0x10040000, 0x10000040, 0x10001000, 0x00001040,
286        0x00041000, 0x00040040, 0x10040040, 0x10041000,
287        0x00001040, 0x00000000, 0x00000000, 0x10040040,
288        0x10000040, 0x10001000, 0x00041040, 0x00040000,
289        0x00041040, 0x00040000, 0x10041000, 0x00001000,
290        0x00000040, 0x10040040, 0x00001000, 0x00041040,
291        0x10001000, 0x00000040, 0x10000040, 0x10040000,
292        0x10040040, 0x10000000, 0x00040000, 0x10001040,
293        0x00000000, 0x10041040, 0x00040040, 0x10000040,
294        0x10040000, 0x10001000, 0x10001040, 0x00000000,
295        0x10041040, 0x00041000, 0x00041000, 0x00001040,
296        0x00001040, 0x00040040, 0x10000000, 0x10041000
297    };
298
299    /**
300     * generate an integer based working key based on our secret key
301     * and what we processing we are planning to do.
302     *
303     * Acknowledgements for this routine go to James Gillogly & Phil Karn.
304     *         (whoever, and wherever they are!).
305     */
306    protected int[] generateWorkingKey(
307        boolean encrypting,
308        byte[]  key)
309    {
310        int[]       newKey = new int[32];
311        boolean[]   pc1m = new boolean[56],
312                    pcr = new boolean[56];
313
314        for (int j = 0; j < 56; j++)
315        {
316            int    l = pc1[j];
317
318            pc1m[j] = ((key[l >>> 3] & bytebit[l & 07]) != 0);
319        }
320
321        for (int i = 0; i < 16; i++)
322        {
323            int    l, m, n;
324
325            if (encrypting)
326            {
327                m = i << 1;
328            }
329            else
330            {
331                m = (15 - i) << 1;
332            }
333
334            n = m + 1;
335            newKey[m] = newKey[n] = 0;
336
337            for (int j = 0; j < 28; j++)
338            {
339                l = j + totrot[i];
340                if (l < 28)
341                {
342                    pcr[j] = pc1m[l];
343                }
344                else
345                {
346                    pcr[j] = pc1m[l - 28];
347                }
348            }
349
350            for (int j = 28; j < 56; j++)
351            {
352                l = j + totrot[i];
353                if (l < 56)
354                {
355                    pcr[j] = pc1m[l];
356                }
357                else
358                {
359                    pcr[j] = pc1m[l - 28];
360                }
361            }
362
363            for (int j = 0; j < 24; j++)
364            {
365                if (pcr[pc2[j]])
366                {
367                    newKey[m] |= bigbyte[j];
368                }
369
370                if (pcr[pc2[j + 24]])
371                {
372                    newKey[n] |= bigbyte[j];
373                }
374            }
375        }
376
377        //
378        // store the processed key
379        //
380        for (int i = 0; i != 32; i += 2)
381        {
382            int    i1, i2;
383
384            i1 = newKey[i];
385            i2 = newKey[i + 1];
386
387            newKey[i] = ((i1 & 0x00fc0000) << 6) | ((i1 & 0x00000fc0) << 10)
388                                   | ((i2 & 0x00fc0000) >>> 10) | ((i2 & 0x00000fc0) >>> 6);
389
390            newKey[i + 1] = ((i1 & 0x0003f000) << 12) | ((i1 & 0x0000003f) << 16)
391                                   | ((i2 & 0x0003f000) >>> 4) | (i2 & 0x0000003f);
392        }
393
394        return newKey;
395    }
396
397    /**
398     * the DES engine.
399     */
400    protected void desFunc(
401        int[]   wKey,
402        byte[]  in,
403        int     inOff,
404        byte[]  out,
405        int     outOff)
406    {
407        int     work, right, left;
408
409        left     = (in[inOff + 0] & 0xff) << 24;
410        left    |= (in[inOff + 1] & 0xff) << 16;
411        left    |= (in[inOff + 2] & 0xff) << 8;
412        left    |= (in[inOff + 3] & 0xff);
413
414        right     = (in[inOff + 4] & 0xff) << 24;
415        right    |= (in[inOff + 5] & 0xff) << 16;
416        right    |= (in[inOff + 6] & 0xff) << 8;
417        right    |= (in[inOff + 7] & 0xff);
418
419        work = ((left >>> 4) ^ right) & 0x0f0f0f0f;
420        right ^= work;
421        left ^= (work << 4);
422        work = ((left >>> 16) ^ right) & 0x0000ffff;
423        right ^= work;
424        left ^= (work << 16);
425        work = ((right >>> 2) ^ left) & 0x33333333;
426        left ^= work;
427        right ^= (work << 2);
428        work = ((right >>> 8) ^ left) & 0x00ff00ff;
429        left ^= work;
430        right ^= (work << 8);
431        right = ((right << 1) | ((right >>> 31) & 1)) & 0xffffffff;
432        work = (left ^ right) & 0xaaaaaaaa;
433        left ^= work;
434        right ^= work;
435        left = ((left << 1) | ((left >>> 31) & 1)) & 0xffffffff;
436
437        for (int round = 0; round < 8; round++)
438        {
439            int     fval;
440
441            work  = (right << 28) | (right >>> 4);
442            work ^= wKey[round * 4 + 0];
443            fval  = SP7[ work      & 0x3f];
444            fval |= SP5[(work >>>  8) & 0x3f];
445            fval |= SP3[(work >>> 16) & 0x3f];
446            fval |= SP1[(work >>> 24) & 0x3f];
447            work  = right ^ wKey[round * 4 + 1];
448            fval |= SP8[ work      & 0x3f];
449            fval |= SP6[(work >>>  8) & 0x3f];
450            fval |= SP4[(work >>> 16) & 0x3f];
451            fval |= SP2[(work >>> 24) & 0x3f];
452            left ^= fval;
453            work  = (left << 28) | (left >>> 4);
454            work ^= wKey[round * 4 + 2];
455            fval  = SP7[ work      & 0x3f];
456            fval |= SP5[(work >>>  8) & 0x3f];
457            fval |= SP3[(work >>> 16) & 0x3f];
458            fval |= SP1[(work >>> 24) & 0x3f];
459            work  = left ^ wKey[round * 4 + 3];
460            fval |= SP8[ work      & 0x3f];
461            fval |= SP6[(work >>>  8) & 0x3f];
462            fval |= SP4[(work >>> 16) & 0x3f];
463            fval |= SP2[(work >>> 24) & 0x3f];
464            right ^= fval;
465        }
466
467        right = (right << 31) | (right >>> 1);
468        work = (left ^ right) & 0xaaaaaaaa;
469        left ^= work;
470        right ^= work;
471        left = (left << 31) | (left >>> 1);
472        work = ((left >>> 8) ^ right) & 0x00ff00ff;
473        right ^= work;
474        left ^= (work << 8);
475        work = ((left >>> 2) ^ right) & 0x33333333;
476        right ^= work;
477        left ^= (work << 2);
478        work = ((right >>> 16) ^ left) & 0x0000ffff;
479        left ^= work;
480        right ^= (work << 16);
481        work = ((right >>> 4) ^ left) & 0x0f0f0f0f;
482        left ^= work;
483        right ^= (work << 4);
484
485        out[outOff + 0] = (byte)((right >>> 24) & 0xff);
486        out[outOff + 1] = (byte)((right >>> 16) & 0xff);
487        out[outOff + 2] = (byte)((right >>>  8) & 0xff);
488        out[outOff + 3] = (byte)(right         & 0xff);
489        out[outOff + 4] = (byte)((left >>> 24) & 0xff);
490        out[outOff + 5] = (byte)((left >>> 16) & 0xff);
491        out[outOff + 6] = (byte)((left >>>  8) & 0xff);
492        out[outOff + 7] = (byte)(left         & 0xff);
493    }
494}
495