1 /* Rijndael.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  * Rijndael --pronounced Reindaal-- is the AES. It is a variable block-size
53  * (128-, 192- and 256-bit), variable key-size (128-, 192- and 256-bit)
54  * symmetric key block cipher.
55  * <p>
56  * References:
57  * <ol>
58  * <li><a href="http://www.esat.kuleuven.ac.be/~rijmen/rijndael/">The Rijndael
59  * Block Cipher - AES Proposal</a>.<br>
60  * <a href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a> and
61  * <a href="mailto:daemen.j@protonworld.com">Joan Daemen</a>.</li>
62  * </ol>
63  */
64 public final class Rijndael
65     extends BaseCipher
66 {
67   private static final Logger log = Configuration.DEBUG ?
68                         Logger.getLogger(Rijndael.class.getName()) : null;
69   private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes
70   private static final int DEFAULT_KEY_SIZE = 16; // in bytes
71   private static final String SS =
72       "\u637C\u777B\uF26B\u6FC5\u3001\u672B\uFED7\uAB76"
73     + "\uCA82\uC97D\uFA59\u47F0\uADD4\uA2AF\u9CA4\u72C0"
74     + "\uB7FD\u9326\u363F\uF7CC\u34A5\uE5F1\u71D8\u3115"
75     + "\u04C7\u23C3\u1896\u059A\u0712\u80E2\uEB27\uB275"
76     + "\u0983\u2C1A\u1B6E\u5AA0\u523B\uD6B3\u29E3\u2F84"
77     + "\u53D1\u00ED\u20FC\uB15B\u6ACB\uBE39\u4A4C\u58CF"
78     + "\uD0EF\uAAFB\u434D\u3385\u45F9\u027F\u503C\u9FA8"
79     + "\u51A3\u408F\u929D\u38F5\uBCB6\uDA21\u10FF\uF3D2"
80     + "\uCD0C\u13EC\u5F97\u4417\uC4A7\u7E3D\u645D\u1973"
81     + "\u6081\u4FDC\u222A\u9088\u46EE\uB814\uDE5E\u0BDB"
82     + "\uE032\u3A0A\u4906\u245C\uC2D3\uAC62\u9195\uE479"
83     + "\uE7C8\u376D\u8DD5\u4EA9\u6C56\uF4EA\u657A\uAE08"
84     + "\uBA78\u252E\u1CA6\uB4C6\uE8DD\u741F\u4BBD\u8B8A"
85     + "\u703E\uB566\u4803\uF60E\u6135\u57B9\u86C1\u1D9E"
86     + "\uE1F8\u9811\u69D9\u8E94\u9B1E\u87E9\uCE55\u28DF"
87     + "\u8CA1\u890D\uBFE6\u4268\u4199\u2D0F\uB054\uBB16";
88   private static final byte[] S = new byte[256];
89   private static final byte[] Si = new byte[256];
90   private static final int[] T1 = new int[256];
91   private static final int[] T2 = new int[256];
92   private static final int[] T3 = new int[256];
93   private static final int[] T4 = new int[256];
94   private static final int[] T5 = new int[256];
95   private static final int[] T6 = new int[256];
96   private static final int[] T7 = new int[256];
97   private static final int[] T8 = new int[256];
98   private static final int[] U1 = new int[256];
99   private static final int[] U2 = new int[256];
100   private static final int[] U3 = new int[256];
101   private static final int[] U4 = new int[256];
102   private static final byte[] rcon = new byte[30];
103   private static final int[][][] shifts = new int[][][] {
104       { { 0, 0 }, { 1, 3 }, { 2, 2 }, { 3, 1 } },
105       { { 0, 0 }, { 1, 5 }, { 2, 4 }, { 3, 3 } },
106       { { 0, 0 }, { 1, 7 }, { 3, 5 }, { 4, 4 } } };
107   /**
108    * KAT vector (from ecb_vk): I=96
109    * KEY=0000000000000000000000010000000000000000000000000000000000000000
110    * CT=E44429474D6FC3084EB2A6B8B46AF754
111    */
112   private static final byte[] KAT_KEY = Util.toBytesFromString(
113       "0000000000000000000000010000000000000000000000000000000000000000");
114   private static final byte[] KAT_CT = Util.toBytesFromString(
115       "E44429474D6FC3084EB2A6B8B46AF754");
116   /** caches the result of the correctness test, once executed. */
117   private static Boolean valid;
118 
119   static
120     {
121       long time = System.currentTimeMillis();
122       int ROOT = 0x11B;
123       int i, j = 0;
124       // S-box, inverse S-box, T-boxes, U-boxes
125       int s, s2, s3, i2, i4, i8, i9, ib, id, ie, t;
126       char c;
127       for (i = 0; i < 256; i++)
128         {
129           c = SS.charAt(i >>> 1);
130           S[i] = (byte)(((i & 1) == 0) ? c >>> 8 : c & 0xFF);
131           s = S[i] & 0xFF;
132           Si[s] = (byte) i;
133           s2 = s << 1;
134           if (s2 >= 0x100)
135             s2 ^= ROOT;
136           s3 = s2 ^ s;
137           i2 = i << 1;
138           if (i2 >= 0x100)
139             i2 ^= ROOT;
140           i4 = i2 << 1;
141           if (i4 >= 0x100)
142             i4 ^= ROOT;
143           i8 = i4 << 1;
144           if (i8 >= 0x100)
145             i8 ^= ROOT;
146           i9 = i8 ^ i;
147           ib = i9 ^ i2;
148           id = i9 ^ i4;
149           ie = i8 ^ i4 ^ i2;
150           T1[i] = t = (s2 << 24) | (s << 16) | (s << 8) | s3;
151           T2[i] = (t >>>  8) | (t << 24);
152           T3[i] = (t >>> 16) | (t << 16);
153           T4[i] = (t >>> 24) | (t <<  8);
154           T5[s] = U1[i] = t = (ie << 24) | (i9 << 16) | (id << 8) | ib;
155           T6[s] = U2[i] = (t >>>  8) | (t << 24);
156           T7[s] = U3[i] = (t >>> 16) | (t << 16);
157           T8[s] = U4[i] = (t >>> 24) | (t <<  8);
158         }
159       // round constants
160       int r = 1;
161       rcon[0] = 1;
162       for (i = 1; i < 30; i++)
163         {
164           r <<= 1;
165           if (r >= 0x100)
166             r ^= ROOT;
167           rcon[i] = (byte) r;
168         }
169       time = System.currentTimeMillis() - time;
170       if (Configuration.DEBUG)
171         {
172           log.fine("Static Data");
173           log.fine("S[]:");
174           StringBuilder sb;
175           for (i = 0; i < 16; i++)
176             {
177               sb = new StringBuilder();
178               for (j = 0; j < 16; j++)
179                 sb.append("0x").append(Util.toString(S[i * 16 + j])).append(", ");
sb.toString()180               log.fine(sb.toString());
181             }
182           log.fine("Si[]:");
183           for (i = 0; i < 16; i++)
184             {
185               sb = new StringBuilder();
186               for (j = 0; j < 16; j++)
187                 sb.append("0x").append(Util.toString(Si[i * 16 + j])).append(", ");
sb.toString()188               log.fine(sb.toString());
189             }
190 
191           log.fine("T1[]:");
192           for (i = 0; i < 64; i++)
193             {
194               sb = new StringBuilder();
195               for (j = 0; j < 4; j++)
196                 sb.append("0x").append(Util.toString(T1[i * 4 + j])).append(", ");
sb.toString()197               log.fine(sb.toString());
198             }
199           log.fine("T2[]:");
200           for (i = 0; i < 64; i++)
201             {
202               sb = new StringBuilder();
203               for (j = 0; j < 4; j++)
204                 sb.append("0x").append(Util.toString(T2[i * 4 + j])).append(", ");
sb.toString()205               log.fine(sb.toString());
206             }
207           log.fine("T3[]:");
208           for (i = 0; i < 64; i++)
209             {
210               sb = new StringBuilder();
211               for (j = 0; j < 4; j++)
212                 sb.append("0x").append(Util.toString(T3[i * 4 + j])).append(", ");
sb.toString()213               log.fine(sb.toString());
214             }
215           log.fine("T4[]:");
216           for (i = 0; i < 64; i++)
217             {
218               sb = new StringBuilder();
219               for (j = 0; j < 4; j++)
220                 sb.append("0x").append(Util.toString(T4[i * 4 + j])).append(", ");
sb.toString()221               log.fine(sb.toString());
222             }
223           log.fine("T5[]:");
224           for (i = 0; i < 64; i++)
225             {
226               sb = new StringBuilder();
227               for (j = 0; j < 4; j++)
228                 sb.append("0x").append(Util.toString(T5[i * 4 + j])).append(", ");
sb.toString()229               log.fine(sb.toString());
230             }
231           log.fine("T6[]:");
232           for (i = 0; i < 64; i++)
233             {
234               sb = new StringBuilder();
235               for (j = 0; j < 4; j++)
236                 sb.append("0x").append(Util.toString(T6[i * 4 + j])).append(", ");
sb.toString()237               log.fine(sb.toString());
238             }
239           log.fine("T7[]:");
240           for (i = 0; i < 64; i++)
241             {
242               sb = new StringBuilder();
243               for (j = 0; j < 4; j++)
244                 sb.append("0x").append(Util.toString(T7[i * 4 + j])).append(", ");
sb.toString()245               log.fine(sb.toString());
246             }
247           log.fine("T8[]:");
248           for (i = 0; i < 64; i++)
249             {
250               sb = new StringBuilder();
251               for (j = 0; j < 4; j++)
252                 sb.append("0x").append(Util.toString(T8[i * 4 + j])).append(", ");
sb.toString()253               log.fine(sb.toString());
254             }
255 
256           log.fine("U1[]:");
257           for (i = 0; i < 64; i++)
258             {
259               sb = new StringBuilder();
260               for (j = 0; j < 4; j++)
261                 sb.append("0x").append(Util.toString(U1[i * 4 + j])).append(", ");
sb.toString()262               log.fine(sb.toString());
263             }
264           log.fine("U2[]:");
265           for (i = 0; i < 64; i++)
266             {
267               sb = new StringBuilder();
268               for (j = 0; j < 4; j++)
269                 sb.append("0x").append(Util.toString(U2[i * 4 + j])).append(", ");
sb.toString()270               log.fine(sb.toString());
271             }
272           log.fine("U3[]:");
273           for (i = 0; i < 64; i++)
274             {
275               sb = new StringBuilder();
276               for (j = 0; j < 4; j++)
277                 sb.append("0x").append(Util.toString(U3[i * 4 + j])).append(", ");
sb.toString()278               log.fine(sb.toString());
279             }
280           log.fine("U4[]:");
281           for (i = 0; i < 64; i++)
282             {
283               sb = new StringBuilder();
284               for (j = 0; j < 4; j++)
285                 sb.append("0x").append(Util.toString(U4[i * 4 + j])).append(", ");
sb.toString()286               log.fine(sb.toString());
287             }
288 
289           log.fine("rcon[]:");
290           for (i = 0; i < 5; i++)
291             {
292               sb = new StringBuilder();
293               for (j = 0; j < 6; j++)
294                 sb.append("0x").append(Util.toString(rcon[i * 6 + j])).append(", ");
sb.toString()295               log.fine(sb.toString());
296             }
297           log.fine("Total initialization time: " + time + " ms.");
298         }
299     }
300 
301   /** Trivial 0-arguments constructor. */
Rijndael()302   public Rijndael()
303   {
304     super(Registry.RIJNDAEL_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE);
305   }
306 
307   /**
308    * Returns the number of rounds for a given Rijndael's key and block sizes.
309    *
310    * @param ks the size of the user key material in bytes.
311    * @param bs the desired block size in bytes.
312    * @return the number of rounds for a given Rijndael's key and block sizes.
313    */
getRounds(int ks, int bs)314   public static int getRounds(int ks, int bs)
315   {
316     switch (ks)
317       {
318       case 16:
319         return bs == 16 ? 10 : (bs == 24 ? 12 : 14);
320       case 24:
321         return bs != 32 ? 12 : 14;
322       default: // 32 bytes = 256 bits
323         return 14;
324       }
325   }
326 
rijndaelEncrypt(byte[] in, int inOffset, byte[] out, int outOffset, Object sessionKey, int bs)327   private static void rijndaelEncrypt(byte[] in, int inOffset, byte[] out,
328                                       int outOffset, Object sessionKey, int bs)
329   {
330     Object[] sKey = (Object[]) sessionKey; // extract encryption round keys
331     int[][] Ke = (int[][]) sKey[0];
332     int BC = bs / 4;
333     int ROUNDS = Ke.length - 1;
334     int SC = BC == 4 ? 0 : (BC == 6 ? 1 : 2);
335     int s1 = shifts[SC][1][0];
336     int s2 = shifts[SC][2][0];
337     int s3 = shifts[SC][3][0];
338     int[] a = new int[BC];
339     int[] t = new int[BC]; // temporary work array
340     int i, tt;
341     for (i = 0; i < BC; i++) // plaintext to ints + key
342       t[i] = (in[inOffset++]         << 24
343            | (in[inOffset++] & 0xFF) << 16
344            | (in[inOffset++] & 0xFF) <<  8
345            | (in[inOffset++] & 0xFF)      ) ^ Ke[0][i];
346     for (int r = 1; r < ROUNDS; r++) // apply round transforms
347       {
348         for (i = 0; i < BC; i++)
349           a[i] = (T1[(t[ i           ] >>> 24)       ]
350                 ^ T2[(t[(i + s1) % BC] >>> 16) & 0xFF]
351                 ^ T3[(t[(i + s2) % BC] >>>  8) & 0xFF]
352                 ^ T4[ t[(i + s3) % BC]         & 0xFF]) ^ Ke[r][i];
353         System.arraycopy(a, 0, t, 0, BC);
354         if (Configuration.DEBUG)
355           log.fine("CT" + r + "=" + Util.toString(t));
356       }
357     for (i = 0; i < BC; i++) // last round is special
358       {
359         tt = Ke[ROUNDS][i];
360         out[outOffset++] = (byte)(S[(t[ i           ] >>> 24)       ] ^ (tt >>> 24));
361         out[outOffset++] = (byte)(S[(t[(i + s1) % BC] >>> 16) & 0xFF] ^ (tt >>> 16));
362         out[outOffset++] = (byte)(S[(t[(i + s2) % BC] >>>  8) & 0xFF] ^ (tt >>>  8));
363         out[outOffset++] = (byte)(S[ t[(i + s3) % BC]         & 0xFF] ^  tt        );
364       }
365     if (Configuration.DEBUG)
366       log.fine("CT=" + Util.toString(out, outOffset - bs, bs));
367   }
368 
rijndaelDecrypt(byte[] in, int inOffset, byte[] out, int outOffset, Object sessionKey, int bs)369   private static void rijndaelDecrypt(byte[] in, int inOffset, byte[] out,
370                                       int outOffset, Object sessionKey, int bs)
371   {
372     Object[] sKey = (Object[]) sessionKey; // extract decryption round keys
373     int[][] Kd = (int[][]) sKey[1];
374     int BC = bs / 4;
375     int ROUNDS = Kd.length - 1;
376     int SC = BC == 4 ? 0 : (BC == 6 ? 1 : 2);
377     int s1 = shifts[SC][1][1];
378     int s2 = shifts[SC][2][1];
379     int s3 = shifts[SC][3][1];
380     int[] a = new int[BC];
381     int[] t = new int[BC]; // temporary work array
382     int i, tt;
383     for (i = 0; i < BC; i++) // ciphertext to ints + key
384       t[i] = (in[inOffset++]         << 24
385            | (in[inOffset++] & 0xFF) << 16
386            | (in[inOffset++] & 0xFF) <<  8
387            | (in[inOffset++] & 0xFF)      ) ^ Kd[0][i];
388     for (int r = 1; r < ROUNDS; r++) // apply round transforms
389       {
390         for (i = 0; i < BC; i++)
391           a[i] = (T5[(t[ i           ] >>> 24)       ]
392                 ^ T6[(t[(i + s1) % BC] >>> 16) & 0xFF]
393                 ^ T7[(t[(i + s2) % BC] >>>  8) & 0xFF]
394                 ^ T8[ t[(i + s3) % BC]         & 0xFF]) ^ Kd[r][i];
395         System.arraycopy(a, 0, t, 0, BC);
396         if (Configuration.DEBUG)
397           log.fine("PT" + r + "=" + Util.toString(t));
398       }
399     for (i = 0; i < BC; i++) // last round is special
400       {
401         tt = Kd[ROUNDS][i];
402         out[outOffset++] = (byte)(Si[(t[ i           ] >>> 24)       ] ^ (tt >>> 24));
403         out[outOffset++] = (byte)(Si[(t[(i + s1) % BC] >>> 16) & 0xFF] ^ (tt >>> 16));
404         out[outOffset++] = (byte)(Si[(t[(i + s2) % BC] >>>  8) & 0xFF] ^ (tt >>>  8));
405         out[outOffset++] = (byte)(Si[ t[(i + s3) % BC]         & 0xFF] ^  tt        );
406       }
407     if (Configuration.DEBUG)
408       log.fine("PT=" + Util.toString(out, outOffset - bs, bs));
409   }
410 
aesEncrypt(byte[] in, int i, byte[] out, int j, Object key)411   private static void aesEncrypt(byte[] in, int i, byte[] out, int j, Object key)
412   {
413     int[][] Ke = (int[][])((Object[]) key)[0]; // extract encryption round keys
414     int ROUNDS = Ke.length - 1;
415     int[] Ker = Ke[0];
416     // plaintext to ints + key
417     int t0 = (in[i++]         << 24
418            | (in[i++] & 0xFF) << 16
419            | (in[i++] & 0xFF) <<  8
420            | (in[i++] & 0xFF)      ) ^ Ker[0];
421     int t1 = (in[i++]         << 24
422            | (in[i++] & 0xFF) << 16
423            | (in[i++] & 0xFF) <<  8
424            | (in[i++] & 0xFF)      ) ^ Ker[1];
425     int t2 = (in[i++]         << 24
426            | (in[i++] & 0xFF) << 16
427            | (in[i++] & 0xFF) <<  8
428            | (in[i++] & 0xFF)      ) ^ Ker[2];
429     int t3 = (in[i++]         << 24
430            | (in[i++] & 0xFF) << 16
431            | (in[i++] & 0xFF) <<  8
432            | (in[i++] & 0xFF)      ) ^ Ker[3];
433     int a0, a1, a2, a3;
434     for (int r = 1; r < ROUNDS; r++) // apply round transforms
435       {
436         Ker = Ke[r];
437         a0 = (T1[(t0 >>> 24)       ]
438             ^ T2[(t1 >>> 16) & 0xFF]
439             ^ T3[(t2 >>>  8) & 0xFF]
440             ^ T4[ t3         & 0xFF]) ^ Ker[0];
441         a1 = (T1[(t1 >>> 24)       ]
442             ^ T2[(t2 >>> 16) & 0xFF]
443             ^ T3[(t3 >>>  8) & 0xFF]
444             ^ T4[ t0         & 0xFF]) ^ Ker[1];
445         a2 = (T1[(t2 >>> 24)       ]
446             ^ T2[(t3 >>> 16) & 0xFF]
447             ^ T3[(t0 >>>  8) & 0xFF]
448             ^ T4[ t1         & 0xFF]) ^ Ker[2];
449         a3 = (T1[(t3 >>> 24)       ]
450             ^ T2[(t0 >>> 16) & 0xFF]
451             ^ T3[(t1 >>>  8) & 0xFF]
452             ^ T4[ t2         & 0xFF]) ^ Ker[3];
453         t0 = a0;
454         t1 = a1;
455         t2 = a2;
456         t3 = a3;
457         if (Configuration.DEBUG)
458           log.fine("CT" + r + "=" + Util.toString(t0) + Util.toString(t1)
459                    + Util.toString(t2) + Util.toString(t3));
460       }
461     // last round is special
462     Ker = Ke[ROUNDS];
463     int tt = Ker[0];
464     out[j++] = (byte)(S[(t0 >>> 24)       ] ^ (tt >>> 24));
465     out[j++] = (byte)(S[(t1 >>> 16) & 0xFF] ^ (tt >>> 16));
466     out[j++] = (byte)(S[(t2 >>>  8) & 0xFF] ^ (tt >>>  8));
467     out[j++] = (byte)(S[ t3         & 0xFF] ^  tt        );
468     tt = Ker[1];
469     out[j++] = (byte)(S[(t1 >>> 24)       ] ^ (tt >>> 24));
470     out[j++] = (byte)(S[(t2 >>> 16) & 0xFF] ^ (tt >>> 16));
471     out[j++] = (byte)(S[(t3 >>>  8) & 0xFF] ^ (tt >>>  8));
472     out[j++] = (byte)(S[ t0         & 0xFF] ^  tt        );
473     tt = Ker[2];
474     out[j++] = (byte)(S[(t2 >>> 24)       ] ^ (tt >>> 24));
475     out[j++] = (byte)(S[(t3 >>> 16) & 0xFF] ^ (tt >>> 16));
476     out[j++] = (byte)(S[(t0 >>>  8) & 0xFF] ^ (tt >>>  8));
477     out[j++] = (byte)(S[ t1         & 0xFF] ^  tt        );
478     tt = Ker[3];
479     out[j++] = (byte)(S[(t3 >>> 24)       ] ^ (tt >>> 24));
480     out[j++] = (byte)(S[(t0 >>> 16) & 0xFF] ^ (tt >>> 16));
481     out[j++] = (byte)(S[(t1 >>>  8) & 0xFF] ^ (tt >>>  8));
482     out[j++] = (byte)(S[ t2         & 0xFF] ^  tt        );
483     if (Configuration.DEBUG)
484       log.fine("CT=" + Util.toString(out, j - 16, 16));
485   }
486 
aesDecrypt(byte[] in, int i, byte[] out, int j, Object key)487   private static void aesDecrypt(byte[] in, int i, byte[] out, int j, Object key)
488   {
489     int[][] Kd = (int[][])((Object[]) key)[1]; // extract decryption round keys
490     int ROUNDS = Kd.length - 1;
491     int[] Kdr = Kd[0];
492     // ciphertext to ints + key
493     int t0 = (in[i++]         << 24
494            | (in[i++] & 0xFF) << 16
495            | (in[i++] & 0xFF) <<  8
496            | (in[i++] & 0xFF)      ) ^ Kdr[0];
497     int t1 = (in[i++]         << 24
498            | (in[i++] & 0xFF) << 16
499            | (in[i++] & 0xFF) <<  8
500            | (in[i++] & 0xFF)      ) ^ Kdr[1];
501     int t2 = (in[i++]         << 24
502            | (in[i++] & 0xFF) << 16
503            | (in[i++] & 0xFF) <<  8
504            | (in[i++] & 0xFF)      ) ^ Kdr[2];
505     int t3 = (in[i++]         << 24
506            | (in[i++] & 0xFF) << 16
507            | (in[i++] & 0xFF) <<  8
508            | (in[i++] & 0xFF)      ) ^ Kdr[3];
509 
510     int a0, a1, a2, a3;
511     for (int r = 1; r < ROUNDS; r++) // apply round transforms
512       {
513         Kdr = Kd[r];
514         a0 = (T5[(t0 >>> 24)       ]
515             ^ T6[(t3 >>> 16) & 0xFF]
516             ^ T7[(t2 >>>  8) & 0xFF]
517             ^ T8[ t1         & 0xFF]) ^ Kdr[0];
518         a1 = (T5[(t1 >>> 24)       ]
519             ^ T6[(t0 >>> 16) & 0xFF]
520             ^ T7[(t3 >>>  8) & 0xFF]
521             ^ T8[ t2         & 0xFF]) ^ Kdr[1];
522         a2 = (T5[(t2 >>> 24)       ]
523             ^ T6[(t1 >>> 16) & 0xFF]
524             ^ T7[(t0 >>>  8) & 0xFF]
525             ^ T8[ t3         & 0xFF]) ^ Kdr[2];
526         a3 = (T5[(t3 >>> 24)       ]
527             ^ T6[(t2 >>> 16) & 0xFF]
528             ^ T7[(t1 >>>  8) & 0xFF]
529             ^ T8[ t0         & 0xFF]) ^ Kdr[3];
530         t0 = a0;
531         t1 = a1;
532         t2 = a2;
533         t3 = a3;
534         if (Configuration.DEBUG)
535           log.fine("PT" + r + "=" + Util.toString(t0) + Util.toString(t1)
536                    + Util.toString(t2) + Util.toString(t3));
537       }
538     // last round is special
539     Kdr = Kd[ROUNDS];
540     int tt = Kdr[0];
541     out[j++] = (byte)(Si[(t0 >>> 24)       ] ^ (tt >>> 24));
542     out[j++] = (byte)(Si[(t3 >>> 16) & 0xFF] ^ (tt >>> 16));
543     out[j++] = (byte)(Si[(t2 >>>  8) & 0xFF] ^ (tt >>>  8));
544     out[j++] = (byte)(Si[ t1         & 0xFF] ^  tt        );
545     tt = Kdr[1];
546     out[j++] = (byte)(Si[(t1 >>> 24)       ] ^ (tt >>> 24));
547     out[j++] = (byte)(Si[(t0 >>> 16) & 0xFF] ^ (tt >>> 16));
548     out[j++] = (byte)(Si[(t3 >>>  8) & 0xFF] ^ (tt >>>  8));
549     out[j++] = (byte)(Si[ t2         & 0xFF] ^  tt        );
550     tt = Kdr[2];
551     out[j++] = (byte)(Si[(t2 >>> 24)       ] ^ (tt >>> 24));
552     out[j++] = (byte)(Si[(t1 >>> 16) & 0xFF] ^ (tt >>> 16));
553     out[j++] = (byte)(Si[(t0 >>>  8) & 0xFF] ^ (tt >>>  8));
554     out[j++] = (byte)(Si[ t3         & 0xFF] ^  tt        );
555     tt = Kdr[3];
556     out[j++] = (byte)(Si[(t3 >>> 24)       ] ^ (tt >>> 24));
557     out[j++] = (byte)(Si[(t2 >>> 16) & 0xFF] ^ (tt >>> 16));
558     out[j++] = (byte)(Si[(t1 >>>  8) & 0xFF] ^ (tt >>>  8));
559     out[j++] = (byte)(Si[ t0         & 0xFF] ^  tt        );
560     if (Configuration.DEBUG)
561       log.fine("PT=" + Util.toString(out, j - 16, 16));
562   }
563 
clone()564   public Object clone()
565   {
566     Rijndael result = new Rijndael();
567     result.currentBlockSize = this.currentBlockSize;
568 
569     return result;
570   }
571 
blockSizes()572   public Iterator blockSizes()
573   {
574     ArrayList al = new ArrayList();
575     al.add(Integer.valueOf(128 / 8));
576     al.add(Integer.valueOf(192 / 8));
577     al.add(Integer.valueOf(256 / 8));
578 
579     return Collections.unmodifiableList(al).iterator();
580   }
581 
keySizes()582   public Iterator keySizes()
583   {
584     ArrayList al = new ArrayList();
585     al.add(Integer.valueOf(128 / 8));
586     al.add(Integer.valueOf(192 / 8));
587     al.add(Integer.valueOf(256 / 8));
588 
589     return Collections.unmodifiableList(al).iterator();
590   }
591 
592   /**
593    * Expands a user-supplied key material into a session key for a designated
594    * <i>block size</i>.
595    *
596    * @param k the 128/192/256-bit user-key to use.
597    * @param bs the block size in bytes of this Rijndael.
598    * @return an Object encapsulating the session key.
599    * @exception IllegalArgumentException if the block size is not 16, 24 or 32.
600    * @exception InvalidKeyException if the key data is invalid.
601    */
makeKey(byte[] k, int bs)602   public Object makeKey(byte[] k, int bs) throws InvalidKeyException
603   {
604     if (k == null)
605       throw new InvalidKeyException("Empty key");
606     if (! (k.length == 16 || k.length == 24 || k.length == 32))
607       throw new InvalidKeyException("Incorrect key length");
608     if (! (bs == 16 || bs == 24 || bs == 32))
609       throw new IllegalArgumentException();
610     int ROUNDS = getRounds(k.length, bs);
611     int BC = bs / 4;
612     int[][] Ke = new int[ROUNDS + 1][BC]; // encryption round keys
613     int[][] Kd = new int[ROUNDS + 1][BC]; // decryption round keys
614     int ROUND_KEY_COUNT = (ROUNDS + 1) * BC;
615     int KC = k.length / 4;
616     int[] tk = new int[KC];
617     int i, j;
618     // copy user material bytes into temporary ints
619     for (i = 0, j = 0; i < KC;)
620       tk[i++] =  k[j++]         << 24
621               | (k[j++] & 0xFF) << 16
622               | (k[j++] & 0xFF) << 8
623               | (k[j++] & 0xFF);
624     // copy values into round key arrays
625     int t = 0;
626     for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++)
627       {
628         Ke[t / BC][t % BC] = tk[j];
629         Kd[ROUNDS - (t / BC)][t % BC] = tk[j];
630       }
631     int tt, rconpointer = 0;
632     while (t < ROUND_KEY_COUNT)
633       {
634         // extrapolate using phi (the round key evolution function)
635         tt = tk[KC - 1];
636         tk[0] ^= (S[(tt >>> 16) & 0xFF] & 0xFF) << 24
637                ^ (S[(tt >>>  8) & 0xFF] & 0xFF) << 16
638                ^ (S[ tt         & 0xFF] & 0xFF) <<  8
639                ^ (S[(tt >>> 24)       ] & 0xFF) ^ rcon[rconpointer++] << 24;
640         if (KC != 8)
641           for (i = 1, j = 0; i < KC;)
642             tk[i++] ^= tk[j++];
643         else
644           {
645             for (i = 1, j = 0; i < KC / 2;)
646               tk[i++] ^= tk[j++];
647             tt = tk[KC / 2 - 1];
648             tk[KC / 2] ^= (S[ tt         & 0xFF] & 0xFF)
649                         ^ (S[(tt >>>  8) & 0xFF] & 0xFF) << 8
650                         ^ (S[(tt >>> 16) & 0xFF] & 0xFF) << 16
651                         ^  S[(tt >>> 24) & 0xFF]         << 24;
652             for (j = KC / 2, i = j + 1; i < KC;)
653               tk[i++] ^= tk[j++];
654           }
655         // copy values into round key arrays
656         for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++)
657           {
658             Ke[t / BC][t % BC] = tk[j];
659             Kd[ROUNDS - (t / BC)][t % BC] = tk[j];
660           }
661       }
662     for (int r = 1; r < ROUNDS; r++) // inverse MixColumn where needed
663       for (j = 0; j < BC; j++)
664         {
665           tt = Kd[r][j];
666           Kd[r][j] = U1[(tt >>> 24)       ]
667                    ^ U2[(tt >>> 16) & 0xFF]
668                    ^ U3[(tt >>>  8) & 0xFF]
669                    ^ U4[ tt         & 0xFF];
670         }
671     return new Object[] { Ke, Kd };
672   }
673 
encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)674   public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
675   {
676     if (! (bs == 16 || bs == 24 || bs == 32))
677       throw new IllegalArgumentException();
678     if (bs == DEFAULT_BLOCK_SIZE)
679       aesEncrypt(in, i, out, j, k);
680     else
681       rijndaelEncrypt(in, i, out, j, k, bs);
682   }
683 
decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)684   public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
685   {
686     if (! (bs == 16 || bs == 24 || bs == 32))
687       throw new IllegalArgumentException();
688     if (bs == DEFAULT_BLOCK_SIZE)
689       aesDecrypt(in, i, out, j, k);
690     else
691       rijndaelDecrypt(in, i, out, j, k, bs);
692   }
693 
selfTest()694   public boolean selfTest()
695   {
696     if (valid == null)
697       {
698         boolean result = super.selfTest(); // do symmetry tests
699         if (result)
700           result = testKat(KAT_KEY, KAT_CT);
701         valid = Boolean.valueOf(result);
702       }
703     return valid.booleanValue();
704   }
705 }
706