Source for gnu.javax.crypto.cipher.Twofish

   1: /* Twofish.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:  * Twofish is a balanced 128-bit Feistel cipher, consisting of 16 rounds. In
  53:  * each round, a 64-bit S-box value is computed from 64 bits of the block, and
  54:  * this value is xored into the other half of the block. The two half-blocks are
  55:  * then exchanged, and the next round begins. Before the first round, all input
  56:  * bits are xored with key-dependent "whitening" subkeys, and after the final
  57:  * round the output bits are xored with other key-dependent whitening subkeys;
  58:  * these subkeys are not used anywhere else in the algorithm.
  59:  * <p>
  60:  * Twofish is designed by Bruce Schneier, Doug Whiting, John Kelsey, Chris
  61:  * Hall, David Wagner and Niels Ferguson.
  62:  * <p>
  63:  * References:
  64:  * <ol>
  65:  *    <li><a href="http://www.counterpane.com/twofish-paper.html">Twofish: A
  66:  *    128-bit Block Cipher</a>.</li>
  67:  * </ol>
  68:  */
  69: public final class Twofish
  70:     extends BaseCipher
  71: {
  72:   private static final Logger log = Configuration.DEBUG ?
  73:                         Logger.getLogger(Twofish.class.getName()) : null;
  74:   private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes
  75:   private static final int DEFAULT_KEY_SIZE = 16; // in bytes
  76:   private static final int MAX_ROUNDS = 16; // max # rounds (for allocating subkeys)
  77:   private static final int ROUNDS = MAX_ROUNDS;
  78:   // subkey array indices
  79:   private static final int INPUT_WHITEN = 0;
  80:   private static final int OUTPUT_WHITEN = INPUT_WHITEN + DEFAULT_BLOCK_SIZE / 4;
  81:   private static final int ROUND_SUBKEYS = OUTPUT_WHITEN + DEFAULT_BLOCK_SIZE / 4;
  82:   private static final int SK_STEP = 0x02020202;
  83:   private static final int SK_BUMP = 0x01010101;
  84:   private static final int SK_ROTL = 9;
  85:   private static final String[] Pm = new String[] {
  86:       // p0
  87:       "\uA967\uB3E8\u04FD\uA376\u9A92\u8078\uE4DD\uD138"
  88:     + "\u0DC6\u3598\u18F7\uEC6C\u4375\u3726\uFA13\u9448"
  89:     + "\uF2D0\u8B30\u8454\uDF23\u195B\u3D59\uF3AE\uA282"
  90:     + "\u6301\u832E\uD951\u9B7C\uA6EB\uA5BE\u160C\uE361"
  91:     + "\uC08C\u3AF5\u732C\u250B\uBB4E\u896B\u536A\uB4F1"
  92:     + "\uE1E6\uBD45\uE2F4\uB666\uCC95\u0356\uD41C\u1ED7"
  93:     + "\uFBC3\u8EB5\uE9CF\uBFBA\uEA77\u39AF\u33C9\u6271"
  94:     + "\u8179\u09AD\u24CD\uF9D8\uE5C5\uB94D\u4408\u86E7"
  95:     + "\uA11D\uAAED\u0670\uB2D2\u417B\uA011\u31C2\u2790"
  96:     + "\u20F6\u60FF\u965C\uB1AB\u9E9C\u521B\u5F93\u0AEF"
  97:     + "\u9185\u49EE\u2D4F\u8F3B\u4787\u6D46\uD63E\u6964"
  98:     + "\u2ACE\uCB2F\uFC97\u057A\uAC7F\uD51A\u4B0E\uA75A"
  99:     + "\u2814\u3F29\u883C\u4C02\uB8DA\uB017\u551F\u8A7D"
 100:     + "\u57C7\u8D74\uB7C4\u9F72\u7E15\u2212\u5807\u9934"
 101:     + "\u6E50\uDE68\u65BC\uDBF8\uC8A8\u2B40\uDCFE\u32A4"
 102:     + "\uCA10\u21F0\uD35D\u0F00\u6F9D\u3642\u4A5E\uC1E0",
 103:       // p1
 104:       "\u75F3\uC6F4\uDB7B\uFBC8\u4AD3\uE66B\u457D\uE84B"
 105:     + "\uD632\uD8FD\u3771\uF1E1\u300F\uF81B\u87FA\u063F"
 106:     + "\u5EBA\uAE5B\u8A00\uBC9D\u6DC1\uB10E\u805D\uD2D5"
 107:     + "\uA084\u0714\uB590\u2CA3\uB273\u4C54\u9274\u3651"
 108:     + "\u38B0\uBD5A\uFC60\u6296\u6C42\uF710\u7C28\u278C"
 109:     + "\u1395\u9CC7\u2446\u3B70\uCAE3\u85CB\u11D0\u93B8"
 110:     + "\uA683\u20FF\u9F77\uC3CC\u036F\u08BF\u40E7\u2BE2"
 111:     + "\u790C\uAA82\u413A\uEAB9\uE49A\uA497\u7EDA\u7A17"
 112:     + "\u6694\uA11D\u3DF0\uDEB3\u0B72\uA71C\uEFD1\u533E"
 113:     + "\u8F33\u265F\uEC76\u2A49\u8188\uEE21\uC41A\uEBD9"
 114:     + "\uC539\u99CD\uAD31\u8B01\u1823\uDD1F\u4E2D\uF948"
 115:     + "\u4FF2\u658E\u785C\u5819\u8DE5\u9857\u677F\u0564"
 116:     + "\uAF63\uB6FE\uF5B7\u3CA5\uCEE9\u6844\uE04D\u4369"
 117:     + "\u292E\uAC15\u59A8\u0A9E\u6E47\uDF34\u356A\uCFDC"
 118:     + "\u22C9\uC09B\u89D4\uEDAB\u12A2\u0D52\uBB02\u2FA9"
 119:     + "\uD761\u1EB4\u5004\uF6C2\u1625\u8656\u5509\uBE91" };
 120:   /** Fixed 8x8 permutation S-boxes */
 121:   private static final byte[][] P = new byte[2][256]; // blank final
 122:   /**
 123:    * Define the fixed p0/p1 permutations used in keyed S-box lookup. By
 124:    * changing the following constant definitions, the S-boxes will
 125:    * automatically get changed in the Twofish engine.
 126:    */
 127:   private static final int P_00 = 1;
 128:   private static final int P_01 = 0;
 129:   private static final int P_02 = 0;
 130:   private static final int P_03 = P_01 ^ 1;
 131:   private static final int P_04 = 1;
 132:   private static final int P_10 = 0;
 133:   private static final int P_11 = 0;
 134:   private static final int P_12 = 1;
 135:   private static final int P_13 = P_11 ^ 1;
 136:   private static final int P_14 = 0;
 137:   private static final int P_20 = 1;
 138:   private static final int P_21 = 1;
 139:   private static final int P_22 = 0;
 140:   private static final int P_23 = P_21 ^ 1;
 141:   private static final int P_24 = 0;
 142:   private static final int P_30 = 0;
 143:   private static final int P_31 = 1;
 144:   private static final int P_32 = 1;
 145:   private static final int P_33 = P_31 ^ 1;
 146:   private static final int P_34 = 1;
 147:   /** Primitive polynomial for GF(256) */
 148:   private static final int GF256_FDBK_2 = 0x169 / 2;
 149:   private static final int GF256_FDBK_4 = 0x169 / 4;
 150:   /** MDS matrix */
 151:   private static final int[][] MDS = new int[4][256]; // blank final
 152:   private static final int RS_GF_FDBK = 0x14D; // field generator
 153:   /**
 154:    * KAT vector (from ecb_vk):
 155:    * I=183
 156:    * KEY=0000000000000000000000000000000000000000000002000000000000000000
 157:    * CT=F51410475B33FBD3DB2117B5C17C82D4
 158:    */
 159:   private static final byte[] KAT_KEY = Util.toBytesFromString(
 160:       "0000000000000000000000000000000000000000000002000000000000000000");
 161:   private static final byte[] KAT_CT =
 162:       Util.toBytesFromString("F51410475B33FBD3DB2117B5C17C82D4");
 163:   /** caches the result of the correctness test, once executed. */
 164:   private static Boolean valid;
 165:   static
 166:     {
 167:       long time = System.currentTimeMillis();
 168:       // expand the P arrays
 169:       int i;
 170:       char c;
 171:       for (i = 0; i < 256; i++)
 172:         {
 173:           c = Pm[0].charAt(i >>> 1);
 174:           P[0][i] = (byte)((i & 1) == 0 ? c >>> 8 : c);
 175:           c = Pm[1].charAt(i >>> 1);
 176:           P[1][i] = (byte)((i & 1) == 0 ? c >>> 8 : c);
 177:         }
 178:       // precompute the MDS matrix
 179:       int[] m1 = new int[2];
 180:       int[] mX = new int[2];
 181:       int[] mY = new int[2];
 182:       int j;
 183:       for (i = 0; i < 256; i++)
 184:         {
 185:           j = P[0][i] & 0xFF; // compute all the matrix elements
 186:           m1[0] = j;
 187:           mX[0] = Mx_X(j) & 0xFF;
 188:           mY[0] = Mx_Y(j) & 0xFF;
 189:           j = P[1][i] & 0xFF;
 190:           m1[1] = j;
 191:           mX[1] = Mx_X(j) & 0xFF;
 192:           mY[1] = Mx_Y(j) & 0xFF;
 193:           MDS[0][i] = m1[P_00] << 0
 194:                     | mX[P_00] << 8
 195:                     | mY[P_00] << 16
 196:                     | mY[P_00] << 24;
 197:           MDS[1][i] = mY[P_10] << 0
 198:                     | mY[P_10] << 8
 199:                     | mX[P_10] << 16
 200:                     | m1[P_10] << 24;
 201:           MDS[2][i] = mX[P_20] << 0
 202:                     | mY[P_20] << 8
 203:                     | m1[P_20] << 16
 204:                     | mY[P_20] << 24;
 205:           MDS[3][i] = mX[P_30] << 0
 206:                     | m1[P_30] << 8
 207:                     | mY[P_30] << 16
 208:                     | mX[P_30] << 24;
 209:         }
 210:       time = System.currentTimeMillis() - time;
 211:       if (Configuration.DEBUG)
 212:         {
 213:           log.fine("Static Data");
 214:           log.fine("MDS[0][]:");
 215:           StringBuilder sb;
 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(MDS[0][i * 4 + j])).append(", ");
 221:               log.fine(sb.toString());
 222:             }
 223:           log.fine("MDS[1][]:");
 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(MDS[1][i * 4 + j])).append(", ");
 229:               log.fine(sb.toString());
 230:             }
 231:           log.fine("MDS[2][]:");
 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(MDS[2][i * 4 + j])).append(", ");
 237:               log.fine(sb.toString());
 238:             }
 239:           log.fine("MDS[3][]:");
 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(MDS[3][i * 4 + j])).append(", ");
 245:               log.fine(sb.toString());
 246:             }
 247:           log.fine("Total initialization time: " + time + " ms.");
 248:         }
 249:     }
 250: 
 251:   private static final int LFSR1(int x)
 252:   {
 253:     return (x >> 1) ^ ((x & 0x01) != 0 ? GF256_FDBK_2 : 0);
 254:   }
 255: 
 256:   private static final int LFSR2(int x)
 257:   {
 258:     return (x >> 2)
 259:         ^ ((x & 0x02) != 0 ? GF256_FDBK_2 : 0)
 260:         ^ ((x & 0x01) != 0 ? GF256_FDBK_4 : 0);
 261:   }
 262: 
 263:   private static final int Mx_X(int x)
 264:   { // 5B
 265:     return x ^ LFSR2(x);
 266:   }
 267: 
 268:   private static final int Mx_Y(int x)
 269:   { // EF
 270:     return x ^ LFSR1(x) ^ LFSR2(x);
 271:   }
 272: 
 273:   /** Trivial 0-arguments constructor. */
 274:   public Twofish()
 275:   {
 276:     super(Registry.TWOFISH_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE);
 277:   }
 278: 
 279:   private static final int b0(int x)
 280:   {
 281:     return x & 0xFF;
 282:   }
 283: 
 284:   private static final int b1(int x)
 285:   {
 286:     return (x >>> 8) & 0xFF;
 287:   }
 288: 
 289:   private static final int b2(int x)
 290:   {
 291:     return (x >>> 16) & 0xFF;
 292:   }
 293: 
 294:   private static final int b3(int x)
 295:   {
 296:     return (x >>> 24) & 0xFF;
 297:   }
 298: 
 299:   /**
 300:    * Use (12, 8) Reed-Solomon code over GF(256) to produce a key S-box 32-bit
 301:    * entity from two key material 32-bit entities.
 302:    *
 303:    * @param k0 1st 32-bit entity.
 304:    * @param k1 2nd 32-bit entity.
 305:    * @return remainder polynomial generated using RS code
 306:    */
 307:   private static final int RS_MDS_Encode(int k0, int k1)
 308:   {
 309:     int r = k1;
 310:     int i;
 311:     for (i = 0; i < 4; i++) // shift 1 byte at a time
 312:       r = RS_rem(r);
 313:     r ^= k0;
 314:     for (i = 0; i < 4; i++)
 315:       r = RS_rem(r);
 316:     return r;
 317:   }
 318: 
 319:   /**
 320:    * Reed-Solomon code parameters: (12, 8) reversible code:<p>
 321:    * <pre>
 322:    *   g(x) = x**4 + (a + 1/a) x**3 + a x**2 + (a + 1/a) x + 1
 323:    * </pre>
 324:    * where a = primitive root of field generator 0x14D
 325:    */
 326:   private static final int RS_rem(int x)
 327:   {
 328:     int b = (x >>> 24) & 0xFF;
 329:     int g2 = ((b << 1) ^ ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xFF;
 330:     int g3 = (b >>> 1) ^ ((b & 0x01) != 0 ? (RS_GF_FDBK >>> 1) : 0) ^ g2;
 331:     int result = (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b;
 332:     return result;
 333:   }
 334: 
 335:   private static final int F32(int k64Cnt, int x, int[] k32)
 336:   {
 337:     int b0 = b0(x);
 338:     int b1 = b1(x);
 339:     int b2 = b2(x);
 340:     int b3 = b3(x);
 341:     int k0 = k32[0];
 342:     int k1 = k32[1];
 343:     int k2 = k32[2];
 344:     int k3 = k32[3];
 345:     int result = 0;
 346:     switch (k64Cnt & 3)
 347:       {
 348:       case 1:
 349:         result = MDS[0][(P[P_01][b0] & 0xFF) ^ b0(k0)]
 350:                ^ MDS[1][(P[P_11][b1] & 0xFF) ^ b1(k0)]
 351:                ^ MDS[2][(P[P_21][b2] & 0xFF) ^ b2(k0)]
 352:                ^ MDS[3][(P[P_31][b3] & 0xFF) ^ b3(k0)];
 353:         break;
 354:       case 0: // same as 4
 355:         b0 = (P[P_04][b0] & 0xFF) ^ b0(k3);
 356:         b1 = (P[P_14][b1] & 0xFF) ^ b1(k3);
 357:         b2 = (P[P_24][b2] & 0xFF) ^ b2(k3);
 358:         b3 = (P[P_34][b3] & 0xFF) ^ b3(k3);
 359:       case 3:
 360:         b0 = (P[P_03][b0] & 0xFF) ^ b0(k2);
 361:         b1 = (P[P_13][b1] & 0xFF) ^ b1(k2);
 362:         b2 = (P[P_23][b2] & 0xFF) ^ b2(k2);
 363:         b3 = (P[P_33][b3] & 0xFF) ^ b3(k2);
 364:       case 2: // 128-bit keys (optimize for this case)
 365:         result = MDS[0][(P[P_01][(P[P_02][b0] & 0xFF) ^ b0(k1)] & 0xFF) ^ b0(k0)]
 366:                ^ MDS[1][(P[P_11][(P[P_12][b1] & 0xFF) ^ b1(k1)] & 0xFF) ^ b1(k0)]
 367:                ^ MDS[2][(P[P_21][(P[P_22][b2] & 0xFF) ^ b2(k1)] & 0xFF) ^ b2(k0)]
 368:                ^ MDS[3][(P[P_31][(P[P_32][b3] & 0xFF) ^ b3(k1)] & 0xFF) ^ b3(k0)];
 369:         break;
 370:       }
 371:     return result;
 372:   }
 373: 
 374:   private static final int Fe32(int[] sBox, int x, int R)
 375:   {
 376:     return sBox[        2 * _b(x, R    )    ]
 377:          ^ sBox[        2 * _b(x, R + 1) + 1]
 378:          ^ sBox[0x200 + 2 * _b(x, R + 2)    ]
 379:          ^ sBox[0x200 + 2 * _b(x, R + 3) + 1];
 380:   }
 381: 
 382:   private static final int _b(int x, int N)
 383:   {
 384:     switch (N % 4)
 385:       {
 386:       case 0:
 387:         return x & 0xFF;
 388:       case 1:
 389:         return (x >>> 8) & 0xFF;
 390:       case 2:
 391:         return (x >>> 16) & 0xFF;
 392:       default:
 393:         return x >>> 24;
 394:       }
 395:   }
 396: 
 397:   public Object clone()
 398:   {
 399:     Twofish result = new Twofish();
 400:     result.currentBlockSize = this.currentBlockSize;
 401:     return result;
 402:   }
 403: 
 404:   public Iterator blockSizes()
 405:   {
 406:     ArrayList al = new ArrayList();
 407:     al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE));
 408:     return Collections.unmodifiableList(al).iterator();
 409:   }
 410: 
 411:   public Iterator keySizes()
 412:   {
 413:     ArrayList al = new ArrayList();
 414:     al.add(Integer.valueOf(8)); //   64-bit
 415:     al.add(Integer.valueOf(16)); // 128-bit
 416:     al.add(Integer.valueOf(24)); // 192-bit
 417:     al.add(Integer.valueOf(32)); // 256-bit
 418:     return Collections.unmodifiableList(al).iterator();
 419:   }
 420: 
 421:   /**
 422:    * Expands a user-supplied key material into a session key for a designated
 423:    * <i>block size</i>.
 424:    *
 425:    * @param k the 64/128/192/256-bit user-key to use.
 426:    * @param bs the desired block size in bytes.
 427:    * @return an Object encapsulating the session key.
 428:    * @exception IllegalArgumentException if the block size is not 16 (128-bit).
 429:    * @exception InvalidKeyException if the key data is invalid.
 430:    */
 431:   public Object makeKey(byte[] k, int bs) throws InvalidKeyException
 432:   {
 433:     if (bs != DEFAULT_BLOCK_SIZE)
 434:       throw new IllegalArgumentException();
 435:     if (k == null)
 436:       throw new InvalidKeyException("Empty key");
 437:     int length = k.length;
 438:     if (! (length == 8 || length == 16 || length == 24 || length == 32))
 439:       throw new InvalidKeyException("Incorrect key length");
 440:     int k64Cnt = length / 8;
 441:     int subkeyCnt = ROUND_SUBKEYS + 2 * ROUNDS;
 442:     int[] k32e = new int[4]; // even 32-bit entities
 443:     int[] k32o = new int[4]; // odd 32-bit entities
 444:     int[] sBoxKey = new int[4];
 445:     // split user key material into even and odd 32-bit entities and
 446:     // compute S-box keys using (12, 8) Reed-Solomon code over GF(256)
 447:     int i, j, offset = 0;
 448:     for (i = 0, j = k64Cnt - 1; i < 4 && offset < length; i++, j--)
 449:       {
 450:         k32e[i] = (k[offset++] & 0xFF)
 451:                 | (k[offset++] & 0xFF) << 8
 452:                 | (k[offset++] & 0xFF) << 16
 453:                 | (k[offset++] & 0xFF) << 24;
 454:         k32o[i] = (k[offset++] & 0xFF)
 455:                 | (k[offset++] & 0xFF) << 8
 456:                 | (k[offset++] & 0xFF) << 16
 457:                 | (k[offset++] & 0xFF) << 24;
 458:         sBoxKey[j] = RS_MDS_Encode(k32e[i], k32o[i]); // reverse order
 459:       }
 460:     // compute the round decryption subkeys for PHT. these same subkeys
 461:     // will be used in encryption but will be applied in reverse order.
 462:     int q, A, B;
 463:     int[] subKeys = new int[subkeyCnt];
 464:     for (i = q = 0; i < subkeyCnt / 2; i++, q += SK_STEP)
 465:       {
 466:         A = F32(k64Cnt, q, k32e); // A uses even key entities
 467:         B = F32(k64Cnt, q + SK_BUMP, k32o); // B uses odd  key entities
 468:         B = B << 8 | B >>> 24;
 469:         A += B;
 470:         subKeys[2 * i] = A; // combine with a PHT
 471:         A += B;
 472:         subKeys[2 * i + 1] = A << SK_ROTL | A >>> (32 - SK_ROTL);
 473:       }
 474:     // fully expand the table for speed
 475:     int k0 = sBoxKey[0];
 476:     int k1 = sBoxKey[1];
 477:     int k2 = sBoxKey[2];
 478:     int k3 = sBoxKey[3];
 479:     int b0, b1, b2, b3;
 480:     int[] sBox = new int[4 * 256];
 481:     for (i = 0; i < 256; i++)
 482:       {
 483:         b0 = b1 = b2 = b3 = i;
 484:         switch (k64Cnt & 3)
 485:           {
 486:           case 1:
 487:             sBox[        2 * i    ] = MDS[0][(P[P_01][b0] & 0xFF) ^ b0(k0)];
 488:             sBox[        2 * i + 1] = MDS[1][(P[P_11][b1] & 0xFF) ^ b1(k0)];
 489:             sBox[0x200 + 2 * i    ] = MDS[2][(P[P_21][b2] & 0xFF) ^ b2(k0)];
 490:             sBox[0x200 + 2 * i + 1] = MDS[3][(P[P_31][b3] & 0xFF) ^ b3(k0)];
 491:             break;
 492:           case 0: // same as 4
 493:             b0 = (P[P_04][b0] & 0xFF) ^ b0(k3);
 494:             b1 = (P[P_14][b1] & 0xFF) ^ b1(k3);
 495:             b2 = (P[P_24][b2] & 0xFF) ^ b2(k3);
 496:             b3 = (P[P_34][b3] & 0xFF) ^ b3(k3);
 497:           case 3:
 498:             b0 = (P[P_03][b0] & 0xFF) ^ b0(k2);
 499:             b1 = (P[P_13][b1] & 0xFF) ^ b1(k2);
 500:             b2 = (P[P_23][b2] & 0xFF) ^ b2(k2);
 501:             b3 = (P[P_33][b3] & 0xFF) ^ b3(k2);
 502:           case 2: // 128-bit keys
 503:             sBox[        2 * i    ] = MDS[0][(P[P_01][(P[P_02][b0] & 0xFF)
 504:                                                       ^ b0(k1)] & 0xFF) ^ b0(k0)];
 505:             sBox[        2 * i + 1] = MDS[1][(P[P_11][(P[P_12][b1] & 0xFF)
 506:                                                       ^ b1(k1)] & 0xFF) ^ b1(k0)];
 507:             sBox[0x200 + 2 * i    ] = MDS[2][(P[P_21][(P[P_22][b2] & 0xFF)
 508:                                                       ^ b2(k1)] & 0xFF) ^ b2(k0)];
 509:             sBox[0x200 + 2 * i + 1] = MDS[3][(P[P_31][(P[P_32][b3] & 0xFF)
 510:                                                       ^ b3(k1)] & 0xFF) ^ b3(k0)];
 511:           }
 512:       }
 513:     if (Configuration.DEBUG)
 514:       {
 515:         StringBuilder sb;
 516:         log.fine("S-box[]:");
 517:         for (i = 0; i < 64; i++)
 518:           {
 519:             sb = new StringBuilder();
 520:             for (j = 0; j < 4; j++)
 521:               sb.append("0x").append(Util.toString(sBox[i * 4 + j])).append(", ");
 522:             log.fine(sb.toString());
 523:           }
 524:         log.fine("");
 525:         for (i = 0; i < 64; i++)
 526:           {
 527:             sb = new StringBuilder();
 528:             for (j = 0; j < 4; j++)
 529:               sb.append("0x").append(Util.toString(sBox[256 + i * 4 + j])).append(", ");
 530:             log.fine(sb.toString());
 531:           }
 532:         log.fine("");
 533:         for (i = 0; i < 64; i++)
 534:           {
 535:             sb = new StringBuilder();
 536:             for (j = 0; j < 4; j++)
 537:               sb.append("0x").append(Util.toString(sBox[512 + i * 4 + j])).append(", ");
 538:             log.fine(sb.toString());
 539:           }
 540:         log.fine("");
 541:         for (i = 0; i < 64; i++)
 542:           {
 543:             sb = new StringBuilder();
 544:             for (j = 0; j < 4; j++)
 545:               sb.append("0x").append(Util.toString(sBox[768 + i * 4 + j])).append(", ");
 546:             log.fine(sb.toString());
 547:           }
 548:         log.fine("User (odd, even) keys  --> S-Box keys:");
 549:         for (i = 0; i < k64Cnt; i++)
 550:           log.fine("0x" + Util.toString(k32o[i])
 551:                    + "  0x" + Util.toString(k32e[i])
 552:                    + " --> 0x" + Util.toString(sBoxKey[k64Cnt - 1 - i]));
 553:         log.fine("Round keys:");
 554:         for (i = 0; i < ROUND_SUBKEYS + 2 * ROUNDS; i += 2)
 555:           log.fine("0x" + Util.toString(subKeys[i])
 556:                    + "  0x" + Util.toString(subKeys[i + 1]));
 557:       }
 558:     return new Object[] { sBox, subKeys };
 559:   }
 560: 
 561:   public void encrypt(byte[] in, int inOffset, byte[] out, int outOffset,
 562:                       Object sessionKey, int bs)
 563:   {
 564:     if (bs != DEFAULT_BLOCK_SIZE)
 565:       throw new IllegalArgumentException();
 566:     Object[] sk = (Object[]) sessionKey; // extract S-box and session key
 567:     int[] sBox = (int[]) sk[0];
 568:     int[] sKey = (int[]) sk[1];
 569:     if (Configuration.DEBUG)
 570:       log.fine("PT=" + Util.toString(in, inOffset, bs));
 571:     int x0 = (in[inOffset++] & 0xFF)
 572:            | (in[inOffset++] & 0xFF) << 8
 573:            | (in[inOffset++] & 0xFF) << 16
 574:            | (in[inOffset++] & 0xFF) << 24;
 575:     int x1 = (in[inOffset++] & 0xFF)
 576:            | (in[inOffset++] & 0xFF) << 8
 577:            | (in[inOffset++] & 0xFF) << 16
 578:            | (in[inOffset++] & 0xFF) << 24;
 579:     int x2 = (in[inOffset++] & 0xFF)
 580:            | (in[inOffset++] & 0xFF) << 8
 581:            | (in[inOffset++] & 0xFF) << 16
 582:            | (in[inOffset++] & 0xFF) << 24;
 583:     int x3 = (in[inOffset++] & 0xFF)
 584:            | (in[inOffset++] & 0xFF) << 8
 585:            | (in[inOffset++] & 0xFF) << 16
 586:            | (in[inOffset++] & 0xFF) << 24;
 587:     x0 ^= sKey[INPUT_WHITEN];
 588:     x1 ^= sKey[INPUT_WHITEN + 1];
 589:     x2 ^= sKey[INPUT_WHITEN + 2];
 590:     x3 ^= sKey[INPUT_WHITEN + 3];
 591:     if (Configuration.DEBUG)
 592:       log.fine("PTw=" + Util.toString(x0) + Util.toString(x1)
 593:                + Util.toString(x2) + Util.toString(x3));
 594:     int t0, t1;
 595:     int k = ROUND_SUBKEYS;
 596:     for (int R = 0; R < ROUNDS; R += 2)
 597:       {
 598:         t0 = Fe32(sBox, x0, 0);
 599:         t1 = Fe32(sBox, x1, 3);
 600:         x2 ^= t0 + t1 + sKey[k++];
 601:         x2 = x2 >>> 1 | x2 << 31;
 602:         x3 = x3 << 1 | x3 >>> 31;
 603:         x3 ^= t0 + 2 * t1 + sKey[k++];
 604:         if (Configuration.DEBUG)
 605:           log.fine("CT" + (R) + "=" + Util.toString(x0) + Util.toString(x1)
 606:                    + Util.toString(x2) + Util.toString(x3));
 607:         t0 = Fe32(sBox, x2, 0);
 608:         t1 = Fe32(sBox, x3, 3);
 609:         x0 ^= t0 + t1 + sKey[k++];
 610:         x0 = x0 >>> 1 | x0 << 31;
 611:         x1 = x1 << 1 | x1 >>> 31;
 612:         x1 ^= t0 + 2 * t1 + sKey[k++];
 613:         if (Configuration.DEBUG)
 614:           log.fine("CT" + (R + 1) + "=" + Util.toString(x0) + Util.toString(x1)
 615:                    + Util.toString(x2) + Util.toString(x3));
 616:       }
 617:     x2 ^= sKey[OUTPUT_WHITEN];
 618:     x3 ^= sKey[OUTPUT_WHITEN + 1];
 619:     x0 ^= sKey[OUTPUT_WHITEN + 2];
 620:     x1 ^= sKey[OUTPUT_WHITEN + 3];
 621:     if (Configuration.DEBUG)
 622:       log.fine("CTw=" + Util.toString(x0) + Util.toString(x1)
 623:                + Util.toString(x2) + Util.toString(x3));
 624:     out[outOffset++] = (byte) x2;
 625:     out[outOffset++] = (byte)(x2 >>> 8);
 626:     out[outOffset++] = (byte)(x2 >>> 16);
 627:     out[outOffset++] = (byte)(x2 >>> 24);
 628:     out[outOffset++] = (byte) x3;
 629:     out[outOffset++] = (byte)(x3 >>> 8);
 630:     out[outOffset++] = (byte)(x3 >>> 16);
 631:     out[outOffset++] = (byte)(x3 >>> 24);
 632:     out[outOffset++] = (byte) x0;
 633:     out[outOffset++] = (byte)(x0 >>> 8);
 634:     out[outOffset++] = (byte)(x0 >>> 16);
 635:     out[outOffset++] = (byte)(x0 >>> 24);
 636:     out[outOffset++] = (byte) x1;
 637:     out[outOffset++] = (byte)(x1 >>> 8);
 638:     out[outOffset++] = (byte)(x1 >>> 16);
 639:     out[outOffset  ] = (byte)(x1 >>> 24);
 640:     if (Configuration.DEBUG)
 641:       log.fine("CT=" + Util.toString(out, outOffset - 15, 16) + "\n");
 642:   }
 643: 
 644:   public void decrypt(byte[] in, int inOffset, byte[] out, int outOffset,
 645:                       Object sessionKey, int bs)
 646:   {
 647:     if (bs != DEFAULT_BLOCK_SIZE)
 648:       throw new IllegalArgumentException();
 649:     Object[] sk = (Object[]) sessionKey; // extract S-box and session key
 650:     int[] sBox = (int[]) sk[0];
 651:     int[] sKey = (int[]) sk[1];
 652:     if (Configuration.DEBUG)
 653:       log.fine("CT=" + Util.toString(in, inOffset, bs));
 654:     int x2 = (in[inOffset++] & 0xFF)
 655:            | (in[inOffset++] & 0xFF) << 8
 656:            | (in[inOffset++] & 0xFF) << 16
 657:            | (in[inOffset++] & 0xFF) << 24;
 658:     int x3 = (in[inOffset++] & 0xFF)
 659:            | (in[inOffset++] & 0xFF) << 8
 660:            | (in[inOffset++] & 0xFF) << 16
 661:            | (in[inOffset++] & 0xFF) << 24;
 662:     int x0 = (in[inOffset++] & 0xFF)
 663:            | (in[inOffset++] & 0xFF) << 8
 664:            | (in[inOffset++] & 0xFF) << 16
 665:            | (in[inOffset++] & 0xFF) << 24;
 666:     int x1 = (in[inOffset++] & 0xFF)
 667:            | (in[inOffset++] & 0xFF) << 8
 668:            | (in[inOffset++] & 0xFF) << 16
 669:            | (in[inOffset++] & 0xFF) << 24;
 670:     x2 ^= sKey[OUTPUT_WHITEN];
 671:     x3 ^= sKey[OUTPUT_WHITEN + 1];
 672:     x0 ^= sKey[OUTPUT_WHITEN + 2];
 673:     x1 ^= sKey[OUTPUT_WHITEN + 3];
 674:     if (Configuration.DEBUG)
 675:       log.fine("CTw=" + Util.toString(x2) + Util.toString(x3)
 676:                + Util.toString(x0) + Util.toString(x1));
 677:     int k = ROUND_SUBKEYS + 2 * ROUNDS - 1;
 678:     int t0, t1;
 679:     for (int R = 0; R < ROUNDS; R += 2)
 680:       {
 681:         t0 = Fe32(sBox, x2, 0);
 682:         t1 = Fe32(sBox, x3, 3);
 683:         x1 ^= t0 + 2 * t1 + sKey[k--];
 684:         x1 = x1 >>> 1 | x1 << 31;
 685:         x0 = x0 << 1 | x0 >>> 31;
 686:         x0 ^= t0 + t1 + sKey[k--];
 687:         if (Configuration.DEBUG)
 688:           log.fine("PT" + (ROUNDS - R) + "=" + Util.toString(x2)
 689:                    + Util.toString(x3) + Util.toString(x0) + Util.toString(x1));
 690:         t0 = Fe32(sBox, x0, 0);
 691:         t1 = Fe32(sBox, x1, 3);
 692:         x3 ^= t0 + 2 * t1 + sKey[k--];
 693:         x3 = x3 >>> 1 | x3 << 31;
 694:         x2 = x2 << 1 | x2 >>> 31;
 695:         x2 ^= t0 + t1 + sKey[k--];
 696:         if (Configuration.DEBUG)
 697:           log.fine("PT" + (ROUNDS - R - 1) + "=" + Util.toString(x2)
 698:                    + Util.toString(x3) + Util.toString(x0) + Util.toString(x1));
 699:       }
 700:     x0 ^= sKey[INPUT_WHITEN];
 701:     x1 ^= sKey[INPUT_WHITEN + 1];
 702:     x2 ^= sKey[INPUT_WHITEN + 2];
 703:     x3 ^= sKey[INPUT_WHITEN + 3];
 704:     if (Configuration.DEBUG)
 705:       log.fine("PTw=" + Util.toString(x2) + Util.toString(x3)
 706:                + Util.toString(x0) + Util.toString(x1));
 707:     out[outOffset++] = (byte) x0;
 708:     out[outOffset++] = (byte)(x0 >>> 8);
 709:     out[outOffset++] = (byte)(x0 >>> 16);
 710:     out[outOffset++] = (byte)(x0 >>> 24);
 711:     out[outOffset++] = (byte) x1;
 712:     out[outOffset++] = (byte)(x1 >>> 8);
 713:     out[outOffset++] = (byte)(x1 >>> 16);
 714:     out[outOffset++] = (byte)(x1 >>> 24);
 715:     out[outOffset++] = (byte) x2;
 716:     out[outOffset++] = (byte)(x2 >>> 8);
 717:     out[outOffset++] = (byte)(x2 >>> 16);
 718:     out[outOffset++] = (byte)(x2 >>> 24);
 719:     out[outOffset++] = (byte) x3;
 720:     out[outOffset++] = (byte)(x3 >>> 8);
 721:     out[outOffset++] = (byte)(x3 >>> 16);
 722:     out[outOffset  ] = (byte)(x3 >>> 24);
 723:     if (Configuration.DEBUG)
 724:       log.fine("PT=" + Util.toString(out, outOffset - 15, 16) + "\n");
 725:   }
 726: 
 727:   public boolean selfTest()
 728:   {
 729:     if (valid == null)
 730:       {
 731:         boolean result = super.selfTest(); // do symmetry tests
 732:         if (result)
 733:           result = testKat(KAT_KEY, KAT_CT);
 734:         valid = Boolean.valueOf(result);
 735:       }
 736:     return valid.booleanValue();
 737:   }
 738: }