OSDN Git Service

2006-08-14 Mark Wielaard <mark@klomp.org>
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / javax / crypto / cipher / Khazad.java
1 /* Khazad.java -- 
2    Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
3
4 This file is a part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or (at
9 your option) any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19 USA
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version.  */
37
38
39 package gnu.javax.crypto.cipher;
40
41 import gnu.java.security.Configuration;
42 import gnu.java.security.Registry;
43 import gnu.java.security.util.Util;
44
45 import java.security.InvalidKeyException;
46 import java.util.ArrayList;
47 import java.util.Collections;
48 import java.util.Iterator;
49 import java.util.logging.Logger;
50
51 /**
52  * Khazad is a 64-bit (legacy-level) block cipher that accepts a 128-bit key.
53  * The cipher is a uniform substitution-permutation network whose inverse only
54  * differs from the forward operation in the key schedule. The overall cipher
55  * design follows the Wide Trail strategy, favours component reuse, and permits
56  * a wide variety of implementation trade-offs.
57  * <p>
58  * References:
59  * <ol>
60  * <li><a
61  * href="http://planeta.terra.com.br/informatica/paulobarreto/KhazadPage.html">The
62  * Khazad Block Cipher</a>.<br>
63  * <a href="mailto:paulo.barreto@terra.com.br">Paulo S.L.M. Barreto</a> and <a
64  * href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a>.</li>
65  * </ol>
66  */
67 public final class Khazad
68     extends BaseCipher
69 {
70   private static final Logger log = Logger.getLogger(Khazad.class.getName());
71   private static final int DEFAULT_BLOCK_SIZE = 8; // in bytes
72   private static final int DEFAULT_KEY_SIZE = 16; // in bytes
73   private static final int R = 8; // standard number of rounds; para. 3.7
74   private static final String Sd = // p. 20 [KHAZAD]
75       "\uBA54\u2F74\u53D3\uD24D\u50AC\u8DBF\u7052\u9A4C"
76     + "\uEAD5\u97D1\u3351\u5BA6\uDE48\uA899\uDB32\uB7FC"
77     + "\uE39E\u919B\uE2BB\u416E\uA5CB\u6B95\uA1F3\uB102"
78     + "\uCCC4\u1D14\uC363\uDA5D\u5FDC\u7DCD\u7F5A\u6C5C"
79     + "\uF726\uFFED\uE89D\u6F8E\u19A0\uF089\u0F07\uAFFB"
80     + "\u0815\u0D04\u0164\uDF76\u79DD\u3D16\u3F37\u6D38"
81     + "\uB973\uE935\u5571\u7B8C\u7288\uF62A\u3E5E\u2746"
82     + "\u0C65\u6861\u03C1\u57D6\uD958\uD866\uD73A\uC83C"
83     + "\uFA96\uA798\uECB8\uC7AE\u694B\uABA9\u670A\u47F2"
84     + "\uB522\uE5EE\uBE2B\u8112\u831B\u0E23\uF545\u21CE"
85     + "\u492C\uF9E6\uB628\u1782\u1A8B\uFE8A\u09C9\u874E"
86     + "\uE12E\uE4E0\uEB90\uA41E\u8560\u0025\uF4F1\u940B"
87     + "\uE775\uEF34\u31D4\uD086\u7EAD\uFD29\u303B\u9FF8"
88     + "\uC613\u0605\uC511\u777C\u7A78\u361C\u3959\u1856"
89     + "\uB3B0\u2420\uB292\uA3C0\u4462\u10B4\u8443\u93C2"
90     + "\u4ABD\u8F2D\uBC9C\u6A40\uCFA2\u804F\u1FCA\uAA42";
91   private static final byte[] S = new byte[256];
92   private static final int[] T0 = new int[256];
93   private static final int[] T1 = new int[256];
94   private static final int[] T2 = new int[256];
95   private static final int[] T3 = new int[256];
96   private static final int[] T4 = new int[256];
97   private static final int[] T5 = new int[256];
98   private static final int[] T6 = new int[256];
99   private static final int[] T7 = new int[256];
100   private static final int[][] rc = new int[R + 1][2]; // round constants
101   /**
102    * KAT vector (from ecb_vk): I=120 KEY=00000000000000000000000000000100
103    * CT=A0C86A1BBE2CBF4C
104    */
105   private static final byte[] KAT_KEY =
106       Util.toBytesFromString("00000000000000000000000000000100");
107   private static final byte[] KAT_CT = Util.toBytesFromString("A0C86A1BBE2CBF4C");
108   /** caches the result of the correctness test, once executed. */
109   private static Boolean valid;
110
111   static
112     {
113       long time = System.currentTimeMillis();
114       long ROOT = 0x11d; // para. 2.1 [KHAZAD]
115       int i, j;
116       int s, s2, s3, s4, s5, s6, s7, s8, sb;
117       char c;
118       for (i = 0; i < 256; i++)
119         {
120           c = Sd.charAt(i >>> 1);
121           s = ((i & 1) == 0 ? c >>> 8 : c) & 0xFF;
122           S[i] = (byte) s;
123           s2 = s << 1;
124           if (s2 > 0xFF)
125             s2 ^= ROOT;
126           s3 = s2 ^ s;
127           s4 = s2 << 1;
128           if (s4 > 0xFF)
129             s4 ^= ROOT;
130           s5 = s4 ^ s;
131           s6 = s4 ^ s2;
132           s7 = s6 ^ s;
133           s8 = s4 << 1;
134           if (s8 > 0xFF)
135             s8 ^= ROOT;
136           sb = s8 ^ s2 ^ s;
137           T0[i] = s  << 24 | s3 << 16 | s4 << 8 | s5;
138           T1[i] = s3 << 24 | s  << 16 | s5 << 8 | s4;
139           T2[i] = s4 << 24 | s5 << 16 | s  << 8 | s3;
140           T3[i] = s5 << 24 | s4 << 16 | s3 << 8 | s;
141           T4[i] = s6 << 24 | s8 << 16 | sb << 8 | s7;
142           T5[i] = s8 << 24 | s6 << 16 | s7 << 8 | sb;
143           T6[i] = sb << 24 | s7 << 16 | s6 << 8 | s8;
144           T7[i] = s7 << 24 | sb << 16 | s8 << 8 | s6;
145         }
146       for (i = 0, j = 0; i < R + 1; i++) // compute round constant
147         {
148           rc[i][0] =  S[j++]         << 24
149                    | (S[j++] & 0xFF) << 16
150                    | (S[j++] & 0xFF) << 8
151                    | (S[j++] & 0xFF);
152           rc[i][1] =  S[j++]         << 24
153                    | (S[j++] & 0xFF) << 16
154                    | (S[j++] & 0xFF) << 8
155                    | (S[j++] & 0xFF);
156         }
157       time = System.currentTimeMillis() - time;
158       if (Configuration.DEBUG)
159         {
160           log.fine("Static data");
161           log.fine("T0[]:");
162           StringBuilder b;
163           for (i = 0; i < 64; i++)
164             {
165               b = new StringBuilder();
166               for (j = 0; j < 4; j++)
167                 b.append("0x").append(Util.toString(T0[i * 4 + j])).append(", ");
168               log.fine(b.toString());
169             }
170           log.fine("T1[]:");
171           for (i = 0; i < 64; i++)
172             {
173               b = new StringBuilder();
174               for (j = 0; j < 4; j++)
175                 b.append("0x").append(Util.toString(T1[i * 4 + j])).append(", ");
176               log.fine(b.toString());
177             }
178           log.fine("T2[]:");
179           for (i = 0; i < 64; i++)
180             {
181               b = new StringBuilder();
182               for (j = 0; j < 4; j++)
183                 b.append("0x").append(Util.toString(T2[i * 4 + j])).append(", ");
184               log.fine(b.toString());
185             }
186           log.fine("T3[]:");
187           for (i = 0; i < 64; i++)
188             {
189               b = new StringBuilder();
190               for (j = 0; j < 4; j++)
191                 b.append("0x").append(Util.toString(T3[i * 4 + j])).append(", ");
192               log.fine(b.toString());
193             }
194           log.fine("T4[]:");
195           for (i = 0; i < 64; i++)
196             {
197               b = new StringBuilder();
198               for (j = 0; j < 4; j++)
199                 b.append("0x").append(Util.toString(T4[i * 4 + j])).append(", ");
200               log.fine(b.toString());
201             }
202           log.fine("T5[]:");
203           for (i = 0; i < 64; i++)
204             {
205               b = new StringBuilder();
206               for (j = 0; j < 4; j++)
207                 b.append("0x").append(Util.toString(T5[i * 4 + j])).append(", ");
208               log.fine(b.toString());
209             }
210           log.fine("T6[]:");
211           for (i = 0; i < 64; i++)
212             {
213               b = new StringBuilder();
214               for (j = 0; j < 4; j++)
215                 b.append("0x").append(Util.toString(T6[i * 4 + j])).append(", ");
216               log.fine(b.toString());
217             }
218           log.fine("T7[]:");
219           for (i = 0; i < 64; i++)
220             {
221               b = new StringBuilder();
222               for (j = 0; j < 4; j++)
223                 b.append("0x").append(Util.toString(T7[i * 4 + j])).append(", ");
224               log.fine(b.toString());
225             }
226           log.fine("rc[]:");
227           for (i = 0; i < R + 1; i++)
228             log.fine("0x" + Util.toString(rc[i][0]) + Util.toString(rc[i][1]));
229           log.fine("Total initialization time: " + time + " ms.");
230         }
231     }
232
233   /** Trivial 0-arguments constructor. */
234   public Khazad()
235   {
236     super(Registry.KHAZAD_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE);
237   }
238
239   private static void khazad(byte[] in, int i, byte[] out, int j, int[][] K)
240   {
241     // sigma(K[0])
242     int k0 = K[0][0];
243     int k1 = K[0][1];
244     int a0 = (in[i++]         << 24
245            | (in[i++] & 0xFF) << 16
246            | (in[i++] & 0xFF) <<  8
247            | (in[i++] & 0xFF)      ) ^ k0;
248     int a1 = (in[i++]         << 24
249            | (in[i++] & 0xFF) << 16
250            | (in[i++] & 0xFF) <<  8
251            | (in[i  ] & 0xFF)      ) ^ k1;
252     int b0, b1;
253     // round function
254     for (int r = 1; r < R; r++)
255       {
256         k0 = K[r][0];
257         k1 = K[r][1];
258         b0 = T0[ a0 >>> 24        ]
259            ^ T1[(a0 >>> 16) & 0xFF]
260            ^ T2[(a0 >>>  8) & 0xFF]
261            ^ T3[ a0         & 0xFF]
262            ^ T4[ a1 >>> 24        ]
263            ^ T5[(a1 >>> 16) & 0xFF]
264            ^ T6[(a1 >>>  8) & 0xFF]
265            ^ T7[ a1         & 0xFF] ^ k0;
266         b1 = T0[ a1 >>> 24        ]
267            ^ T1[(a1 >>> 16) & 0xFF]
268            ^ T2[(a1 >>>  8) & 0xFF]
269            ^ T3[ a1         & 0xFF]
270            ^ T4[ a0 >>> 24        ]
271            ^ T5[(a0 >>> 16) & 0xFF]
272            ^ T6[(a0 >>>  8) & 0xFF]
273            ^ T7[ a0         & 0xFF] ^ k1;
274         a0 = b0;
275         a1 = b1;
276         if (Configuration.DEBUG)
277           log.fine("T" + r + "=" + Util.toString(a0) + Util.toString(a1));
278       }
279     // sigma(K[R]) o gamma applied to previous output
280     k0 = K[R][0];
281     k1 = K[R][1];
282     out[j++] = (byte)(S[ a0 >>> 24        ] ^ (k0 >>> 24));
283     out[j++] = (byte)(S[(a0 >>> 16) & 0xFF] ^ (k0 >>> 16));
284     out[j++] = (byte)(S[(a0 >>>  8) & 0xFF] ^ (k0 >>>  8));
285     out[j++] = (byte)(S[ a0         & 0xFF] ^  k0        );
286     out[j++] = (byte)(S[ a1 >>> 24        ] ^ (k1 >>> 24));
287     out[j++] = (byte)(S[(a1 >>> 16) & 0xFF] ^ (k1 >>> 16));
288     out[j++] = (byte)(S[(a1 >>>  8) & 0xFF] ^ (k1 >>>  8));
289     out[j  ] = (byte)(S[ a1         & 0xFF] ^  k1        );
290     if (Configuration.DEBUG)
291       log.fine("T=" + Util.toString(out, j - 7, 8) + "\n");
292   }
293
294   public Object clone()
295   {
296     Khazad result = new Khazad();
297     result.currentBlockSize = this.currentBlockSize;
298
299     return result;
300   }
301
302   public Iterator blockSizes()
303   {
304     ArrayList al = new ArrayList();
305     al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE));
306
307     return Collections.unmodifiableList(al).iterator();
308   }
309
310   public Iterator keySizes()
311   {
312     ArrayList al = new ArrayList();
313     al.add(Integer.valueOf(DEFAULT_KEY_SIZE));
314     return Collections.unmodifiableList(al).iterator();
315   }
316
317   /**
318    * Expands a user-supplied key material into a session key for a designated
319    * <i>block size</i>.
320    * 
321    * @param uk the 128-bit user-supplied key material.
322    * @param bs the desired block size in bytes.
323    * @return an Object encapsulating the session key.
324    * @exception IllegalArgumentException if the block size is not 16 (128-bit).
325    * @exception InvalidKeyException if the key data is invalid.
326    */
327   public Object makeKey(byte[] uk, int bs) throws InvalidKeyException
328   {
329     if (bs != DEFAULT_BLOCK_SIZE)
330       throw new IllegalArgumentException();
331     if (uk == null)
332       throw new InvalidKeyException("Empty key");
333     if (uk.length != 16)
334       throw new InvalidKeyException("Key is not 128-bit.");
335     int[][] Ke = new int[R + 1][2]; // encryption round keys
336     int[][] Kd = new int[R + 1][2]; // decryption round keys
337     int r, i;
338     int k20, k21, k10, k11, rc0, rc1, kr0, kr1;
339     i = 0;
340     k20 =  uk[i++]         << 24
341         | (uk[i++] & 0xFF) << 16
342         | (uk[i++] & 0xFF) << 8
343         | (uk[i++] & 0xFF);
344     k21 =  uk[i++]         << 24
345         | (uk[i++] & 0xFF) << 16
346         | (uk[i++] & 0xFF) << 8
347         | (uk[i++] & 0xFF);
348     k10 =  uk[i++]         << 24
349         | (uk[i++] & 0xFF) << 16
350         | (uk[i++] & 0xFF) << 8
351         | (uk[i++] & 0xFF);
352     k11 =  uk[i++]         << 24
353         | (uk[i++] & 0xFF) << 16
354         | (uk[i++] & 0xFF) << 8
355         | (uk[i++] & 0xFF);
356     for (r = 0, i = 0; r <= R; r++)
357       {
358         rc0 = rc[r][0];
359         rc1 = rc[r][1];
360         kr0 = T0[ k10 >>> 24        ]
361             ^ T1[(k10 >>> 16) & 0xFF]
362             ^ T2[(k10 >>>  8) & 0xFF]
363             ^ T3[ k10         & 0xFF]
364             ^ T4[(k11 >>> 24) & 0xFF]
365             ^ T5[(k11 >>> 16) & 0xFF]
366             ^ T6[(k11 >>>  8) & 0xFF]
367             ^ T7[ k11         & 0xFF] ^ rc0 ^ k20;
368         kr1 = T0[ k11 >>> 24        ]
369             ^ T1[(k11 >>> 16) & 0xFF]
370             ^ T2[(k11 >>>  8) & 0xFF]
371             ^ T3[ k11         & 0xFF]
372             ^ T4[(k10 >>> 24) & 0xFF]
373             ^ T5[(k10 >>> 16) & 0xFF]
374             ^ T6[(k10 >>>  8) & 0xFF]
375             ^ T7[ k10         & 0xFF] ^ rc1 ^ k21;
376         Ke[r][0] = kr0;
377         Ke[r][1] = kr1;
378         k20 = k10;
379         k21 = k11;
380         k10 = kr0;
381         k11 = kr1;
382         if (r == 0 || r == R)
383           {
384             Kd[R - r][0] = kr0;
385             Kd[R - r][1] = kr1;
386           }
387         else
388           {
389             Kd[R - r][0] = T0[S[ kr0 >>> 24        ] & 0xFF]
390                          ^ T1[S[(kr0 >>> 16) & 0xFF] & 0xFF]
391                          ^ T2[S[(kr0 >>>  8) & 0xFF] & 0xFF]
392                          ^ T3[S[ kr0         & 0xFF] & 0xFF]
393                          ^ T4[S[ kr1 >>> 24        ] & 0xFF]
394                          ^ T5[S[(kr1 >>> 16) & 0xFF] & 0xFF]
395                          ^ T6[S[(kr1 >>>  8) & 0xFF] & 0xFF]
396                          ^ T7[S[ kr1         & 0xFF] & 0xFF];
397             Kd[R - r][1] = T0[S[ kr1 >>> 24        ] & 0xFF]
398                          ^ T1[S[(kr1 >>> 16) & 0xFF] & 0xFF]
399                          ^ T2[S[(kr1 >>>  8) & 0xFF] & 0xFF]
400                          ^ T3[S[ kr1         & 0xFF] & 0xFF]
401                          ^ T4[S[ kr0 >>> 24        ] & 0xFF]
402                          ^ T5[S[(kr0 >>> 16) & 0xFF] & 0xFF]
403                          ^ T6[S[(kr0 >>>  8) & 0xFF] & 0xFF]
404                          ^ T7[S[ kr0         & 0xFF] & 0xFF];
405           }
406       }
407     if (Configuration.DEBUG)
408       {
409         log.fine("Key schedule");
410         log.fine("Ke[]:");
411         for (r = 0; r < R + 1; r++)
412           log.fine("#" + r + ": 0x" + Util.toString(Ke[r][0])
413                    + Util.toString(Ke[r][1]));
414         log.fine("Kd[]:");
415         for (r = 0; r < R + 1; r++)
416           log.fine("#" + r + ": 0x" + Util.toString(Kd[r][0])
417                    + Util.toString(Kd[r][1]));
418       }
419     return new Object[] { Ke, Kd };
420   }
421
422   public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
423   {
424     if (bs != DEFAULT_BLOCK_SIZE)
425       throw new IllegalArgumentException();
426     int[][] K = (int[][])((Object[]) k)[0];
427     khazad(in, i, out, j, K);
428   }
429
430   public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
431   {
432     if (bs != DEFAULT_BLOCK_SIZE)
433       throw new IllegalArgumentException();
434     int[][] K = (int[][])((Object[]) k)[1];
435     khazad(in, i, out, j, K);
436   }
437
438   public boolean selfTest()
439   {
440     if (valid == null)
441       {
442         boolean result = super.selfTest(); // do symmetry tests
443         if (result)
444           result = testKat(KAT_KEY, KAT_CT);
445         valid = Boolean.valueOf(result);
446       }
447     return valid.booleanValue();
448   }
449 }