Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / libjava / classpath / gnu / javax / crypto / cipher / Khazad.java
1 /* Khazad.java --
2    Copyright (C) 2001, 2002, 2003, 2006, 2010 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 = Configuration.DEBUG ?
71                         Logger.getLogger(Khazad.class.getName()) : null;
72   private static final int DEFAULT_BLOCK_SIZE = 8; // in bytes
73   private static final int DEFAULT_KEY_SIZE = 16; // in bytes
74   private static final int R = 8; // standard number of rounds; para. 3.7
75   private static final String Sd = // p. 20 [KHAZAD]
76       "\uBA54\u2F74\u53D3\uD24D\u50AC\u8DBF\u7052\u9A4C"
77     + "\uEAD5\u97D1\u3351\u5BA6\uDE48\uA899\uDB32\uB7FC"
78     + "\uE39E\u919B\uE2BB\u416E\uA5CB\u6B95\uA1F3\uB102"
79     + "\uCCC4\u1D14\uC363\uDA5D\u5FDC\u7DCD\u7F5A\u6C5C"
80     + "\uF726\uFFED\uE89D\u6F8E\u19A0\uF089\u0F07\uAFFB"
81     + "\u0815\u0D04\u0164\uDF76\u79DD\u3D16\u3F37\u6D38"
82     + "\uB973\uE935\u5571\u7B8C\u7288\uF62A\u3E5E\u2746"
83     + "\u0C65\u6861\u03C1\u57D6\uD958\uD866\uD73A\uC83C"
84     + "\uFA96\uA798\uECB8\uC7AE\u694B\uABA9\u670A\u47F2"
85     + "\uB522\uE5EE\uBE2B\u8112\u831B\u0E23\uF545\u21CE"
86     + "\u492C\uF9E6\uB628\u1782\u1A8B\uFE8A\u09C9\u874E"
87     + "\uE12E\uE4E0\uEB90\uA41E\u8560\u0025\uF4F1\u940B"
88     + "\uE775\uEF34\u31D4\uD086\u7EAD\uFD29\u303B\u9FF8"
89     + "\uC613\u0605\uC511\u777C\u7A78\u361C\u3959\u1856"
90     + "\uB3B0\u2420\uB292\uA3C0\u4462\u10B4\u8443\u93C2"
91     + "\u4ABD\u8F2D\uBC9C\u6A40\uCFA2\u804F\u1FCA\uAA42";
92   private static final byte[] S = new byte[256];
93   private static final int[] T0 = new int[256];
94   private static final int[] T1 = new int[256];
95   private static final int[] T2 = new int[256];
96   private static final int[] T3 = new int[256];
97   private static final int[] T4 = new int[256];
98   private static final int[] T5 = new int[256];
99   private static final int[] T6 = new int[256];
100   private static final int[] T7 = new int[256];
101   private static final int[][] rc = new int[R + 1][2]; // round constants
102   /**
103    * KAT vector (from ecb_vk): I=120 KEY=00000000000000000000000000000100
104    * CT=A0C86A1BBE2CBF4C
105    */
106   private static final byte[] KAT_KEY =
107       Util.toBytesFromString("00000000000000000000000000000100");
108   private static final byte[] KAT_CT = Util.toBytesFromString("A0C86A1BBE2CBF4C");
109   /** caches the result of the correctness test, once executed. */
110   private static Boolean valid;
111
112   static
113     {
114       long time = System.currentTimeMillis();
115       long ROOT = 0x11d; // para. 2.1 [KHAZAD]
116       int i, j;
117       int s, s2, s3, s4, s5, s6, s7, s8, sb;
118       char c;
119       for (i = 0; i < 256; i++)
120         {
121           c = Sd.charAt(i >>> 1);
122           s = ((i & 1) == 0 ? c >>> 8 : c) & 0xFF;
123           S[i] = (byte) s;
124           s2 = s << 1;
125           if (s2 > 0xFF)
126             s2 ^= ROOT;
127           s3 = s2 ^ s;
128           s4 = s2 << 1;
129           if (s4 > 0xFF)
130             s4 ^= ROOT;
131           s5 = s4 ^ s;
132           s6 = s4 ^ s2;
133           s7 = s6 ^ s;
134           s8 = s4 << 1;
135           if (s8 > 0xFF)
136             s8 ^= ROOT;
137           sb = s8 ^ s2 ^ s;
138           T0[i] = s  << 24 | s3 << 16 | s4 << 8 | s5;
139           T1[i] = s3 << 24 | s  << 16 | s5 << 8 | s4;
140           T2[i] = s4 << 24 | s5 << 16 | s  << 8 | s3;
141           T3[i] = s5 << 24 | s4 << 16 | s3 << 8 | s;
142           T4[i] = s6 << 24 | s8 << 16 | sb << 8 | s7;
143           T5[i] = s8 << 24 | s6 << 16 | s7 << 8 | sb;
144           T6[i] = sb << 24 | s7 << 16 | s6 << 8 | s8;
145           T7[i] = s7 << 24 | sb << 16 | s8 << 8 | s6;
146         }
147       for (i = 0, j = 0; i < R + 1; i++) // compute round constant
148         {
149           rc[i][0] =  S[j++]         << 24
150                    | (S[j++] & 0xFF) << 16
151                    | (S[j++] & 0xFF) << 8
152                    | (S[j++] & 0xFF);
153           rc[i][1] =  S[j++]         << 24
154                    | (S[j++] & 0xFF) << 16
155                    | (S[j++] & 0xFF) << 8
156                    | (S[j++] & 0xFF);
157         }
158       time = System.currentTimeMillis() - time;
159       if (Configuration.DEBUG)
160         {
161           log.fine("Static data");
162           log.fine("T0[]:");
163           StringBuilder b;
164           for (i = 0; i < 64; i++)
165             {
166               b = new StringBuilder();
167               for (j = 0; j < 4; j++)
168                 b.append("0x").append(Util.toString(T0[i * 4 + j])).append(", ");
169               log.fine(b.toString());
170             }
171           log.fine("T1[]:");
172           for (i = 0; i < 64; i++)
173             {
174               b = new StringBuilder();
175               for (j = 0; j < 4; j++)
176                 b.append("0x").append(Util.toString(T1[i * 4 + j])).append(", ");
177               log.fine(b.toString());
178             }
179           log.fine("T2[]:");
180           for (i = 0; i < 64; i++)
181             {
182               b = new StringBuilder();
183               for (j = 0; j < 4; j++)
184                 b.append("0x").append(Util.toString(T2[i * 4 + j])).append(", ");
185               log.fine(b.toString());
186             }
187           log.fine("T3[]:");
188           for (i = 0; i < 64; i++)
189             {
190               b = new StringBuilder();
191               for (j = 0; j < 4; j++)
192                 b.append("0x").append(Util.toString(T3[i * 4 + j])).append(", ");
193               log.fine(b.toString());
194             }
195           log.fine("T4[]:");
196           for (i = 0; i < 64; i++)
197             {
198               b = new StringBuilder();
199               for (j = 0; j < 4; j++)
200                 b.append("0x").append(Util.toString(T4[i * 4 + j])).append(", ");
201               log.fine(b.toString());
202             }
203           log.fine("T5[]:");
204           for (i = 0; i < 64; i++)
205             {
206               b = new StringBuilder();
207               for (j = 0; j < 4; j++)
208                 b.append("0x").append(Util.toString(T5[i * 4 + j])).append(", ");
209               log.fine(b.toString());
210             }
211           log.fine("T6[]:");
212           for (i = 0; i < 64; i++)
213             {
214               b = new StringBuilder();
215               for (j = 0; j < 4; j++)
216                 b.append("0x").append(Util.toString(T6[i * 4 + j])).append(", ");
217               log.fine(b.toString());
218             }
219           log.fine("T7[]:");
220           for (i = 0; i < 64; i++)
221             {
222               b = new StringBuilder();
223               for (j = 0; j < 4; j++)
224                 b.append("0x").append(Util.toString(T7[i * 4 + j])).append(", ");
225               log.fine(b.toString());
226             }
227           log.fine("rc[]:");
228           for (i = 0; i < R + 1; i++)
229             log.fine("0x" + Util.toString(rc[i][0]) + Util.toString(rc[i][1]));
230           log.fine("Total initialization time: " + time + " ms.");
231         }
232     }
233
234   /** Trivial 0-arguments constructor. */
235   public Khazad()
236   {
237     super(Registry.KHAZAD_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE);
238   }
239
240   private static void khazad(byte[] in, int i, byte[] out, int j, int[][] K)
241   {
242     // sigma(K[0])
243     int k0 = K[0][0];
244     int k1 = K[0][1];
245     int a0 = (in[i++]         << 24
246            | (in[i++] & 0xFF) << 16
247            | (in[i++] & 0xFF) <<  8
248            | (in[i++] & 0xFF)      ) ^ k0;
249     int a1 = (in[i++]         << 24
250            | (in[i++] & 0xFF) << 16
251            | (in[i++] & 0xFF) <<  8
252            | (in[i  ] & 0xFF)      ) ^ k1;
253     int b0, b1;
254     // round function
255     for (int r = 1; r < R; r++)
256       {
257         k0 = K[r][0];
258         k1 = K[r][1];
259         b0 = T0[ a0 >>> 24        ]
260            ^ T1[(a0 >>> 16) & 0xFF]
261            ^ T2[(a0 >>>  8) & 0xFF]
262            ^ T3[ a0         & 0xFF]
263            ^ T4[ a1 >>> 24        ]
264            ^ T5[(a1 >>> 16) & 0xFF]
265            ^ T6[(a1 >>>  8) & 0xFF]
266            ^ T7[ a1         & 0xFF] ^ k0;
267         b1 = T0[ a1 >>> 24        ]
268            ^ T1[(a1 >>> 16) & 0xFF]
269            ^ T2[(a1 >>>  8) & 0xFF]
270            ^ T3[ a1         & 0xFF]
271            ^ T4[ a0 >>> 24        ]
272            ^ T5[(a0 >>> 16) & 0xFF]
273            ^ T6[(a0 >>>  8) & 0xFF]
274            ^ T7[ a0         & 0xFF] ^ k1;
275         a0 = b0;
276         a1 = b1;
277         if (Configuration.DEBUG)
278           log.fine("T" + r + "=" + Util.toString(a0) + Util.toString(a1));
279       }
280     // sigma(K[R]) o gamma applied to previous output
281     k0 = K[R][0];
282     k1 = K[R][1];
283     out[j++] = (byte)(S[ a0 >>> 24        ] ^ (k0 >>> 24));
284     out[j++] = (byte)(S[(a0 >>> 16) & 0xFF] ^ (k0 >>> 16));
285     out[j++] = (byte)(S[(a0 >>>  8) & 0xFF] ^ (k0 >>>  8));
286     out[j++] = (byte)(S[ a0         & 0xFF] ^  k0        );
287     out[j++] = (byte)(S[ a1 >>> 24        ] ^ (k1 >>> 24));
288     out[j++] = (byte)(S[(a1 >>> 16) & 0xFF] ^ (k1 >>> 16));
289     out[j++] = (byte)(S[(a1 >>>  8) & 0xFF] ^ (k1 >>>  8));
290     out[j  ] = (byte)(S[ a1         & 0xFF] ^  k1        );
291     if (Configuration.DEBUG)
292       log.fine("T=" + Util.toString(out, j - 7, 8) + "\n");
293   }
294
295   public Object clone()
296   {
297     Khazad result = new Khazad();
298     result.currentBlockSize = this.currentBlockSize;
299
300     return result;
301   }
302
303   public Iterator blockSizes()
304   {
305     ArrayList al = new ArrayList();
306     al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE));
307
308     return Collections.unmodifiableList(al).iterator();
309   }
310
311   public Iterator keySizes()
312   {
313     ArrayList al = new ArrayList();
314     al.add(Integer.valueOf(DEFAULT_KEY_SIZE));
315     return Collections.unmodifiableList(al).iterator();
316   }
317
318   /**
319    * Expands a user-supplied key material into a session key for a designated
320    * <i>block size</i>.
321    *
322    * @param uk the 128-bit user-supplied key material.
323    * @param bs the desired block size in bytes.
324    * @return an Object encapsulating the session key.
325    * @exception IllegalArgumentException if the block size is not 16 (128-bit).
326    * @exception InvalidKeyException if the key data is invalid.
327    */
328   public Object makeKey(byte[] uk, int bs) throws InvalidKeyException
329   {
330     if (bs != DEFAULT_BLOCK_SIZE)
331       throw new IllegalArgumentException();
332     if (uk == null)
333       throw new InvalidKeyException("Empty key");
334     if (uk.length != 16)
335       throw new InvalidKeyException("Key is not 128-bit.");
336     int[][] Ke = new int[R + 1][2]; // encryption round keys
337     int[][] Kd = new int[R + 1][2]; // decryption round keys
338     int r, i;
339     int k20, k21, k10, k11, rc0, rc1, kr0, kr1;
340     i = 0;
341     k20 =  uk[i++]         << 24
342         | (uk[i++] & 0xFF) << 16
343         | (uk[i++] & 0xFF) << 8
344         | (uk[i++] & 0xFF);
345     k21 =  uk[i++]         << 24
346         | (uk[i++] & 0xFF) << 16
347         | (uk[i++] & 0xFF) << 8
348         | (uk[i++] & 0xFF);
349     k10 =  uk[i++]         << 24
350         | (uk[i++] & 0xFF) << 16
351         | (uk[i++] & 0xFF) << 8
352         | (uk[i++] & 0xFF);
353     k11 =  uk[i++]         << 24
354         | (uk[i++] & 0xFF) << 16
355         | (uk[i++] & 0xFF) << 8
356         | (uk[i++] & 0xFF);
357     for (r = 0, i = 0; r <= R; r++)
358       {
359         rc0 = rc[r][0];
360         rc1 = rc[r][1];
361         kr0 = T0[ k10 >>> 24        ]
362             ^ T1[(k10 >>> 16) & 0xFF]
363             ^ T2[(k10 >>>  8) & 0xFF]
364             ^ T3[ k10         & 0xFF]
365             ^ T4[(k11 >>> 24) & 0xFF]
366             ^ T5[(k11 >>> 16) & 0xFF]
367             ^ T6[(k11 >>>  8) & 0xFF]
368             ^ T7[ k11         & 0xFF] ^ rc0 ^ k20;
369         kr1 = T0[ k11 >>> 24        ]
370             ^ T1[(k11 >>> 16) & 0xFF]
371             ^ T2[(k11 >>>  8) & 0xFF]
372             ^ T3[ k11         & 0xFF]
373             ^ T4[(k10 >>> 24) & 0xFF]
374             ^ T5[(k10 >>> 16) & 0xFF]
375             ^ T6[(k10 >>>  8) & 0xFF]
376             ^ T7[ k10         & 0xFF] ^ rc1 ^ k21;
377         Ke[r][0] = kr0;
378         Ke[r][1] = kr1;
379         k20 = k10;
380         k21 = k11;
381         k10 = kr0;
382         k11 = kr1;
383         if (r == 0 || r == R)
384           {
385             Kd[R - r][0] = kr0;
386             Kd[R - r][1] = kr1;
387           }
388         else
389           {
390             Kd[R - r][0] = T0[S[ kr0 >>> 24        ] & 0xFF]
391                          ^ T1[S[(kr0 >>> 16) & 0xFF] & 0xFF]
392                          ^ T2[S[(kr0 >>>  8) & 0xFF] & 0xFF]
393                          ^ T3[S[ kr0         & 0xFF] & 0xFF]
394                          ^ T4[S[ kr1 >>> 24        ] & 0xFF]
395                          ^ T5[S[(kr1 >>> 16) & 0xFF] & 0xFF]
396                          ^ T6[S[(kr1 >>>  8) & 0xFF] & 0xFF]
397                          ^ T7[S[ kr1         & 0xFF] & 0xFF];
398             Kd[R - r][1] = T0[S[ kr1 >>> 24        ] & 0xFF]
399                          ^ T1[S[(kr1 >>> 16) & 0xFF] & 0xFF]
400                          ^ T2[S[(kr1 >>>  8) & 0xFF] & 0xFF]
401                          ^ T3[S[ kr1         & 0xFF] & 0xFF]
402                          ^ T4[S[ kr0 >>> 24        ] & 0xFF]
403                          ^ T5[S[(kr0 >>> 16) & 0xFF] & 0xFF]
404                          ^ T6[S[(kr0 >>>  8) & 0xFF] & 0xFF]
405                          ^ T7[S[ kr0         & 0xFF] & 0xFF];
406           }
407       }
408     if (Configuration.DEBUG)
409       {
410         log.fine("Key schedule");
411         log.fine("Ke[]:");
412         for (r = 0; r < R + 1; r++)
413           log.fine("#" + r + ": 0x" + Util.toString(Ke[r][0])
414                    + Util.toString(Ke[r][1]));
415         log.fine("Kd[]:");
416         for (r = 0; r < R + 1; r++)
417           log.fine("#" + r + ": 0x" + Util.toString(Kd[r][0])
418                    + Util.toString(Kd[r][1]));
419       }
420     return new Object[] { Ke, Kd };
421   }
422
423   public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
424   {
425     if (bs != DEFAULT_BLOCK_SIZE)
426       throw new IllegalArgumentException();
427     int[][] K = (int[][])((Object[]) k)[0];
428     khazad(in, i, out, j, K);
429   }
430
431   public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
432   {
433     if (bs != DEFAULT_BLOCK_SIZE)
434       throw new IllegalArgumentException();
435     int[][] K = (int[][])((Object[]) k)[1];
436     khazad(in, i, out, j, K);
437   }
438
439   public boolean selfTest()
440   {
441     if (valid == null)
442       {
443         boolean result = super.selfTest(); // do symmetry tests
444         if (result)
445           result = testKat(KAT_KEY, KAT_CT);
446         valid = Boolean.valueOf(result);
447       }
448     return valid.booleanValue();
449   }
450 }