Source for gnu.javax.crypto.cipher.Square

   1: /* Square.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.Registry;
  42: import gnu.java.security.util.Util;
  43: 
  44: import java.security.InvalidKeyException;
  45: import java.util.ArrayList;
  46: import java.util.Collections;
  47: import java.util.Iterator;
  48: 
  49: /**
  50:  * Square is a 128-bit key, 128-bit block cipher algorithm developed by Joan
  51:  * Daemen, Lars Knudsen and Vincent Rijmen.
  52:  * <p>
  53:  * References:
  54:  * <ol>
  55:  * <li><a href="http://www.esat.kuleuven.ac.be/~rijmen/square/">The block
  56:  * cipher Square</a>.<br>
  57:  * <a href="mailto:daemen.j@protonworld.com">Joan Daemen</a>, <a
  58:  * href="mailto:lars.knudsen@esat.kuleuven.ac.be">Lars Knudsen</a> and <a
  59:  * href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a>.</li>
  60:  * </ol>
  61:  */
  62: public final class Square
  63:     extends BaseCipher
  64: {
  65:   private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes
  66:   private static final int DEFAULT_KEY_SIZE = 16; // in bytes
  67:   private static final int ROUNDS = 8;
  68:   private static final int ROOT = 0x1F5; // for generating GF(2**8)
  69:   private static final int[] OFFSET = new int[ROUNDS];
  70:   private static final String Sdata =
  71:       "\uB1CE\uC395\u5AAD\uE702\u4D44\uFB91\u0C87\uA150"
  72:     + "\uCB67\u54DD\u468F\uE14E\uF0FD\uFCEB\uF9C4\u1A6E"
  73:     + "\u5EF5\uCC8D\u1C56\u43FE\u0761\uF875\u59FF\u0322"
  74:     + "\u8AD1\u13EE\u8800\u0E34\u1580\u94E3\uEDB5\u5323"
  75:     + "\u4B47\u17A7\u9035\uABD8\uB8DF\u4F57\u9A92\uDB1B"
  76:     + "\u3CC8\u9904\u8EE0\uD77D\u85BB\u402C\u3A45\uF142"
  77:     + "\u6520\u4118\u7225\u9370\u3605\uF20B\uA379\uEC08"
  78:     + "\u2731\u32B6\u7CB0\u0A73\u5B7B\uB781\uD20D\u6A26"
  79:     + "\u9E58\u9C83\u74B3\uAC30\u7A69\u770F\uAE21\uDED0"
  80:     + "\u2E97\u10A4\u98A8\uD468\u2D62\u296D\u1649\u76C7"
  81:     + "\uE8C1\u9637\uE5CA\uF4E9\u6312\uC2A6\u14BC\uD328"
  82:     + "\uAF2F\uE624\u52C6\uA009\uBD8C\uCF5D\u115F\u01C5"
  83:     + "\u9F3D\uA29B\uC93B\uBE51\u191F\u3F5C\uB2EF\u4ACD"
  84:     + "\uBFBA\u6F64\uD9F3\u3EB4\uAADC\uD506\uC07E\uF666"
  85:     + "\u6C84\u7138\uB91D\u7F9D\u488B\u2ADA\uA533\u8239"
  86:     + "\uD678\u86FA\uE42B\uA91E\u8960\u6BEA\u554C\uF7E2";
  87:   /** Substitution boxes for encryption and decryption. */
  88:   private static final byte[] Se = new byte[256];
  89:   private static final byte[] Sd = new byte[256];
  90:   /** Transposition boxes for encryption and decryption. */
  91:   private static final int[] Te = new int[256];
  92:   private static final int[] Td = new int[256];
  93:   /**
  94:    * KAT vector (from ecb_vk): I=87 KEY=00000000000000000000020000000000
  95:    * CT=A9DF031B4E25E89F527EFFF89CB0BEBA
  96:    */
  97:   private static final byte[] KAT_KEY =
  98:       Util.toBytesFromString("00000000000000000000020000000000");
  99:   private static final byte[] KAT_CT =
 100:       Util.toBytesFromString("A9DF031B4E25E89F527EFFF89CB0BEBA");
 101:   /** caches the result of the correctness test, once executed. */
 102:   private static Boolean valid;
 103:   static
 104:     {
 105:       int i, j;
 106:       // re-construct Se box values
 107:       int limit = Sdata.length();
 108:       char c1;
 109:       for (i = 0, j = 0; i < limit; i++)
 110:         {
 111:           c1 = Sdata.charAt(i);
 112:           Se[j++] = (byte)(c1 >>> 8);
 113:           Se[j++] = (byte) c1;
 114:         }
 115:       // compute Sd box values
 116:       for (i = 0; i < 256; i++)
 117:         Sd[Se[i] & 0xFF] = (byte) i;
 118:       // generate OFFSET values
 119:       OFFSET[0] = 1;
 120:       for (i = 1; i < ROUNDS; i++)
 121:         {
 122:           OFFSET[i] = mul(OFFSET[i - 1], 2);
 123:           OFFSET[i - 1] <<= 24;
 124:         }
 125:       OFFSET[ROUNDS - 1] <<= 24;
 126:       // generate Te and Td boxes if we're not reading their values
 127:       // Notes:
 128:       // (1) The function mul() computes the product of two elements of GF(2**8)
 129:       // with ROOT as reduction polynomial.
 130:       // (2) the values used in computing the Te and Td are the GF(2**8)
 131:       // coefficients of the diffusion polynomial c(x) and its inverse
 132:       // (modulo x**4 + 1) d(x), defined in sections 2.1 and 4 of the Square
 133:       // paper.
 134:       for (i = 0; i < 256; i++)
 135:         {
 136:           j = Se[i] & 0xFF;
 137:           Te[i] = (Se[i & 3] == 0) ? 0
 138:                                    : mul(j, 2) << 24
 139:                                    | j << 16
 140:                                    | j << 8
 141:                                    | mul(j, 3);
 142:           j = Sd[i] & 0xFF;
 143:           Td[i] = (Sd[i & 3] == 0) ? 0
 144:                                    : mul(j, 14) << 24
 145:                                    | mul(j,  9) << 16
 146:                                    | mul(j, 13) << 8
 147:                                    | mul(j, 11);
 148:         }
 149:     }
 150: 
 151:   /** Trivial 0-arguments constructor. */
 152:   public Square()
 153:   {
 154:     super(Registry.SQUARE_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE);
 155:   }
 156: 
 157:   private static void square(byte[] in, int i, byte[] out, int j, int[][] K,
 158:                              int[] T, byte[] S)
 159:   {
 160:     int a = ((in[i++])        << 24
 161:            | (in[i++] & 0xFF) << 16
 162:            | (in[i++] & 0xFF) <<  8
 163:            | (in[i++] & 0xFF)      ) ^ K[0][0];
 164:     int b = ((in[i++])        << 24
 165:            | (in[i++] & 0xFF) << 16
 166:            | (in[i++] & 0xFF) <<  8
 167:            | (in[i++] & 0xFF)      ) ^ K[0][1];
 168:     int c = ((in[i++])        << 24
 169:            | (in[i++] & 0xFF) << 16
 170:            | (in[i++] & 0xFF) <<  8
 171:            | (in[i++] & 0xFF)      ) ^ K[0][2];
 172:     int d = ((in[i++])        << 24
 173:            | (in[i++] & 0xFF) << 16
 174:            | (in[i++] & 0xFF) <<  8
 175:            | (in[i  ] & 0xFF)      ) ^ K[0][3];
 176:     int r, aa, bb, cc, dd;
 177:     for (r = 1; r < ROUNDS; r++)
 178:       { // R - 1 full rounds
 179:         aa =        T[(a >>> 24)       ]
 180:            ^ rot32R(T[(b >>> 24)       ], 8)
 181:            ^ rot32R(T[(c >>> 24)       ], 16)
 182:            ^ rot32R(T[(d >>> 24)       ], 24) ^ K[r][0];
 183:         bb =        T[(a >>> 16) & 0xFF]
 184:            ^ rot32R(T[(b >>> 16) & 0xFF], 8)
 185:            ^ rot32R(T[(c >>> 16) & 0xFF], 16)
 186:            ^ rot32R(T[(d >>> 16) & 0xFF], 24) ^ K[r][1];
 187:         cc =        T[(a >>>  8) & 0xFF]
 188:            ^ rot32R(T[(b >>>  8) & 0xFF], 8)
 189:            ^ rot32R(T[(c >>>  8) & 0xFF], 16)
 190:            ^ rot32R(T[(d >>>  8) & 0xFF], 24) ^ K[r][2];
 191:         dd =        T[ a         & 0xFF]
 192:            ^ rot32R(T[ b         & 0xFF], 8)
 193:            ^ rot32R(T[ c         & 0xFF], 16)
 194:            ^ rot32R(T[ d         & 0xFF], 24) ^ K[r][3];
 195:         a = aa;
 196:         b = bb;
 197:         c = cc;
 198:         d = dd;
 199:       }
 200:     // last round (diffusion becomes only transposition)
 201:     aa = ((S[(a >>> 24)       ]       ) << 24
 202:         | (S[(b >>> 24)       ] & 0xFF) << 16
 203:         | (S[(c >>> 24)       ] & 0xFF) <<  8
 204:         | (S[(d >>> 24)       ] & 0xFF)      ) ^ K[r][0];
 205:     bb = ((S[(a >>> 16) & 0xFF]       ) << 24
 206:         | (S[(b >>> 16) & 0xFF] & 0xFF) << 16
 207:         | (S[(c >>> 16) & 0xFF] & 0xFF) <<  8
 208:         | (S[(d >>> 16) & 0xFF] & 0xFF)      ) ^ K[r][1];
 209:     cc = ((S[(a >>>  8) & 0xFF]       ) << 24
 210:         | (S[(b >>>  8) & 0xFF] & 0xFF) << 16
 211:         | (S[(c >>>  8) & 0xFF] & 0xFF) <<  8
 212:         | (S[(d >>>  8) & 0xFF] & 0xFF)      ) ^ K[r][2];
 213:     dd = ((S[ a         & 0xFF]       ) << 24
 214:         | (S[ b         & 0xFF] & 0xFF) << 16
 215:         | (S[ c         & 0xFF] & 0xFF) <<  8
 216:         | (S[ d         & 0xFF] & 0xFF)      ) ^ K[r][3];
 217:     out[j++] = (byte)(aa >>> 24);
 218:     out[j++] = (byte)(aa >>> 16);
 219:     out[j++] = (byte)(aa >>> 8);
 220:     out[j++] = (byte) aa;
 221:     out[j++] = (byte)(bb >>> 24);
 222:     out[j++] = (byte)(bb >>> 16);
 223:     out[j++] = (byte)(bb >>> 8);
 224:     out[j++] = (byte) bb;
 225:     out[j++] = (byte)(cc >>> 24);
 226:     out[j++] = (byte)(cc >>> 16);
 227:     out[j++] = (byte)(cc >>> 8);
 228:     out[j++] = (byte) cc;
 229:     out[j++] = (byte)(dd >>> 24);
 230:     out[j++] = (byte)(dd >>> 16);
 231:     out[j++] = (byte)(dd >>> 8);
 232:     out[j  ] = (byte) dd;
 233:   }
 234: 
 235:   /**
 236:    * Applies the Theta function to an input <i>in</i> in order to produce in
 237:    * <i>out</i> an internal session sub-key.
 238:    * <p>
 239:    * Both <i>in</i> and <i>out</i> are arrays of four ints.
 240:    * <p>
 241:    * Pseudo-code is:
 242:    * <pre>
 243:    * for (i = 0; i &lt; 4; i++)
 244:    *   {
 245:    *     out[i] = 0;
 246:    *     for (j = 0, n = 24; j &lt; 4; j++, n -= 8)
 247:    *       {
 248:    *         k = mul(in[i] &gt;&gt;&gt; 24, G[0][j]) &circ; mul(in[i] &gt;&gt;&gt; 16, G[1][j])
 249:    *             &circ; mul(in[i] &gt;&gt;&gt; 8, G[2][j]) &circ; mul(in[i], G[3][j]);
 250:    *         out[i] &circ;= k &lt;&lt; n;
 251:    *       }
 252:    *   }
 253:    * </pre>
 254:    */
 255:   private static void transform(int[] in, int[] out)
 256:   {
 257:     int l3, l2, l1, l0, m;
 258:     for (int i = 0; i < 4; i++)
 259:       {
 260:         l3 = in[i];
 261:         l2 = l3 >>> 8;
 262:         l1 = l3 >>> 16;
 263:         l0 = l3 >>> 24;
 264:         m = ((mul(l0, 2) ^ mul(l1, 3) ^ l2 ^ l3) & 0xFF) << 24;
 265:         m ^= ((l0 ^ mul(l1, 2) ^ mul(l2, 3) ^ l3) & 0xFF) << 16;
 266:         m ^= ((l0 ^ l1 ^ mul(l2, 2) ^ mul(l3, 3)) & 0xFF) << 8;
 267:         m ^= ((mul(l0, 3) ^ l1 ^ l2 ^ mul(l3, 2)) & 0xFF);
 268:         out[i] = m;
 269:       }
 270:   }
 271: 
 272:   /**
 273:    * Left rotate a 32-bit chunk.
 274:    *
 275:    * @param x the 32-bit data to rotate
 276:    * @param s number of places to left-rotate by
 277:    * @return the newly permutated value.
 278:    */
 279:   private static int rot32L(int x, int s)
 280:   {
 281:     return x << s | x >>> (32 - s);
 282:   }
 283: 
 284:   /**
 285:    * Right rotate a 32-bit chunk.
 286:    *
 287:    * @param x the 32-bit data to rotate
 288:    * @param s number of places to right-rotate by
 289:    * @return the newly permutated value.
 290:    */
 291:   private static int rot32R(int x, int s)
 292:   {
 293:     return x >>> s | x << (32 - s);
 294:   }
 295: 
 296:   /**
 297:    * Returns the product of two binary numbers a and b, using the generator ROOT
 298:    * as the modulus: p = (a * b) mod ROOT. ROOT Generates a suitable Galois
 299:    * Field in GF(2**8).
 300:    * <p>
 301:    * For best performance call it with abs(b) &lt; abs(a).
 302:    *
 303:    * @param a operand for multiply.
 304:    * @param b operand for multiply.
 305:    * @return the result of (a * b) % ROOT.
 306:    */
 307:   private static final int mul(int a, int b)
 308:   {
 309:     if (a == 0)
 310:       return 0;
 311:     a &= 0xFF;
 312:     b &= 0xFF;
 313:     int result = 0;
 314:     while (b != 0)
 315:       {
 316:         if ((b & 0x01) != 0)
 317:           result ^= a;
 318:         b >>>= 1;
 319:         a <<= 1;
 320:         if (a > 0xFF)
 321:           a ^= ROOT;
 322:       }
 323:     return result & 0xFF;
 324:   }
 325: 
 326:   public Object clone()
 327:   {
 328:     Square result = new Square();
 329:     result.currentBlockSize = this.currentBlockSize;
 330: 
 331:     return result;
 332:   }
 333: 
 334:   public Iterator blockSizes()
 335:   {
 336:     ArrayList al = new ArrayList();
 337:     al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE));
 338: 
 339:     return Collections.unmodifiableList(al).iterator();
 340:   }
 341: 
 342:   public Iterator keySizes()
 343:   {
 344:     ArrayList al = new ArrayList();
 345:     al.add(Integer.valueOf(DEFAULT_KEY_SIZE));
 346: 
 347:     return Collections.unmodifiableList(al).iterator();
 348:   }
 349: 
 350:   public Object makeKey(byte[] uk, int bs) throws InvalidKeyException
 351:   {
 352:     if (bs != DEFAULT_BLOCK_SIZE)
 353:       throw new IllegalArgumentException();
 354:     if (uk == null)
 355:       throw new InvalidKeyException("Empty key");
 356:     if (uk.length != DEFAULT_KEY_SIZE)
 357:       throw new InvalidKeyException("Key is not 128-bit.");
 358:     int[][] Ke = new int[ROUNDS + 1][4];
 359:     int[][] Kd = new int[ROUNDS + 1][4];
 360:     int[][] tK = new int[ROUNDS + 1][4];
 361:     int i = 0;
 362:     Ke[0][0] = (uk[i++] & 0xFF) << 24
 363:              | (uk[i++] & 0xFF) << 16
 364:              | (uk[i++] & 0xFF) << 8
 365:              | (uk[i++] & 0xFF);
 366:     tK[0][0] = Ke[0][0];
 367:     Ke[0][1] = (uk[i++] & 0xFF) << 24
 368:              | (uk[i++] & 0xFF) << 16
 369:              | (uk[i++] & 0xFF) << 8
 370:              | (uk[i++] & 0xFF);
 371:     tK[0][1] = Ke[0][1];
 372:     Ke[0][2] = (uk[i++] & 0xFF) << 24
 373:              | (uk[i++] & 0xFF) << 16
 374:              | (uk[i++] & 0xFF) << 8
 375:              | (uk[i++] & 0xFF);
 376:     tK[0][2] = Ke[0][2];
 377:     Ke[0][3] = (uk[i++] & 0xFF) << 24
 378:              | (uk[i++] & 0xFF) << 16
 379:              | (uk[i++] & 0xFF) << 8
 380:              | (uk[i  ] & 0xFF);
 381:     tK[0][3] = Ke[0][3];
 382:     int j;
 383:     for (i = 1, j = 0; i < ROUNDS + 1; i++, j++)
 384:       {
 385:         tK[i][0] = tK[j][0] ^ rot32L(tK[j][3], 8) ^ OFFSET[j];
 386:         tK[i][1] = tK[j][1] ^ tK[i][0];
 387:         tK[i][2] = tK[j][2] ^ tK[i][1];
 388:         tK[i][3] = tK[j][3] ^ tK[i][2];
 389:         System.arraycopy(tK[i], 0, Ke[i], 0, 4);
 390:         transform(Ke[j], Ke[j]);
 391:       }
 392:     for (i = 0; i < ROUNDS; i++)
 393:       System.arraycopy(tK[ROUNDS - i], 0, Kd[i], 0, 4);
 394:     transform(tK[0], Kd[ROUNDS]);
 395:     return new Object[] { Ke, Kd };
 396:   }
 397: 
 398:   public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
 399:   {
 400:     if (bs != DEFAULT_BLOCK_SIZE)
 401:       throw new IllegalArgumentException();
 402:     int[][] K = (int[][])((Object[]) k)[0];
 403:     square(in, i, out, j, K, Te, Se);
 404:   }
 405: 
 406:   public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
 407:   {
 408:     if (bs != DEFAULT_BLOCK_SIZE)
 409:       throw new IllegalArgumentException();
 410:     int[][] K = (int[][])((Object[]) k)[1];
 411:     square(in, i, out, j, K, Td, Sd);
 412:   }
 413: 
 414:   public boolean selfTest()
 415:   {
 416:     if (valid == null)
 417:       {
 418:         boolean result = super.selfTest(); // do symmetry tests
 419:         if (result)
 420:           result = testKat(KAT_KEY, KAT_CT);
 421:         valid = Boolean.valueOf(result);
 422:       }
 423:     return valid.booleanValue();
 424:   }
 425: }