2 Copyright (C) 2001, 2002, 2003, 2006, 2010 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 = Configuration.DEBUG ?
71 Logger.getLogger(Anubis.class.getName()) : null;
72 private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes
73 private static final int DEFAULT_KEY_SIZE = 16; // in bytes
74 private static final String Sd = // p. 25 [ANUBIS]
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];
99 * Anubis round constants. This is the largest possible considering that we
100 * always use R values, R = 8 + N, and 4 <= N <= 10.
102 private static final int[] rc = new int[18];
104 * KAT vector (from ecb_vk): I=83
105 * KEY=000000000000000000002000000000000000000000000000
106 * CT=2E66AB15773F3D32FB6C697509460DF4
108 private static final byte[] KAT_KEY =
109 Util.toBytesFromString("000000000000000000002000000000000000000000000000");
110 private static final byte[] KAT_CT =
111 Util.toBytesFromString("2E66AB15773F3D32FB6C697509460DF4");
112 /** caches the result of the correctness test, once executed. */
113 private static Boolean valid;
117 long time = System.currentTimeMillis();
118 int ROOT = 0x11d; // para. 2.1 [ANUBIS]
119 int i, s, s2, s4, s6, s8, t;
121 for (i = 0; i < 256; i++)
123 c = Sd.charAt(i >>> 1);
124 s = ((i & 1) == 0 ? c >>> 8 : c) & 0xFF;
136 T0[i] = s << 24 | s2 << 16 | s4 << 8 | s6;
137 T1[i] = s2 << 24 | s << 16 | s6 << 8 | s4;
138 T2[i] = s4 << 24 | s6 << 16 | s << 8 | s2;
139 T3[i] = s6 << 24 | s4 << 16 | s2 << 8 | s;
140 T4[i] = s << 24 | s << 16 | s << 8 | s;
141 T5[s] = s << 24 | s2 << 16 | s6 << 8 | s8;
143 // compute round constant
144 for (i = 0, s = 0; i < 18;)
145 rc[i++] = S[(s++) & 0xFF] << 24
146 | (S[(s++) & 0xFF] & 0xFF) << 16
147 | (S[(s++) & 0xFF] & 0xFF) << 8
148 | (S[(s++) & 0xFF] & 0xFF);
149 time = System.currentTimeMillis() - time;
150 if (Configuration.DEBUG)
152 log.fine("Static data");
155 for (i = 0; i < 64; i++)
157 sb = new StringBuilder();
158 for (t = 0; t < 4; t++)
159 sb.append("0x").append(Util.toString(T0[i * 4 + t])).append(", ");
160 log.fine(sb.toString());
163 for (i = 0; i < 64; i++)
165 sb = new StringBuilder();
166 for (t = 0; t < 4; t++)
167 sb.append("0x").append(Util.toString(T1[i * 4 + t])).append(", ");
168 log.fine(sb.toString());
171 for (i = 0; i < 64; i++)
173 sb = new StringBuilder();
174 for (t = 0; t < 4; t++)
175 sb.append("0x").append(Util.toString(T2[i * 4 + t])).append(", ");
176 log.fine(sb.toString());
179 for (i = 0; i < 64; i++)
181 sb = new StringBuilder();
182 for (t = 0; t < 4; t++)
183 sb.append("0x").append(Util.toString(T3[i * 4 + t])).append(", ");
184 log.fine(sb.toString());
187 for (i = 0; i < 64; i++)
189 sb = new StringBuilder();
190 for (t = 0; t < 4; t++)
191 sb.append("0x").append(Util.toString(T4[i * 4 + t])).append(", ");
192 log.fine(sb.toString());
195 for (i = 0; i < 64; i++)
197 sb = new StringBuilder();
198 for (t = 0; t < 4; t++)
199 sb.append("0x").append(Util.toString(T5[i * 4 + t])).append(", ");
200 log.fine(sb.toString());
203 for (i = 0; i < 18; i++)
204 log.fine("0x" + Util.toString(rc[i]));
205 log.fine("Total initialization time: " + time + " ms.");
209 /** Trivial 0-arguments constructor. */
212 super(Registry.ANUBIS_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE);
215 private static void anubis(byte[] in, int i, byte[] out, int j, int[][] K)
217 // extract encryption round keys
218 int R = K.length - 1;
220 // mu function + affine key addition
221 int a0 = (in[i++] << 24
222 | (in[i++] & 0xFF) << 16
223 | (in[i++] & 0xFF) << 8
224 | (in[i++] & 0xFF) ) ^ Ker[0];
225 int a1 = (in[i++] << 24
226 | (in[i++] & 0xFF) << 16
227 | (in[i++] & 0xFF) << 8
228 | (in[i++] & 0xFF) ) ^ Ker[1];
229 int a2 = (in[i++] << 24
230 | (in[i++] & 0xFF) << 16
231 | (in[i++] & 0xFF) << 8
232 | (in[i++] & 0xFF) ) ^ Ker[2];
233 int a3 = (in[i++] << 24
234 | (in[i++] & 0xFF) << 16
235 | (in[i++] & 0xFF) << 8
236 | (in[i] & 0xFF) ) ^ Ker[3];
239 for (int r = 1; r < R; r++)
245 ^ T3[ a3 >>> 24 ] ^ Ker[0];
246 b1 = T0[(a0 >>> 16) & 0xFF]
247 ^ T1[(a1 >>> 16) & 0xFF]
248 ^ T2[(a2 >>> 16) & 0xFF]
249 ^ T3[(a3 >>> 16) & 0xFF] ^ Ker[1];
250 b2 = T0[(a0 >>> 8) & 0xFF]
251 ^ T1[(a1 >>> 8) & 0xFF]
252 ^ T2[(a2 >>> 8) & 0xFF]
253 ^ T3[(a3 >>> 8) & 0xFF] ^ Ker[2];
257 ^ T3[ a3 & 0xFF] ^ Ker[3];
262 if (Configuration.DEBUG)
263 log.fine("T" + r + "=" + Util.toString(a0) + Util.toString(a1)
264 + Util.toString(a2) + Util.toString(a3));
266 // last round function
269 out[j++] = (byte)(S[ a0 >>> 24 ] ^ (tt >>> 24));
270 out[j++] = (byte)(S[ a1 >>> 24 ] ^ (tt >>> 16));
271 out[j++] = (byte)(S[ a2 >>> 24 ] ^ (tt >>> 8));
272 out[j++] = (byte)(S[ a3 >>> 24 ] ^ tt);
274 out[j++] = (byte)(S[(a0 >>> 16) & 0xFF] ^ (tt >>> 24));
275 out[j++] = (byte)(S[(a1 >>> 16) & 0xFF] ^ (tt >>> 16));
276 out[j++] = (byte)(S[(a2 >>> 16) & 0xFF] ^ (tt >>> 8));
277 out[j++] = (byte)(S[(a3 >>> 16) & 0xFF] ^ tt);
279 out[j++] = (byte)(S[(a0 >>> 8) & 0xFF] ^ (tt >>> 24));
280 out[j++] = (byte)(S[(a1 >>> 8) & 0xFF] ^ (tt >>> 16));
281 out[j++] = (byte)(S[(a2 >>> 8) & 0xFF] ^ (tt >>> 8));
282 out[j++] = (byte)(S[(a3 >>> 8) & 0xFF] ^ tt);
284 out[j++] = (byte)(S[ a0 & 0xFF] ^ (tt >>> 24));
285 out[j++] = (byte)(S[ a1 & 0xFF] ^ (tt >>> 16));
286 out[j++] = (byte)(S[ a2 & 0xFF] ^ (tt >>> 8));
287 out[j ] = (byte)(S[ a3 & 0xFF] ^ tt);
288 if (Configuration.DEBUG)
289 log.fine("T=" + Util.toString(out, j - 15, 16) + "\n");
292 public Object clone()
294 Anubis result = new Anubis();
295 result.currentBlockSize = this.currentBlockSize;
300 public Iterator blockSizes()
302 ArrayList al = new ArrayList();
303 al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE));
305 return Collections.unmodifiableList(al).iterator();
308 public Iterator keySizes()
310 ArrayList al = new ArrayList();
311 for (int n = 4; n < 10; n++)
312 al.add(Integer.valueOf(n * 32 / 8));
313 return Collections.unmodifiableList(al).iterator();
317 * Expands a user-supplied key material into a session key for a designated
320 * @param uk the 32N-bit user-supplied key material; 4 <= N <= 10.
321 * @param bs the desired block size in bytes.
322 * @return an Object encapsulating the session key.
323 * @exception IllegalArgumentException if the block size is not 16 (128-bit).
324 * @exception InvalidKeyException if the key data is invalid.
326 public Object makeKey(byte[] uk, int bs) throws InvalidKeyException
328 if (bs != DEFAULT_BLOCK_SIZE)
329 throw new IllegalArgumentException();
331 throw new InvalidKeyException("Empty key");
332 if ((uk.length % 4) != 0)
333 throw new InvalidKeyException("Key is not multiple of 32-bit.");
334 int N = uk.length / 4;
336 throw new InvalidKeyException("Key is not 32N; 4 <= N <= 10");
338 int[][] Ke = new int[R + 1][4]; // encryption round keys
339 int[][] Kd = new int[R + 1][4]; // decryption round keys
340 int[] tk = new int[N];
341 int[] kk = new int[N];
342 int r, i, j, k, k0, k1, k2, k3, tt;
344 for (r = 0, i = 0; r < N;)
345 tk[r++] = uk[i++] << 24
346 | (uk[i++] & 0xFF) << 16
347 | (uk[i++] & 0xFF) << 8
349 for (r = 0; r <= R; r++)
353 // psi = key evolution function
354 kk[0] = T0[(tk[0 ] >>> 24) ]
355 ^ T1[(tk[N - 1] >>> 16) & 0xFF]
356 ^ T2[(tk[N - 2] >>> 8) & 0xFF]
357 ^ T3[ tk[N - 3] & 0xFF];
358 kk[1] = T0[(tk[1 ] >>> 24) ]
359 ^ T1[(tk[0 ] >>> 16) & 0xFF]
360 ^ T2[(tk[N - 1] >>> 8) & 0xFF]
361 ^ T3[ tk[N - 2] & 0xFF];
362 kk[2] = T0[(tk[2 ] >>> 24) ]
363 ^ T1[(tk[1 ] >>> 16) & 0xFF]
364 ^ T2[(tk[0 ] >>> 8) & 0xFF]
365 ^ T3[ tk[N - 1] & 0xFF];
366 kk[3] = T0[(tk[3 ] >>> 24) ]
367 ^ T1[(tk[2 ] >>> 16) & 0xFF]
368 ^ T2[(tk[1 ] >>> 8) & 0xFF]
369 ^ T3[ tk[0 ] & 0xFF];
370 for (i = 4; i < N; i++)
371 kk[i] = T0[ tk[i ] >>> 24 ]
372 ^ T1[(tk[i - 1] >>> 16) & 0xFF]
373 ^ T2[(tk[i - 2] >>> 8) & 0xFF]
374 ^ T3[ tk[i - 3] & 0xFF];
375 // apply sigma (affine addition) to round constant
376 tk[0] = rc[r - 1] ^ kk[0];
377 for (i = 1; i < N; i++)
380 // phi = key selection function
382 k0 = T4[ tt >>> 24 ];
383 k1 = T4[(tt >>> 16) & 0xFF];
384 k2 = T4[(tt >>> 8) & 0xFF];
386 for (k = N - 2; k >= 0; k--)
390 ^ (T5[(k0 >>> 24) & 0xFF] & 0xFF000000)
391 ^ (T5[(k0 >>> 16) & 0xFF] & 0x00FF0000)
392 ^ (T5[(k0 >>> 8) & 0xFF] & 0x0000FF00)
393 ^ (T5 [k0 & 0xFF] & 0x000000FF);
394 k1 = T4[(tt >>> 16) & 0xFF]
395 ^ (T5[(k1 >>> 24) & 0xFF] & 0xFF000000)
396 ^ (T5[(k1 >>> 16) & 0xFF] & 0x00FF0000)
397 ^ (T5[(k1 >>> 8) & 0xFF] & 0x0000FF00)
398 ^ (T5[ k1 & 0xFF] & 0x000000FF);
399 k2 = T4[(tt >>> 8) & 0xFF]
400 ^ (T5[(k2 >>> 24) & 0xFF] & 0xFF000000)
401 ^ (T5[(k2 >>> 16) & 0xFF] & 0x00FF0000)
402 ^ (T5[(k2 >>> 8) & 0xFF] & 0x0000FF00)
403 ^ (T5[ k2 & 0xFF] & 0x000000FF);
405 ^ (T5[(k3 >>> 24) & 0xFF] & 0xFF000000)
406 ^ (T5[(k3 >>> 16) & 0xFF] & 0x00FF0000)
407 ^ (T5[(k3 >>> 8) & 0xFF] & 0x0000FF00)
408 ^ (T5[ k3 & 0xFF] & 0x000000FF);
414 if (r == 0 || r == R)
423 Kd[R - r][0] = T0[S[ k0 >>> 24 ] & 0xFF]
424 ^ T1[S[(k0 >>> 16) & 0xFF] & 0xFF]
425 ^ T2[S[(k0 >>> 8) & 0xFF] & 0xFF]
426 ^ T3[S[ k0 & 0xFF] & 0xFF];
427 Kd[R - r][1] = T0[S[ k1 >>> 24 ] & 0xFF]
428 ^ T1[S[(k1 >>> 16) & 0xFF] & 0xFF]
429 ^ T2[S[(k1 >>> 8) & 0xFF] & 0xFF]
430 ^ T3[S[ k1 & 0xFF] & 0xFF];
431 Kd[R - r][2] = T0[S[ k2 >>> 24 ] & 0xFF]
432 ^ T1[S[(k2 >>> 16) & 0xFF] & 0xFF]
433 ^ T2[S[(k2 >>> 8) & 0xFF] & 0xFF]
434 ^ T3[S[ k2 & 0xFF] & 0xFF];
435 Kd[R - r][3] = T0[S[ k3 >>> 24 ] & 0xFF]
436 ^ T1[S[(k3 >>> 16) & 0xFF] & 0xFF]
437 ^ T2[S[(k3 >>> 8) & 0xFF] & 0xFF]
438 ^ T3[S[ k3 & 0xFF] & 0xFF];
441 if (Configuration.DEBUG)
443 log.fine("Key schedule");
446 for (r = 0; r < R + 1; r++)
448 sb = new StringBuilder("#").append(r).append(": ");
449 for (j = 0; j < 4; j++)
450 sb.append("0x").append(Util.toString(Ke[r][j])).append(", ");
451 log.fine(sb.toString());
454 for (r = 0; r < R + 1; r++)
456 sb = new StringBuilder("#").append(r).append(": ");
457 for (j = 0; j < 4; j++)
458 sb.append("0x").append(Util.toString(Kd[r][j])).append(", ");
459 log.fine(sb.toString());
462 return new Object[] { Ke, Kd };
465 public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
467 if (bs != DEFAULT_BLOCK_SIZE)
468 throw new IllegalArgumentException();
469 int[][] K = (int[][])((Object[]) k)[0];
470 anubis(in, i, out, j, K);
473 public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
475 if (bs != DEFAULT_BLOCK_SIZE)
476 throw new IllegalArgumentException();
477 int[][] K = (int[][])((Object[]) k)[1];
478 anubis(in, i, out, j, K);
481 public boolean selfTest()
485 boolean result = super.selfTest(); // do symmetry tests
487 result = testKat(KAT_KEY, KAT_CT);
488 valid = Boolean.valueOf(result);
490 return valid.booleanValue();