2 Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
4 This file is a part of GNU Classpath.
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.
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.
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
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
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. */
39 package gnu.javax.crypto.cipher;
41 import gnu.java.security.Configuration;
42 import gnu.java.security.Registry;
43 import gnu.java.security.util.Util;
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;
52 * Anubis is a 128-bit block cipher that accepts a variable-length key. The
53 * cipher is a uniform substitution-permutation network whose inverse only
54 * differs from the forward operation in the key schedule. The design of both
55 * the round transformation and the key schedule is based upon the Wide Trail
56 * strategy and permits a wide variety of implementation trade-offs.
61 * href="http://planeta.terra.com.br/informatica/paulobarreto/AnubisPage.html">The
62 * ANUBIS 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>
67 public final class Anubis
70 private static final Logger log = Logger.getLogger(Anubis.class.getName());
71 private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes
72 private static final int DEFAULT_KEY_SIZE = 16; // in bytes
73 private static final String Sd = // p. 25 [ANUBIS]
74 "\uBA54\u2F74\u53D3\uD24D\u50AC\u8DBF\u7052\u9A4C"
75 + "\uEAD5\u97D1\u3351\u5BA6\uDE48\uA899\uDB32\uB7FC"
76 + "\uE39E\u919B\uE2BB\u416E\uA5CB\u6B95\uA1F3\uB102"
77 + "\uCCC4\u1D14\uC363\uDA5D\u5FDC\u7DCD\u7F5A\u6C5C"
78 + "\uF726\uFFED\uE89D\u6F8E\u19A0\uF089\u0F07\uAFFB"
79 + "\u0815\u0D04\u0164\uDF76\u79DD\u3D16\u3F37\u6D38"
80 + "\uB973\uE935\u5571\u7B8C\u7288\uF62A\u3E5E\u2746"
81 + "\u0C65\u6861\u03C1\u57D6\uD958\uD866\uD73A\uC83C"
82 + "\uFA96\uA798\uECB8\uC7AE\u694B\uABA9\u670A\u47F2"
83 + "\uB522\uE5EE\uBE2B\u8112\u831B\u0E23\uF545\u21CE"
84 + "\u492C\uF9E6\uB628\u1782\u1A8B\uFE8A\u09C9\u874E"
85 + "\uE12E\uE4E0\uEB90\uA41E\u8560\u0025\uF4F1\u940B"
86 + "\uE775\uEF34\u31D4\uD086\u7EAD\uFD29\u303B\u9FF8"
87 + "\uC613\u0605\uC511\u777C\u7A78\u361C\u3959\u1856"
88 + "\uB3B0\u2420\uB292\uA3C0\u4462\u10B4\u8443\u93C2"
89 + "\u4ABD\u8F2D\uBC9C\u6A40\uCFA2\u804F\u1FCA\uAA42";
90 private static final byte[] S = new byte[256];
91 private static final int[] T0 = new int[256];
92 private static final int[] T1 = new int[256];
93 private static final int[] T2 = new int[256];
94 private static final int[] T3 = new int[256];
95 private static final int[] T4 = new int[256];
96 private static final int[] T5 = new int[256];
98 * Anubis round constants. This is the largest possible considering that we
99 * always use R values, R = 8 + N, and 4 <= N <= 10.
101 private static final int[] rc = new int[18];
103 * KAT vector (from ecb_vk): I=83
104 * KEY=000000000000000000002000000000000000000000000000
105 * CT=2E66AB15773F3D32FB6C697509460DF4
107 private static final byte[] KAT_KEY =
108 Util.toBytesFromString("000000000000000000002000000000000000000000000000");
109 private static final byte[] KAT_CT =
110 Util.toBytesFromString("2E66AB15773F3D32FB6C697509460DF4");
111 /** caches the result of the correctness test, once executed. */
112 private static Boolean valid;
116 long time = System.currentTimeMillis();
117 int ROOT = 0x11d; // para. 2.1 [ANUBIS]
118 int i, s, s2, s4, s6, s8, t;
120 for (i = 0; i < 256; i++)
122 c = Sd.charAt(i >>> 1);
123 s = ((i & 1) == 0 ? c >>> 8 : c) & 0xFF;
135 T0[i] = s << 24 | s2 << 16 | s4 << 8 | s6;
136 T1[i] = s2 << 24 | s << 16 | s6 << 8 | s4;
137 T2[i] = s4 << 24 | s6 << 16 | s << 8 | s2;
138 T3[i] = s6 << 24 | s4 << 16 | s2 << 8 | s;
139 T4[i] = s << 24 | s << 16 | s << 8 | s;
140 T5[s] = s << 24 | s2 << 16 | s6 << 8 | s8;
142 // compute round constant
143 for (i = 0, s = 0; i < 18;)
144 rc[i++] = S[(s++) & 0xFF] << 24
145 | (S[(s++) & 0xFF] & 0xFF) << 16
146 | (S[(s++) & 0xFF] & 0xFF) << 8
147 | (S[(s++) & 0xFF] & 0xFF);
148 time = System.currentTimeMillis() - time;
149 if (Configuration.DEBUG)
151 log.fine("Static data");
154 for (i = 0; i < 64; i++)
156 sb = new StringBuilder();
157 for (t = 0; t < 4; t++)
158 sb.append("0x").append(Util.toString(T0[i * 4 + t])).append(", ");
159 log.fine(sb.toString());
162 for (i = 0; i < 64; i++)
164 sb = new StringBuilder();
165 for (t = 0; t < 4; t++)
166 sb.append("0x").append(Util.toString(T1[i * 4 + t])).append(", ");
167 log.fine(sb.toString());
170 for (i = 0; i < 64; i++)
172 sb = new StringBuilder();
173 for (t = 0; t < 4; t++)
174 sb.append("0x").append(Util.toString(T2[i * 4 + t])).append(", ");
175 log.fine(sb.toString());
178 for (i = 0; i < 64; i++)
180 sb = new StringBuilder();
181 for (t = 0; t < 4; t++)
182 sb.append("0x").append(Util.toString(T3[i * 4 + t])).append(", ");
183 log.fine(sb.toString());
186 for (i = 0; i < 64; i++)
188 sb = new StringBuilder();
189 for (t = 0; t < 4; t++)
190 sb.append("0x").append(Util.toString(T4[i * 4 + t])).append(", ");
191 log.fine(sb.toString());
194 for (i = 0; i < 64; i++)
196 sb = new StringBuilder();
197 for (t = 0; t < 4; t++)
198 sb.append("0x").append(Util.toString(T5[i * 4 + t])).append(", ");
199 log.fine(sb.toString());
202 for (i = 0; i < 18; i++)
203 log.fine("0x" + Util.toString(rc[i]));
204 log.fine("Total initialization time: " + time + " ms.");
208 /** Trivial 0-arguments constructor. */
211 super(Registry.ANUBIS_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE);
214 private static void anubis(byte[] in, int i, byte[] out, int j, int[][] K)
216 // extract encryption round keys
217 int R = K.length - 1;
219 // mu function + affine key addition
220 int a0 = (in[i++] << 24
221 | (in[i++] & 0xFF) << 16
222 | (in[i++] & 0xFF) << 8
223 | (in[i++] & 0xFF) ) ^ Ker[0];
224 int a1 = (in[i++] << 24
225 | (in[i++] & 0xFF) << 16
226 | (in[i++] & 0xFF) << 8
227 | (in[i++] & 0xFF) ) ^ Ker[1];
228 int a2 = (in[i++] << 24
229 | (in[i++] & 0xFF) << 16
230 | (in[i++] & 0xFF) << 8
231 | (in[i++] & 0xFF) ) ^ Ker[2];
232 int a3 = (in[i++] << 24
233 | (in[i++] & 0xFF) << 16
234 | (in[i++] & 0xFF) << 8
235 | (in[i] & 0xFF) ) ^ Ker[3];
238 for (int r = 1; r < R; r++)
244 ^ T3[ a3 >>> 24 ] ^ Ker[0];
245 b1 = T0[(a0 >>> 16) & 0xFF]
246 ^ T1[(a1 >>> 16) & 0xFF]
247 ^ T2[(a2 >>> 16) & 0xFF]
248 ^ T3[(a3 >>> 16) & 0xFF] ^ Ker[1];
249 b2 = T0[(a0 >>> 8) & 0xFF]
250 ^ T1[(a1 >>> 8) & 0xFF]
251 ^ T2[(a2 >>> 8) & 0xFF]
252 ^ T3[(a3 >>> 8) & 0xFF] ^ Ker[2];
256 ^ T3[ a3 & 0xFF] ^ Ker[3];
261 if (Configuration.DEBUG)
262 log.fine("T" + r + "=" + Util.toString(a0) + Util.toString(a1)
263 + Util.toString(a2) + Util.toString(a3));
265 // last round function
268 out[j++] = (byte)(S[ a0 >>> 24 ] ^ (tt >>> 24));
269 out[j++] = (byte)(S[ a1 >>> 24 ] ^ (tt >>> 16));
270 out[j++] = (byte)(S[ a2 >>> 24 ] ^ (tt >>> 8));
271 out[j++] = (byte)(S[ a3 >>> 24 ] ^ tt);
273 out[j++] = (byte)(S[(a0 >>> 16) & 0xFF] ^ (tt >>> 24));
274 out[j++] = (byte)(S[(a1 >>> 16) & 0xFF] ^ (tt >>> 16));
275 out[j++] = (byte)(S[(a2 >>> 16) & 0xFF] ^ (tt >>> 8));
276 out[j++] = (byte)(S[(a3 >>> 16) & 0xFF] ^ tt);
278 out[j++] = (byte)(S[(a0 >>> 8) & 0xFF] ^ (tt >>> 24));
279 out[j++] = (byte)(S[(a1 >>> 8) & 0xFF] ^ (tt >>> 16));
280 out[j++] = (byte)(S[(a2 >>> 8) & 0xFF] ^ (tt >>> 8));
281 out[j++] = (byte)(S[(a3 >>> 8) & 0xFF] ^ tt);
283 out[j++] = (byte)(S[ a0 & 0xFF] ^ (tt >>> 24));
284 out[j++] = (byte)(S[ a1 & 0xFF] ^ (tt >>> 16));
285 out[j++] = (byte)(S[ a2 & 0xFF] ^ (tt >>> 8));
286 out[j ] = (byte)(S[ a3 & 0xFF] ^ tt);
287 if (Configuration.DEBUG)
288 log.fine("T=" + Util.toString(out, j - 15, 16) + "\n");
291 public Object clone()
293 Anubis result = new Anubis();
294 result.currentBlockSize = this.currentBlockSize;
299 public Iterator blockSizes()
301 ArrayList al = new ArrayList();
302 al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE));
304 return Collections.unmodifiableList(al).iterator();
307 public Iterator keySizes()
309 ArrayList al = new ArrayList();
310 for (int n = 4; n < 10; n++)
311 al.add(Integer.valueOf(n * 32 / 8));
312 return Collections.unmodifiableList(al).iterator();
316 * Expands a user-supplied key material into a session key for a designated
319 * @param uk the 32N-bit user-supplied key material; 4 <= N <= 10.
320 * @param bs the desired block size in bytes.
321 * @return an Object encapsulating the session key.
322 * @exception IllegalArgumentException if the block size is not 16 (128-bit).
323 * @exception InvalidKeyException if the key data is invalid.
325 public Object makeKey(byte[] uk, int bs) throws InvalidKeyException
327 if (bs != DEFAULT_BLOCK_SIZE)
328 throw new IllegalArgumentException();
330 throw new InvalidKeyException("Empty key");
331 if ((uk.length % 4) != 0)
332 throw new InvalidKeyException("Key is not multiple of 32-bit.");
333 int N = uk.length / 4;
335 throw new InvalidKeyException("Key is not 32N; 4 <= N <= 10");
337 int[][] Ke = new int[R + 1][4]; // encryption round keys
338 int[][] Kd = new int[R + 1][4]; // decryption round keys
339 int[] tk = new int[N];
340 int[] kk = new int[N];
341 int r, i, j, k, k0, k1, k2, k3, tt;
343 for (r = 0, i = 0; r < N;)
344 tk[r++] = uk[i++] << 24
345 | (uk[i++] & 0xFF) << 16
346 | (uk[i++] & 0xFF) << 8
348 for (r = 0; r <= R; r++)
352 // psi = key evolution function
353 kk[0] = T0[(tk[0 ] >>> 24) ]
354 ^ T1[(tk[N - 1] >>> 16) & 0xFF]
355 ^ T2[(tk[N - 2] >>> 8) & 0xFF]
356 ^ T3[ tk[N - 3] & 0xFF];
357 kk[1] = T0[(tk[1 ] >>> 24) ]
358 ^ T1[(tk[0 ] >>> 16) & 0xFF]
359 ^ T2[(tk[N - 1] >>> 8) & 0xFF]
360 ^ T3[ tk[N - 2] & 0xFF];
361 kk[2] = T0[(tk[2 ] >>> 24) ]
362 ^ T1[(tk[1 ] >>> 16) & 0xFF]
363 ^ T2[(tk[0 ] >>> 8) & 0xFF]
364 ^ T3[ tk[N - 1] & 0xFF];
365 kk[3] = T0[(tk[3 ] >>> 24) ]
366 ^ T1[(tk[2 ] >>> 16) & 0xFF]
367 ^ T2[(tk[1 ] >>> 8) & 0xFF]
368 ^ T3[ tk[0 ] & 0xFF];
369 for (i = 4; i < N; i++)
370 kk[i] = T0[ tk[i ] >>> 24 ]
371 ^ T1[(tk[i - 1] >>> 16) & 0xFF]
372 ^ T2[(tk[i - 2] >>> 8) & 0xFF]
373 ^ T3[ tk[i - 3] & 0xFF];
374 // apply sigma (affine addition) to round constant
375 tk[0] = rc[r - 1] ^ kk[0];
376 for (i = 1; i < N; i++)
379 // phi = key selection function
381 k0 = T4[ tt >>> 24 ];
382 k1 = T4[(tt >>> 16) & 0xFF];
383 k2 = T4[(tt >>> 8) & 0xFF];
385 for (k = N - 2; k >= 0; k--)
389 ^ (T5[(k0 >>> 24) & 0xFF] & 0xFF000000)
390 ^ (T5[(k0 >>> 16) & 0xFF] & 0x00FF0000)
391 ^ (T5[(k0 >>> 8) & 0xFF] & 0x0000FF00)
392 ^ (T5 [k0 & 0xFF] & 0x000000FF);
393 k1 = T4[(tt >>> 16) & 0xFF]
394 ^ (T5[(k1 >>> 24) & 0xFF] & 0xFF000000)
395 ^ (T5[(k1 >>> 16) & 0xFF] & 0x00FF0000)
396 ^ (T5[(k1 >>> 8) & 0xFF] & 0x0000FF00)
397 ^ (T5[ k1 & 0xFF] & 0x000000FF);
398 k2 = T4[(tt >>> 8) & 0xFF]
399 ^ (T5[(k2 >>> 24) & 0xFF] & 0xFF000000)
400 ^ (T5[(k2 >>> 16) & 0xFF] & 0x00FF0000)
401 ^ (T5[(k2 >>> 8) & 0xFF] & 0x0000FF00)
402 ^ (T5[ k2 & 0xFF] & 0x000000FF);
404 ^ (T5[(k3 >>> 24) & 0xFF] & 0xFF000000)
405 ^ (T5[(k3 >>> 16) & 0xFF] & 0x00FF0000)
406 ^ (T5[(k3 >>> 8) & 0xFF] & 0x0000FF00)
407 ^ (T5[ k3 & 0xFF] & 0x000000FF);
413 if (r == 0 || r == R)
422 Kd[R - r][0] = T0[S[ k0 >>> 24 ] & 0xFF]
423 ^ T1[S[(k0 >>> 16) & 0xFF] & 0xFF]
424 ^ T2[S[(k0 >>> 8) & 0xFF] & 0xFF]
425 ^ T3[S[ k0 & 0xFF] & 0xFF];
426 Kd[R - r][1] = T0[S[ k1 >>> 24 ] & 0xFF]
427 ^ T1[S[(k1 >>> 16) & 0xFF] & 0xFF]
428 ^ T2[S[(k1 >>> 8) & 0xFF] & 0xFF]
429 ^ T3[S[ k1 & 0xFF] & 0xFF];
430 Kd[R - r][2] = T0[S[ k2 >>> 24 ] & 0xFF]
431 ^ T1[S[(k2 >>> 16) & 0xFF] & 0xFF]
432 ^ T2[S[(k2 >>> 8) & 0xFF] & 0xFF]
433 ^ T3[S[ k2 & 0xFF] & 0xFF];
434 Kd[R - r][3] = T0[S[ k3 >>> 24 ] & 0xFF]
435 ^ T1[S[(k3 >>> 16) & 0xFF] & 0xFF]
436 ^ T2[S[(k3 >>> 8) & 0xFF] & 0xFF]
437 ^ T3[S[ k3 & 0xFF] & 0xFF];
440 if (Configuration.DEBUG)
442 log.fine("Key schedule");
445 for (r = 0; r < R + 1; r++)
447 sb = new StringBuilder("#").append(r).append(": ");
448 for (j = 0; j < 4; j++)
449 sb.append("0x").append(Util.toString(Ke[r][j])).append(", ");
450 log.fine(sb.toString());
453 for (r = 0; r < R + 1; r++)
455 sb = new StringBuilder("#").append(r).append(": ");
456 for (j = 0; j < 4; j++)
457 sb.append("0x").append(Util.toString(Kd[r][j])).append(", ");
458 log.fine(sb.toString());
461 return new Object[] { Ke, Kd };
464 public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
466 if (bs != DEFAULT_BLOCK_SIZE)
467 throw new IllegalArgumentException();
468 int[][] K = (int[][])((Object[]) k)[0];
469 anubis(in, i, out, j, K);
472 public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
474 if (bs != DEFAULT_BLOCK_SIZE)
475 throw new IllegalArgumentException();
476 int[][] K = (int[][])((Object[]) k)[1];
477 anubis(in, i, out, j, K);
480 public boolean selfTest()
484 boolean result = super.selfTest(); // do symmetry tests
486 result = testKat(KAT_KEY, KAT_CT);
487 valid = Boolean.valueOf(result);
489 return valid.booleanValue();