📄 square.java
字号:
public final Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); }// Implementation of JCE methods//............................................................................ /** * <b>SPI</b>: Returns the length of an input block, in bytes. * * @return the length in bytes of an input block for this cipher. */ public int engineBlockSize() { return BLOCK_SIZE; } /** * <b>SPI</b>: Initializes this cipher for encryption, using the * specified key. * * @param key the key to use for encryption. * @exception InvalidKeyException when one of the following occurs: <ul> * <li> key.getEncoded() == null; * <li> The encoded byte array form of the key is zero-length; * <li> The length of the user key data array is out of the * permissible limits. * </ul> */ protected void engineInitEncrypt(Key key) throws InvalidKeyException { makeKey(key, true); } /** * <b>SPI</b>: Initializes this cipher for decryption, using the * specified key. * * @param key the key to use for decryption. * @exception InvalidKeyException when one of the following occurs: <ul> * <li> key.getEncoded() == null; * <li> The encoded byte array form of the key is zero-length; * <li> The length of the user key data array is out of the * permissible limits. * </ul> */ protected void engineInitDecrypt(Key key) throws InvalidKeyException { makeKey(key, false); } /** * <b>SPI</b>: This is the main engine method for updating data. * <p> * <i>in</i> and <i>out</i> may be the same array, and the input and output * regions may overlap. * * @param in the input data. * @param inOffset the offset into in specifying where the data starts. * @param inLen the length of the subarray. * @param out the output array. * @param outOffset the offset indicating where to start writing into * the out array. * @return the number of bytes written. * @exception CryptixException if the native library is being used, and it * reports an error. */ protected int engineUpdate(byte[] in, int inOffset, int inLen, byte[] out, int outOffset) { if (inLen < 0) throw new IllegalArgumentException("inLen < 0"); int blockCount = inLen / BLOCK_SIZE; inLen = blockCount * BLOCK_SIZE; boolean doEncrypt = (getState() == ENCRYPT); // Avoid overlapping input and output regions. if (in == out && (outOffset >= inOffset && outOffset < (long)inOffset+inLen || inOffset >= outOffset && inOffset < (long)outOffset+inLen)) { byte[] newin = new byte[inLen]; System.arraycopy(in, inOffset, newin, 0, inLen); in = newin; inOffset = 0; } if (native_lock != null) { synchronized(native_lock) { // If in == null || out == 0, evaluating their lengths will throw a // NullPointerException. if (inOffset < 0 || (long)inOffset + inLen > in.length || outOffset < 0 || (long)outOffset + inLen > out.length) throw new ArrayIndexOutOfBoundsException(getAlgorithm() + ": Arguments to native_crypt would cause a buffer overflow"); // In future, we may pass more than one block to native_crypt to reduce // native method overhead. for (int i = 0; i < blockCount; i++) { if (0 == native_crypt(native_cookie, in, inOffset, out, outOffset, doEncrypt)) throw new CryptixException(getAlgorithm() + ": Error in native code"); inOffset += BLOCK_SIZE; outOffset += BLOCK_SIZE; } } } else if (doEncrypt) { // state == ENCRYPT for (int i = 0; i < blockCount; i++) { square(in, inOffset, out, outOffset, TE, SE); inOffset += BLOCK_SIZE; outOffset += BLOCK_SIZE; } } else { // state == DECRYPT for (int i = 0; i < blockCount; i++) { square(in, inOffset, out, outOffset, TD, SD); inOffset += BLOCK_SIZE; outOffset += BLOCK_SIZE; } } return inLen; }// Own methods//............................................................................ /** * Expands a user-key to a working key schedule. * * @param key the user-key object to use. * @param doEncrypt true for encryption, false for decryption. * @exception InvalidKeyException if one of the following occurs: <ul> * <li> key.getEncoded() == null; * <li> The length of the user key array is not KEY_LENGTH. * </ul> */ private void makeKey(Key key, boolean doEncrypt) throws InvalidKeyException { byte[] userkey = key.getEncoded(); if (userkey == null) throw new InvalidKeyException(getAlgorithm() + ": Null user key"); if (userkey.length != BLOCK_SIZE) throw new InvalidKeyException(getAlgorithm() + ": Invalid user key length"); // If native library available then use it. If not or if // native method returned error then revert to 100% Java. if (native_lock != null) { synchronized(native_lock) { try {// linkStatus.check(native_ks(native_cookie, userkey, doEncrypt)); linkStatus.check(native_ks(native_cookie, userkey)); return; } catch (Error error) { native_finalize(); native_lock = null;if (DEBUG && debuglevel > 0) debug(error + ". Will use 100% Java."); } } } int i, j = 0; if (doEncrypt) { for (i = 0; i < 4; i++) sKey[0][i] = (userkey[j++] & 0xFF) << 24 | (userkey[j++] & 0xFF) << 16 | (userkey[j++] & 0xFF) << 8 | (userkey[j++] & 0xFF); for (i = 1; i < R + 1; i++) { j = i - 1; sKey[i][0] = sKey[j][0] ^ rot32L(sKey[j][3], 8) ^ OFFSET[j]; sKey[i][1] = sKey[j][1] ^ sKey[i][0]; sKey[i][2] = sKey[j][2] ^ sKey[i][1]; sKey[i][3] = sKey[j][3] ^ sKey[i][2]; transform(sKey[j], sKey[j]); } } else { int[][] tKey = new int[R + 1][4]; // apply the key evolution function for (i = 0; i < 4; i++) tKey[0][i] = (userkey[j++] & 0xFF) << 24 | (userkey[j++] & 0xFF) << 16 | (userkey[j++] & 0xFF) << 8 | (userkey[j++] & 0xFF); for (i = 1; i < R + 1; i++) { j = i - 1; tKey[i][0] = tKey[j][0] ^ rot32L(tKey[j][3], 8) ^ OFFSET[j]; tKey[i][1] = tKey[j][1] ^ tKey[i][0]; tKey[i][2] = tKey[j][2] ^ tKey[i][1]; tKey[i][3] = tKey[j][3] ^ tKey[i][2]; } for (i = 0; i < R; i++) System.arraycopy(tKey[R - i], 0, sKey[i], 0, 4); transform(tKey[0], sKey[R]); } } /** * 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 p = 0; while (b != 0) { if ((b & 0x01) != 0) p ^= a; a <<= 1; if (a > 0xFF) a ^= ROOT; b >>>= 1; } return p & 0xFF; } /** * Applies the Square algorithm (for both encryption and decryption since * it is the same) on a 128-bit plain/cipher text into a same length cipher/ * plain text using the Square formulae, relevant sub-keys, transposition * and S-Box values. * * @param in contains the plain-text 128-bit block. * @param off start index within input where data is considered. * @param out will contain the cipher-text block. * @param outOff index in out where cipher-text starts. * @param T reference to either the encryption (TE) or decryption * (TD) transposition vector. * @param S reference to either the encryption (SE) or decryption * (SD) S-Box values. */ private void square (byte[] in, int off, byte[] out, int outOff, int[] T, byte[] S) { int a = (in[off++] & 0xFF) << 24 | (in[off++] & 0xFF) << 16 | (in[off++] & 0xFF) << 8 | (in[off++] & 0xFF); int b = (in[off++] & 0xFF) << 24 | (in[off++] & 0xFF) << 16 | (in[off++] & 0xFF) << 8 | (in[off++] & 0xFF); int c = (in[off++] & 0xFF) << 24 | (in[off++] & 0xFF) << 16 | (in[off++] & 0xFF) << 8 | (in[off++] & 0xFF); int d = (in[off++] & 0xFF) << 24 | (in[off++] & 0xFF) << 16 | (in[off++] & 0xFF) << 8 | (in[off++] & 0xFF); int aa, bb, cc, dd; int i, j, k; a ^= sKey[0][0]; b ^= sKey[0][1]; c ^= sKey[0][2]; d ^= sKey[0][3]; // R - 1 full rounds for (i = 1; i < R; i++) { aa = T[(a >>> 24) & 0xFF] ^ rot32R(T[(b >>> 24) & 0xFF], 8) ^ rot32R(T[(c >>> 24) & 0xFF], 16) ^ rot32R(T[(d >>> 24) & 0xFF], 24) ^ sKey[i][0]; bb = T[(a >>> 16) & 0xFF] ^ rot32R(T[(b >>> 16) & 0xFF], 8) ^ rot32R(T[(c >>> 16) & 0xFF], 16) ^ rot32R(T[(d >>> 16) & 0xFF], 24) ^ sKey[i][1]; cc = T[(a >>> 8) & 0xFF] ^ rot32R(T[(b >>> 8) & 0xFF], 8) ^ rot32R(T[(c >>> 8) & 0xFF], 16) ^ rot32R(T[(d >>> 8) & 0xFF], 24) ^ sKey[i][2]; dd = T[ a & 0xFF] ^ rot32R(T[ b & 0xFF], 8) ^ rot32R(T[ c & 0xFF], 16) ^ rot32R(T[ d & 0xFF], 24) ^ sKey[i][3]; a = aa; b = bb; c = cc; d = dd; } // last round (diffusion becomes only transposition) for (i = 0, j = 24; i < 4; i++, j -= 8) { k = (S[(a >>> j) & 0xFF] & 0xFF) << 24 | (S[(b >>> j) & 0xFF] & 0xFF) << 16 | (S[(c >>> j) & 0xFF] & 0xFF) << 8 | (S[(d >>> j) & 0xFF] & 0xFF); k ^= sKey[R][i]; out[outOff++] = (byte)((k >>> 24) & 0xFF); out[outOff++] = (byte)((k >>> 16) & 0xFF); out[outOff++] = (byte)((k >>> 8) & 0xFF); out[outOff++] = (byte) (k & 0xFF); } }// Test methods//........................................................................... static final private String[][] tests = { { "000102030405060708090a0b0c0d0e0f", // KEY "000102030405060708090a0b0c0d0e0f", // PLAINTEXT "7C3491D94994E70F0EC2E7A5CCB5A14F"}, // CIPHERTEXT { "000102030405060708090a0b0c0d0e0f", "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f", "7C3491D94994E70F0EC2E7A5CCB5A14F7C3491D94994E70F0EC2E7A5CCB5A14F"} }; public static final void main (String[] args) { try { self_test(); } catch (Exception e) { e.printStackTrace(); } } private static void self_test() throws Exception { Cipher cryptor = Cipher.getInstance("Square", "Cryptix"); RawSecretKey userKey; byte[] tmp, pt, ct; for (int i = 0; i < tests.length; i++) { userKey = new RawSecretKey("Square", Hex.fromString(tests[i][0])); pt = Hex.fromString(tests[i][1]); ct = Hex.fromString(tests[i][2]); cryptor.initEncrypt(userKey); tmp = cryptor.crypt(pt); if (!ArrayUtil.areEqual(ct, tmp)) { System.out.println(" input: " + Hex.toString(pt)); System.out.println(" computed: " + Hex.toString(tmp)); System.out.println(" certified: " + Hex.toString(ct)); throw new CryptixException("encrypt #"+ i +" failed"); } cryptor.initDecrypt(userKey); tmp = cryptor.crypt(ct); if (!ArrayUtil.areEqual(pt, tmp)) throw new CryptixException("decrypt #"+ i +" failed"); }if (DEBUG && debuglevel > 0) debug("Self-test OK"); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -