Source for gnu.javax.crypto.cipher.Rijndael

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