📄 twofish.java
字号:
/****************************************************************************** * * Copyright (c) 1999-2003 AppGate Network Security AB. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code as * defined in and that are subject to the MindTerm Public Source License, * Version 2.0, (the 'License'). You may not use this file except in compliance * with the License. * * You should have received a copy of the MindTerm Public Source License * along with this software; see the file LICENSE. If not, write to * AppGate Network Security AB, Otterhallegatan 2, SE-41118 Goteborg, SWEDEN * *****************************************************************************//* * Author's comment: The contents of this file is heavily based upon * the (free) public implementation from Counterpane Systems found here: * http://www.counterpane.com/download-twofish.html * * Twofish is an AES candidate algorithm. It is a balanced 128-bit Feistel * cipher, consisting of 16 rounds. In each round, a 64-bit S-box value is * computed from 64 bits of the block, and this value is xored into the other * half of the block. The two half-blocks are then exchanged, and the next round * begins. Before the first round, all input bits are xored with key- dependent * "whitening" subkeys, and after the final round the output bits are xored with * other key-dependent whitening subkeys; these subkeys are not used anywhere * else in the algorithm.<p> * * Twofish was submitted by Bruce Schneier, Doug Whiting, John Kelsey, Chris * Hall and David Wagner.<p> */package com.mindbright.security.cipher;import com.mindbright.jca.security.InvalidKeyException;public final class Twofish extends BlockCipher { private int[] sBox; private int[] subKeys; public Twofish() { } public int getBlockSize() { return BLOCK_SIZE; } /** * Expand a user-supplied key material into a session key. * * @param key The 64/128/192/256-bit user-key to use. * @exception InvalidKeyException If the key is invalid. */ public synchronized void initializeKey(byte[] key) throws InvalidKeyException { if (key == null) throw new InvalidKeyException("Empty key"); int length = key.length; if (!(length == 8 || length == 16 || length == 24 || length == 32)) throw new InvalidKeyException("Incorrect key length"); int k64Cnt = length / 8; int subkeyCnt = ROUND_SUBKEYS + 2*ROUNDS; int[] k32e = new int[4]; // even 32-bit entities int[] k32o = new int[4]; // odd 32-bit entities int[] sBoxKey = new int[4]; // // split user key material into even and odd 32-bit entities and // compute S-box keys using (12, 8) Reed-Solomon code over GF(256) // int i, j, offset = 0; for (i = 0, j = k64Cnt-1; i < 4 && offset < length; i++, j--) { k32e[i] = getIntLSBO(key, offset); offset += 4; k32o[i] = getIntLSBO(key, offset); offset += 4; sBoxKey[j] = RS_MDS_Encode( k32e[i], k32o[i] ); // reverse order } // compute the round decryption subkeys for PHT. these same subkeys // will be used in encryption but will be applied in reverse order. int q, A, B; subKeys = new int[subkeyCnt]; for (i = q = 0; i < subkeyCnt/2; i++, q += SK_STEP) { A = F32( k64Cnt, q , k32e ); // A uses even key entities B = F32( k64Cnt, q+SK_BUMP, k32o ); // B uses odd key entities B = B << 8 | B >>> 24; A += B; subKeys[2*i ] = A; // combine with a PHT A += B; subKeys[2*i + 1] = A << SK_ROTL | A >>> (32-SK_ROTL); } // // fully expand the table for speed // int k0 = sBoxKey[0]; int k1 = sBoxKey[1]; int k2 = sBoxKey[2]; int k3 = sBoxKey[3]; int b0, b1, b2, b3; sBox = new int[4 * 256]; for (i = 0; i < 256; i++) { b0 = b1 = b2 = b3 = i; switch (k64Cnt & 3) { case 1: sBox[ 2*i ] = MDS[0][(P[P_01][b0] & 0xFF) ^ b0(k0)]; sBox[ 2*i+1] = MDS[1][(P[P_11][b1] & 0xFF) ^ b1(k0)]; sBox[0x200+2*i ] = MDS[2][(P[P_21][b2] & 0xFF) ^ b2(k0)]; sBox[0x200+2*i+1] = MDS[3][(P[P_31][b3] & 0xFF) ^ b3(k0)]; break; case 0: // same as 4 b0 = (P[P_04][b0] & 0xFF) ^ b0(k3); b1 = (P[P_14][b1] & 0xFF) ^ b1(k3); b2 = (P[P_24][b2] & 0xFF) ^ b2(k3); b3 = (P[P_34][b3] & 0xFF) ^ b3(k3); case 3: b0 = (P[P_03][b0] & 0xFF) ^ b0(k2); b1 = (P[P_13][b1] & 0xFF) ^ b1(k2); b2 = (P[P_23][b2] & 0xFF) ^ b2(k2); b3 = (P[P_33][b3] & 0xFF) ^ b3(k2); case 2: // 128-bit keys sBox[ 2*i ] = MDS[0][(P[P_01][(P[P_02][b0] & 0xFF) ^ b0(k1)] & 0xFF) ^ b0(k0)]; sBox[ 2*i+1] = MDS[1][(P[P_11][(P[P_12][b1] & 0xFF) ^ b1(k1)] & 0xFF) ^ b1(k0)]; sBox[0x200+2*i ] = MDS[2][(P[P_21][(P[P_22][b2] & 0xFF) ^ b2(k1)] & 0xFF) ^ b2(k0)]; sBox[0x200+2*i+1] = MDS[3][(P[P_31][(P[P_32][b3] & 0xFF) ^ b3(k1)] & 0xFF) ^ b3(k0)]; } } } /** * Encrypt exactly one block of plaintext. * * @param in The plaintext. * @param inOffset Index of in from which to start considering data. * @param out The ciphertext generated from a plaintext. * @param outOffset Index of out into which to start putting data. */ public void blockEncrypt(byte[] in, int inOffset, byte[] out, int outOffset) { int x0 = getIntLSBO(in, inOffset); int x1 = getIntLSBO(in, inOffset + 4); int x2 = getIntLSBO(in, inOffset + 8); int x3 = getIntLSBO(in, inOffset + 12); x0 ^= subKeys[INPUT_WHITEN ]; x1 ^= subKeys[INPUT_WHITEN + 1]; x2 ^= subKeys[INPUT_WHITEN + 2]; x3 ^= subKeys[INPUT_WHITEN + 3]; int t0, t1; int k = ROUND_SUBKEYS; for (int R = 0; R < ROUNDS; R += 2) { t0 = Fe32( sBox, x0, 0 ); t1 = Fe32( sBox, x1, 3 ); x2 ^= t0 + t1 + subKeys[k++]; x2 = x2 >>> 1 | x2 << 31; x3 = x3 << 1 | x3 >>> 31; x3 ^= t0 + 2*t1 + subKeys[k++]; t0 = Fe32( sBox, x2, 0 ); t1 = Fe32( sBox, x3, 3 ); x0 ^= t0 + t1 + subKeys[k++]; x0 = x0 >>> 1 | x0 << 31; x1 = x1 << 1 | x1 >>> 31; x1 ^= t0 + 2*t1 + subKeys[k++]; } x2 ^= subKeys[OUTPUT_WHITEN ]; x3 ^= subKeys[OUTPUT_WHITEN + 1]; x0 ^= subKeys[OUTPUT_WHITEN + 2]; x1 ^= subKeys[OUTPUT_WHITEN + 3]; putIntLSBO(x2, out, outOffset); putIntLSBO(x3, out, outOffset + 4); putIntLSBO(x0, out, outOffset + 8); putIntLSBO(x1, out, outOffset + 12); } /** * Decrypt exactly one block of ciphertext. * * @param in The ciphertext. * @param inOffset Index of in from which to start considering data. * @param out The plaintext generated from a ciphertext. * @param outOffset Index of out into which to start putting data. */ public void blockDecrypt(byte[] in, int inOffset, byte[] out, int outOffset) { int x2 = getIntLSBO(in, inOffset); int x3 = getIntLSBO(in, inOffset + 4); int x0 = getIntLSBO(in, inOffset + 8); int x1 = getIntLSBO(in, inOffset + 12); x2 ^= subKeys[OUTPUT_WHITEN ]; x3 ^= subKeys[OUTPUT_WHITEN + 1]; x0 ^= subKeys[OUTPUT_WHITEN + 2]; x1 ^= subKeys[OUTPUT_WHITEN + 3]; int k = ROUND_SUBKEYS + 2*ROUNDS - 1; int t0, t1; for (int R = 0; R < ROUNDS; R += 2) { t0 = Fe32( sBox, x2, 0 ); t1 = Fe32( sBox, x3, 3 ); x1 ^= t0 + 2*t1 + subKeys[k--]; x1 = x1 >>> 1 | x1 << 31; x0 = x0 << 1 | x0 >>> 31; x0 ^= t0 + t1 + subKeys[k--]; t0 = Fe32( sBox, x0, 0 ); t1 = Fe32( sBox, x1, 3 ); x3 ^= t0 + 2*t1 + subKeys[k--]; x3 = x3 >>> 1 | x3 << 31; x2 = x2 << 1 | x2 >>> 31; x2 ^= t0 + t1 + subKeys[k--]; } x0 ^= subKeys[INPUT_WHITEN ]; x1 ^= subKeys[INPUT_WHITEN + 1]; x2 ^= subKeys[INPUT_WHITEN + 2]; x3 ^= subKeys[INPUT_WHITEN + 3]; putIntLSBO(x0, out, outOffset); putIntLSBO(x1, out, outOffset + 4); putIntLSBO(x2, out, outOffset + 8); putIntLSBO(x3, out, outOffset + 12); } // // // private final static int BLOCK_SIZE = 16; // bytes in a data-block private final static int ROUNDS = 16; /* Subkey array indices */ private static final int INPUT_WHITEN = 0; private static final int OUTPUT_WHITEN = INPUT_WHITEN + BLOCK_SIZE/4; private static final int ROUND_SUBKEYS = OUTPUT_WHITEN + BLOCK_SIZE/4; // 2*(# rounds) private static final int SK_STEP = 0x02020202; private static final int SK_BUMP = 0x01010101; private static final int SK_ROTL = 9; /** * Define the fixed p0/p1 permutations used in keyed S-box lookup. * By changing the following constant definitions, the S-boxes will * automatically get changed in the Twofish engine. */ private static final int P_00 = 1; private static final int P_01 = 0; private static final int P_02 = 0; private static final int P_03 = P_01 ^ 1; private static final int P_04 = 1; private static final int P_10 = 0; private static final int P_11 = 0; private static final int P_12 = 1; private static final int P_13 = P_11 ^ 1; private static final int P_14 = 0; private static final int P_20 = 1; private static final int P_21 = 1; private static final int P_22 = 0; private static final int P_23 = P_21 ^ 1; private static final int P_24 = 0; private static final int P_30 = 0; private static final int P_31 = 1; private static final int P_32 = 1; private static final int P_33 = P_31 ^ 1; private static final int P_34 = 1; /** Primitive polynomial for GF(256) */ private static final int GF256_FDBK_2 = 0x169 / 2; private static final int GF256_FDBK_4 = 0x169 / 4; /** MDS matrix */ private static final int[][] MDS = new int[4][256]; // blank final private static final int RS_GF_FDBK = 0x14D; // field generator /** Fixed 8x8 permutation S-boxes */ private static final byte[][] P = new byte[][] { { // p0 (byte) 0xA9, (byte) 0x67, (byte) 0xB3, (byte) 0xE8, (byte) 0x04, (byte) 0xFD, (byte) 0xA3, (byte) 0x76, (byte) 0x9A, (byte) 0x92, (byte) 0x80, (byte) 0x78, (byte) 0xE4, (byte) 0xDD, (byte) 0xD1, (byte) 0x38, (byte) 0x0D, (byte) 0xC6, (byte) 0x35, (byte) 0x98,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -