| /* Square.java -- |
| Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. |
| |
| This file is a part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or (at |
| your option) any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 |
| USA |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package gnu.javax.crypto.cipher; |
| |
| import gnu.java.security.Registry; |
| import gnu.java.security.util.Util; |
| |
| import java.security.InvalidKeyException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Iterator; |
| |
| /** |
| * Square is a 128-bit key, 128-bit block cipher algorithm developed by Joan |
| * Daemen, Lars Knudsen and Vincent Rijmen. |
| * <p> |
| * References: |
| * <ol> |
| * <li><a href="http://www.esat.kuleuven.ac.be/~rijmen/square/">The block |
| * cipher Square</a>.<br> |
| * <a href="mailto:daemen.j@protonworld.com">Joan Daemen</a>, <a |
| * href="mailto:lars.knudsen@esat.kuleuven.ac.be">Lars Knudsen</a> and <a |
| * href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a>.</li> |
| * </ol> |
| */ |
| public final class Square |
| extends BaseCipher |
| { |
| private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes |
| private static final int DEFAULT_KEY_SIZE = 16; // in bytes |
| private static final int ROUNDS = 8; |
| private static final int ROOT = 0x1F5; // for generating GF(2**8) |
| private static final int[] OFFSET = new int[ROUNDS]; |
| private static final String Sdata = |
| "\uB1CE\uC395\u5AAD\uE702\u4D44\uFB91\u0C87\uA150" |
| + "\uCB67\u54DD\u468F\uE14E\uF0FD\uFCEB\uF9C4\u1A6E" |
| + "\u5EF5\uCC8D\u1C56\u43FE\u0761\uF875\u59FF\u0322" |
| + "\u8AD1\u13EE\u8800\u0E34\u1580\u94E3\uEDB5\u5323" |
| + "\u4B47\u17A7\u9035\uABD8\uB8DF\u4F57\u9A92\uDB1B" |
| + "\u3CC8\u9904\u8EE0\uD77D\u85BB\u402C\u3A45\uF142" |
| + "\u6520\u4118\u7225\u9370\u3605\uF20B\uA379\uEC08" |
| + "\u2731\u32B6\u7CB0\u0A73\u5B7B\uB781\uD20D\u6A26" |
| + "\u9E58\u9C83\u74B3\uAC30\u7A69\u770F\uAE21\uDED0" |
| + "\u2E97\u10A4\u98A8\uD468\u2D62\u296D\u1649\u76C7" |
| + "\uE8C1\u9637\uE5CA\uF4E9\u6312\uC2A6\u14BC\uD328" |
| + "\uAF2F\uE624\u52C6\uA009\uBD8C\uCF5D\u115F\u01C5" |
| + "\u9F3D\uA29B\uC93B\uBE51\u191F\u3F5C\uB2EF\u4ACD" |
| + "\uBFBA\u6F64\uD9F3\u3EB4\uAADC\uD506\uC07E\uF666" |
| + "\u6C84\u7138\uB91D\u7F9D\u488B\u2ADA\uA533\u8239" |
| + "\uD678\u86FA\uE42B\uA91E\u8960\u6BEA\u554C\uF7E2"; |
| /** Substitution boxes for encryption and decryption. */ |
| private static final byte[] Se = new byte[256]; |
| private static final byte[] Sd = new byte[256]; |
| /** Transposition boxes for encryption and decryption. */ |
| private static final int[] Te = new int[256]; |
| private static final int[] Td = new int[256]; |
| /** |
| * KAT vector (from ecb_vk): I=87 KEY=00000000000000000000020000000000 |
| * CT=A9DF031B4E25E89F527EFFF89CB0BEBA |
| */ |
| private static final byte[] KAT_KEY = |
| Util.toBytesFromString("00000000000000000000020000000000"); |
| private static final byte[] KAT_CT = |
| Util.toBytesFromString("A9DF031B4E25E89F527EFFF89CB0BEBA"); |
| /** caches the result of the correctness test, once executed. */ |
| private static Boolean valid; |
| static |
| { |
| int i, j; |
| // re-construct Se box values |
| int limit = Sdata.length(); |
| char c1; |
| for (i = 0, j = 0; i < limit; i++) |
| { |
| c1 = Sdata.charAt(i); |
| Se[j++] = (byte)(c1 >>> 8); |
| Se[j++] = (byte) c1; |
| } |
| // compute Sd box values |
| for (i = 0; i < 256; i++) |
| Sd[Se[i] & 0xFF] = (byte) i; |
| // generate OFFSET values |
| OFFSET[0] = 1; |
| for (i = 1; i < ROUNDS; i++) |
| { |
| OFFSET[i] = mul(OFFSET[i - 1], 2); |
| OFFSET[i - 1] <<= 24; |
| } |
| OFFSET[ROUNDS - 1] <<= 24; |
| // generate Te and Td boxes if we're not reading their values |
| // Notes: |
| // (1) The function mul() computes the product of two elements of GF(2**8) |
| // with ROOT as reduction polynomial. |
| // (2) the values used in computing the Te and Td are the GF(2**8) |
| // coefficients of the diffusion polynomial c(x) and its inverse |
| // (modulo x**4 + 1) d(x), defined in sections 2.1 and 4 of the Square |
| // paper. |
| for (i = 0; i < 256; i++) |
| { |
| j = Se[i] & 0xFF; |
| Te[i] = (Se[i & 3] == 0) ? 0 |
| : mul(j, 2) << 24 |
| | j << 16 |
| | j << 8 |
| | mul(j, 3); |
| j = Sd[i] & 0xFF; |
| Td[i] = (Sd[i & 3] == 0) ? 0 |
| : mul(j, 14) << 24 |
| | mul(j, 9) << 16 |
| | mul(j, 13) << 8 |
| | mul(j, 11); |
| } |
| } |
| |
| /** Trivial 0-arguments constructor. */ |
| public Square() |
| { |
| super(Registry.SQUARE_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); |
| } |
| |
| private static void square(byte[] in, int i, byte[] out, int j, int[][] K, |
| int[] T, byte[] S) |
| { |
| int a = ((in[i++]) << 24 |
| | (in[i++] & 0xFF) << 16 |
| | (in[i++] & 0xFF) << 8 |
| | (in[i++] & 0xFF) ) ^ K[0][0]; |
| int b = ((in[i++]) << 24 |
| | (in[i++] & 0xFF) << 16 |
| | (in[i++] & 0xFF) << 8 |
| | (in[i++] & 0xFF) ) ^ K[0][1]; |
| int c = ((in[i++]) << 24 |
| | (in[i++] & 0xFF) << 16 |
| | (in[i++] & 0xFF) << 8 |
| | (in[i++] & 0xFF) ) ^ K[0][2]; |
| int d = ((in[i++]) << 24 |
| | (in[i++] & 0xFF) << 16 |
| | (in[i++] & 0xFF) << 8 |
| | (in[i ] & 0xFF) ) ^ K[0][3]; |
| int r, aa, bb, cc, dd; |
| for (r = 1; r < ROUNDS; r++) |
| { // R - 1 full rounds |
| aa = T[(a >>> 24) ] |
| ^ rot32R(T[(b >>> 24) ], 8) |
| ^ rot32R(T[(c >>> 24) ], 16) |
| ^ rot32R(T[(d >>> 24) ], 24) ^ K[r][0]; |
| bb = T[(a >>> 16) & 0xFF] |
| ^ rot32R(T[(b >>> 16) & 0xFF], 8) |
| ^ rot32R(T[(c >>> 16) & 0xFF], 16) |
| ^ rot32R(T[(d >>> 16) & 0xFF], 24) ^ K[r][1]; |
| cc = T[(a >>> 8) & 0xFF] |
| ^ rot32R(T[(b >>> 8) & 0xFF], 8) |
| ^ rot32R(T[(c >>> 8) & 0xFF], 16) |
| ^ rot32R(T[(d >>> 8) & 0xFF], 24) ^ K[r][2]; |
| dd = T[ a & 0xFF] |
| ^ rot32R(T[ b & 0xFF], 8) |
| ^ rot32R(T[ c & 0xFF], 16) |
| ^ rot32R(T[ d & 0xFF], 24) ^ K[r][3]; |
| a = aa; |
| b = bb; |
| c = cc; |
| d = dd; |
| } |
| // last round (diffusion becomes only transposition) |
| aa = ((S[(a >>> 24) ] ) << 24 |
| | (S[(b >>> 24) ] & 0xFF) << 16 |
| | (S[(c >>> 24) ] & 0xFF) << 8 |
| | (S[(d >>> 24) ] & 0xFF) ) ^ K[r][0]; |
| bb = ((S[(a >>> 16) & 0xFF] ) << 24 |
| | (S[(b >>> 16) & 0xFF] & 0xFF) << 16 |
| | (S[(c >>> 16) & 0xFF] & 0xFF) << 8 |
| | (S[(d >>> 16) & 0xFF] & 0xFF) ) ^ K[r][1]; |
| cc = ((S[(a >>> 8) & 0xFF] ) << 24 |
| | (S[(b >>> 8) & 0xFF] & 0xFF) << 16 |
| | (S[(c >>> 8) & 0xFF] & 0xFF) << 8 |
| | (S[(d >>> 8) & 0xFF] & 0xFF) ) ^ K[r][2]; |
| dd = ((S[ a & 0xFF] ) << 24 |
| | (S[ b & 0xFF] & 0xFF) << 16 |
| | (S[ c & 0xFF] & 0xFF) << 8 |
| | (S[ d & 0xFF] & 0xFF) ) ^ K[r][3]; |
| out[j++] = (byte)(aa >>> 24); |
| out[j++] = (byte)(aa >>> 16); |
| out[j++] = (byte)(aa >>> 8); |
| out[j++] = (byte) aa; |
| out[j++] = (byte)(bb >>> 24); |
| out[j++] = (byte)(bb >>> 16); |
| out[j++] = (byte)(bb >>> 8); |
| out[j++] = (byte) bb; |
| out[j++] = (byte)(cc >>> 24); |
| out[j++] = (byte)(cc >>> 16); |
| out[j++] = (byte)(cc >>> 8); |
| out[j++] = (byte) cc; |
| out[j++] = (byte)(dd >>> 24); |
| out[j++] = (byte)(dd >>> 16); |
| out[j++] = (byte)(dd >>> 8); |
| out[j ] = (byte) dd; |
| } |
| |
| /** |
| * Applies the Theta function to an input <i>in</i> in order to produce in |
| * <i>out</i> an internal session sub-key. |
| * <p> |
| * Both <i>in</i> and <i>out</i> are arrays of four ints. |
| * <p> |
| * Pseudo-code is: |
| * <pre> |
| * for (i = 0; i < 4; i++) |
| * { |
| * out[i] = 0; |
| * for (j = 0, n = 24; j < 4; j++, n -= 8) |
| * { |
| * k = mul(in[i] >>> 24, G[0][j]) ˆ mul(in[i] >>> 16, G[1][j]) |
| * ˆ mul(in[i] >>> 8, G[2][j]) ˆ mul(in[i], G[3][j]); |
| * out[i] ˆ= k << n; |
| * } |
| * } |
| * </pre> |
| */ |
| private static void transform(int[] in, int[] out) |
| { |
| int l3, l2, l1, l0, m; |
| for (int i = 0; i < 4; i++) |
| { |
| l3 = in[i]; |
| l2 = l3 >>> 8; |
| l1 = l3 >>> 16; |
| l0 = l3 >>> 24; |
| m = ((mul(l0, 2) ^ mul(l1, 3) ^ l2 ^ l3) & 0xFF) << 24; |
| m ^= ((l0 ^ mul(l1, 2) ^ mul(l2, 3) ^ l3) & 0xFF) << 16; |
| m ^= ((l0 ^ l1 ^ mul(l2, 2) ^ mul(l3, 3)) & 0xFF) << 8; |
| m ^= ((mul(l0, 3) ^ l1 ^ l2 ^ mul(l3, 2)) & 0xFF); |
| out[i] = m; |
| } |
| } |
| |
| /** |
| * Left rotate a 32-bit chunk. |
| * |
| * @param x the 32-bit data to rotate |
| * @param s number of places to left-rotate by |
| * @return the newly permutated value. |
| */ |
| private static int rot32L(int x, int s) |
| { |
| return x << s | x >>> (32 - s); |
| } |
| |
| /** |
| * Right rotate a 32-bit chunk. |
| * |
| * @param x the 32-bit data to rotate |
| * @param s number of places to right-rotate by |
| * @return the newly permutated value. |
| */ |
| private static int rot32R(int x, int s) |
| { |
| return x >>> s | x << (32 - s); |
| } |
| |
| /** |
| * Returns the product of two binary numbers a and b, using the generator ROOT |
| * as the modulus: p = (a * b) mod ROOT. ROOT Generates a suitable Galois |
| * Field in GF(2**8). |
| * <p> |
| * For best performance call it with abs(b) < abs(a). |
| * |
| * @param a operand for multiply. |
| * @param b operand for multiply. |
| * @return the result of (a * b) % ROOT. |
| */ |
| private static final int mul(int a, int b) |
| { |
| if (a == 0) |
| return 0; |
| a &= 0xFF; |
| b &= 0xFF; |
| int result = 0; |
| while (b != 0) |
| { |
| if ((b & 0x01) != 0) |
| result ^= a; |
| b >>>= 1; |
| a <<= 1; |
| if (a > 0xFF) |
| a ^= ROOT; |
| } |
| return result & 0xFF; |
| } |
| |
| public Object clone() |
| { |
| Square result = new Square(); |
| result.currentBlockSize = this.currentBlockSize; |
| |
| return result; |
| } |
| |
| public Iterator blockSizes() |
| { |
| ArrayList al = new ArrayList(); |
| al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE)); |
| |
| return Collections.unmodifiableList(al).iterator(); |
| } |
| |
| public Iterator keySizes() |
| { |
| ArrayList al = new ArrayList(); |
| al.add(Integer.valueOf(DEFAULT_KEY_SIZE)); |
| |
| return Collections.unmodifiableList(al).iterator(); |
| } |
| |
| public Object makeKey(byte[] uk, int bs) throws InvalidKeyException |
| { |
| if (bs != DEFAULT_BLOCK_SIZE) |
| throw new IllegalArgumentException(); |
| if (uk == null) |
| throw new InvalidKeyException("Empty key"); |
| if (uk.length != DEFAULT_KEY_SIZE) |
| throw new InvalidKeyException("Key is not 128-bit."); |
| int[][] Ke = new int[ROUNDS + 1][4]; |
| int[][] Kd = new int[ROUNDS + 1][4]; |
| int[][] tK = new int[ROUNDS + 1][4]; |
| int i = 0; |
| Ke[0][0] = (uk[i++] & 0xFF) << 24 |
| | (uk[i++] & 0xFF) << 16 |
| | (uk[i++] & 0xFF) << 8 |
| | (uk[i++] & 0xFF); |
| tK[0][0] = Ke[0][0]; |
| Ke[0][1] = (uk[i++] & 0xFF) << 24 |
| | (uk[i++] & 0xFF) << 16 |
| | (uk[i++] & 0xFF) << 8 |
| | (uk[i++] & 0xFF); |
| tK[0][1] = Ke[0][1]; |
| Ke[0][2] = (uk[i++] & 0xFF) << 24 |
| | (uk[i++] & 0xFF) << 16 |
| | (uk[i++] & 0xFF) << 8 |
| | (uk[i++] & 0xFF); |
| tK[0][2] = Ke[0][2]; |
| Ke[0][3] = (uk[i++] & 0xFF) << 24 |
| | (uk[i++] & 0xFF) << 16 |
| | (uk[i++] & 0xFF) << 8 |
| | (uk[i ] & 0xFF); |
| tK[0][3] = Ke[0][3]; |
| int j; |
| for (i = 1, j = 0; i < ROUNDS + 1; i++, j++) |
| { |
| tK[i][0] = tK[j][0] ^ rot32L(tK[j][3], 8) ^ OFFSET[j]; |
| tK[i][1] = tK[j][1] ^ tK[i][0]; |
| tK[i][2] = tK[j][2] ^ tK[i][1]; |
| tK[i][3] = tK[j][3] ^ tK[i][2]; |
| System.arraycopy(tK[i], 0, Ke[i], 0, 4); |
| transform(Ke[j], Ke[j]); |
| } |
| for (i = 0; i < ROUNDS; i++) |
| System.arraycopy(tK[ROUNDS - i], 0, Kd[i], 0, 4); |
| transform(tK[0], Kd[ROUNDS]); |
| return new Object[] { Ke, Kd }; |
| } |
| |
| public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) |
| { |
| if (bs != DEFAULT_BLOCK_SIZE) |
| throw new IllegalArgumentException(); |
| int[][] K = (int[][])((Object[]) k)[0]; |
| square(in, i, out, j, K, Te, Se); |
| } |
| |
| public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) |
| { |
| if (bs != DEFAULT_BLOCK_SIZE) |
| throw new IllegalArgumentException(); |
| int[][] K = (int[][])((Object[]) k)[1]; |
| square(in, i, out, j, K, Td, Sd); |
| } |
| |
| public boolean selfTest() |
| { |
| if (valid == null) |
| { |
| boolean result = super.selfTest(); // do symmetry tests |
| if (result) |
| result = testKat(KAT_KEY, KAT_CT); |
| valid = Boolean.valueOf(result); |
| } |
| return valid.booleanValue(); |
| } |
| } |