Source for gnu.javax.crypto.cipher.Rijndael

   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(", ");
 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(", ");
 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(", ");
 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(", ");
 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(", ");
 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(", ");
 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(", ");
 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(", ");
 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(", ");
 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(", ");
 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(", ");
 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(", ");
 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(", ");
 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(", ");
 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(", ");
 295:               log.fine(sb.toString());
 296:             }
 297:           log.fine("Total initialization time: " + time + " ms.");
 298:         }
 299:     }
 300: 
 301:   /** Trivial 0-arguments constructor. */
 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:    */
 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: 
 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: 
 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: 
 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: 
 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: 
 564:   public Object clone()
 565:   {
 566:     Rijndael result = new Rijndael();
 567:     result.currentBlockSize = this.currentBlockSize;
 568: 
 569:     return result;
 570:   }
 571: 
 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: 
 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:    */
 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: 
 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: 
 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: 
 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: }