📄 twofish.java
字号:
* the result in the provided buffer starting at the given offset.
* The input will be an exact multiple of our blocksize.
*/
protected int encryptBlock(
byte[] src,
int srcIndex,
int len,
byte[] dst,
int dstIndex)
throws IllegalBlockSizeException
{
if (len != TF_BLOCK_SIZE)
{
throw new IllegalBlockSizeException("Datasize less than block size.");
}
int[] x = new int[TF_BLOCK_SIZE / 4];
/*
* copy in the block, add whitening
*/
for (int i = 0; i < TF_BLOCK_SIZE / 4; i++)
{
x[i] = src[srcIndex++] & 0xFF
| (src[srcIndex++] & 0xFF) << 8
| (src[srcIndex++] & 0xFF) << 16
| (src[srcIndex++] & 0xFF) << 24;
x[i] ^= subKeys[INPUT_WHITEN + i];
}
/*
* main Twofish encryption loop
*/
for (int i = 0; i < ROUNDS; i++)
{
int t0, t1;
t0 = f32(x[0], sBoxKeys, k64Cnt);
t1 = f32(x[1] << 8 | x[1] >>> 24, sBoxKeys, k64Cnt);
// System.out.println("t0=" + Integer.toHexString(t0) + ".\tt1=" + Integer.toHexString(t1));
x[3] = x[3] << 1 | x[3] >>> 31;
// PHT, round keys
x[2] ^= t0 + t1 + subKeys[ROUND_SUBKEYS+2*i];
x[3] ^= t0 + 2*t1 + subKeys[ROUND_SUBKEYS+2*i+1];
x[2] = x[2] << 31 | x[2] >>> 1;
/* swap for next round */
if (i < ROUNDS - 1)
{
int tmp;
tmp = x[0]; x[0] = x[2]; x[2] = tmp;
tmp = x[1]; x[1] = x[3]; x[3] = tmp;
}
}
/*
* copy out the block, with whitening
*/
for (int i = 0; i < TF_BLOCK_SIZE / 4; i++)
{
x[i] ^= subKeys[OUTPUT_WHITEN + i];
dst[dstIndex++] = (byte)b0(x[i]);
dst[dstIndex++] = (byte)b1(x[i]);
dst[dstIndex++] = (byte)b2(x[i]);
dst[dstIndex++] = (byte)b3(x[i]);
}
return TF_BLOCK_SIZE;
}
/**
* Returns the block size (in bytes).
*
* @return the block size (in bytes) of the cipher.
*/
protected int engineGetBlockSize()
{
return TF_BLOCK_SIZE;
}
/**
* Sets the padding mechanism of this cipher.
*
* @param padding the name of the type of padding to be applied,
* currently "PKCS7Padding", and "NoPadding" will
* be accepted.
* @exception NoSuchPaddingException if the padding type is unknown.
*/
protected void engineSetPadding(
String padding)
throws NoSuchPaddingException
{
if (padding.equals("PKCS7Padding"))
{
paddedStream = true;
}
else if (padding.equals("NoPadding"))
{
paddedStream = false;
}
else
{
throw new NoSuchPaddingException(
"Twofish only supports PKCS7 padding.");
}
}
/**
* Run four bytes through keyed S-boxes and apply MDS matrix.
*
* <p>This function is a keyed 32-bit permutation. It is the
* major building block for the Twofish round function,
* including the four keyed 8x8 permutations and the 4x4 MDS
* matrix multiply. This function is used both for generating
* round subkeys and within the round function on the block
* being encrypted.
*
* @param x input to f function
* @param k32 pointer to key values
* @returns The output of the keyed permutation applied to x.
*/
final static int f32(
int x,
int[] k32,
int k64len)
{
int[] b = new int[4];
/*
* Run each byte thru 8x8 S-boxes, xoring with key byte
* at each stage. Note that each byte goes through a
* different combination of S-boxes.
*/
/*
* make b[0] = LSB, b[3] = MSB
*/
b[0] = b0(x);
b[1] = b1(x);
b[2] = b2(x);
b[3] = b3(x);
// System.out.println(Integer.toHexString(b[0]) + " " + Integer.toHexString(b[1]) + " " + Integer.toHexString(b[2]) + " " + Integer.toHexString(b[3]) + " ");
switch (k64len & 3)
{
case 0: /* 256 bits of key */
b[0] = (P[P_04][b[0]] & 0xFF) ^ b0(k32[3]);
b[1] = (P[P_14][b[1]] & 0xFF) ^ b1(k32[3]);
b[2] = (P[P_24][b[2]] & 0xFF) ^ b2(k32[3]);
b[3] = (P[P_34][b[3]] & 0xFF) ^ b3(k32[3]);
/* fall thru, having pre-processed b[0]..b[3] with k32[3] */
case 3: /* 192 bits of key */
b[0] = (P[P_03][b[0]] & 0xFF) ^ b0(k32[2]);
b[1] = (P[P_13][b[1]] & 0xFF) ^ b1(k32[2]);
b[2] = (P[P_23][b[2]] & 0xFF) ^ b2(k32[2]);
b[3] = (P[P_33][b[3]] & 0xFF) ^ b3(k32[2]);
/* fall thru, having pre-processed b[0]..b[3] with k32[2] */
case 2: /* 128 bits of key */
b[0] = P[P_00][(P[P_01][(P[P_02][b[0]] ^ b0(k32[1])) & 0xFF] ^ b0(k32[0])) & 0xFF];
b[1] = P[P_10][(P[P_11][(P[P_12][b[1]] ^ b1(k32[1])) & 0xFF] ^ b1(k32[0])) & 0xFF];
b[2] = P[P_20][(P[P_21][(P[P_22][b[2]] ^ b2(k32[1])) & 0xFF] ^ b2(k32[0])) & 0xFF];
b[3] = P[P_30][(P[P_31][(P[P_32][b[3]] ^ b3(k32[1])) & 0xFF] ^ b3(k32[0])) & 0xFF];
}
b[0] &= 0xFF;
b[1] &= 0xFF;
b[2] &= 0xFF;
b[3] &= 0xFF;
// System.out.println(Integer.toHexString(b[0]) + " " + Integer.toHexString(b[1]) + " " + Integer.toHexString(b[2]) + " " + Integer.toHexString(b[3]) + " ");
/* Now perform the MDS matrix multiply inline. */
return ((Mx_1(b[0]) ^ Mx_Y(b[1]) ^ Mx_X(b[2]) ^ Mx_X(b[3]))) ^
((Mx_X(b[0]) ^ Mx_Y(b[1]) ^ Mx_Y(b[2]) ^ Mx_1(b[3])) << 8) ^
((Mx_Y(b[0]) ^ Mx_X(b[1]) ^ Mx_1(b[2]) ^ Mx_Y(b[3])) <<16) ^
((Mx_Y(b[0]) ^ Mx_1(b[1]) ^ Mx_Y(b[2]) ^ Mx_X(b[3])) <<24);
}
final static int LFSR1(int x)
{
return (x >>> 1) ^ ((x & 0x01) != 0 ? GF256_FDBK_2 : 0);
}
final static int LFSR2(int x)
{
return (x >>> 2) ^
((x & 0x02) != 0 ? GF256_FDBK_2 : 0) ^
((x & 0x01) != 0 ? GF256_FDBK_4 : 0);
}
final static int Mx_1(int x)
{
return x;
}
final static int Mx_X(int x)
{
return x ^ LFSR2(x);
} // 5B
final static int Mx_Y(int x)
{
return x ^ LFSR1(x) ^ LFSR2(x);
} // EF
//==================================
// Private Implementation
//==================================
/**
* Initialise the key schedule from the given key material.
*
* <p>Here we precompute all the round subkeys, although that is
* not actually required.
*/
private void prepareKey(byte[] key)
{
int[] k32e = new int[MAX_KEY_BITS/64];
int[] k32o = new int[MAX_KEY_BITS/64];
/*
* key schedule data
*/
sBoxKeys = new int[MAX_KEY_BITS/64];
subKeys = new int[TOTAL_SUBKEYS];
/*
* Round up to next multiple of 64bits
*
* This assumes the key has been padded out with zeros to
* a valid key length
*/
k64Cnt = (key.length + 7) / 8;
// System.out.println("S-box key");
int offset = 0;
for (int i = 0; i < k64Cnt; i++)
{
k32e[i] = (key[offset++] & 0xFF)
| (key[offset++] & 0xFF) << 8
| (key[offset++] & 0xFF) << 16
| (key[offset++] & 0xFF) << 24;
k32o[i] = (key[offset++] & 0xFF)
| (key[offset++] & 0xFF) << 8
| (key[offset++] & 0xFF) << 16
| (key[offset++] & 0xFF) << 24;
// the sbox keys are stored in reverse order
sBoxKeys[k64Cnt - 1 - i] = RS_MDS_Encode(k32e[i], k32o[i]);
// System.out.println(Integer.toHexString(sBoxKeys[k64Cnt - 1 - i]));
}
// System.out.println("Subkeys");
/*
* compute round subkeys for PHT
*/
for (int i = 0; i < TOTAL_SUBKEYS / 2; i++)
{
int A = f32(i * SK_STEP, k32e, k64Cnt);
int B = f32(i * SK_STEP + SK_BUMP, k32o, k64Cnt);
// System.out.print("A = " + Integer.toHexString(A));
// System.out.println(" B = " + Integer.toHexString(B));
B = B << 8 | B >>> 24;
A += B;
subKeys[2 * i] = A;
A += B;
subKeys[2 * i + 1] = A << SK_ROTL | A >>> (32-SK_ROTL);
// System.out.println(Integer.toHexString(subKeys[2 * i]) + "\t" + Integer.toHexString(subKeys[2 * i + 1]));
}
}
/**
* Use (12,8) Reed-Solomon code over GF(256) to produce a key
* S-box dword from two key material integers.
*
* <p>Since this computation is done only once per reKey per 64
* bits of key, the performance impact of this routine is
* imperceptible. The RS code chosen has "simple" coefficients
* to allow smartcard/hardware implementation without lookup
* tables.
* @return Remainder polynomial generated using RS code
*/
final static int RS_MDS_Encode(int k0, int k1)
{
int r = 0;
for (int i = 0; i < 2; i++)
{
// merge in 32 more key bits
r ^= (i == 0) ? k1 : k0;
// shift one byte at a time
for (int j = 0; j < 4; j++)
{
/*
* Reed-Solomon code parameters: (12,8)
* reversible code
* g(x) = x**4 + (a + 1/a) x**3
* + a x**2 + (a + 1/a) x + 1
* where a = primitive root of field
* generator 0x14D
*/
int b = b3(r);
int g2 = ((b << 1) ^ ((b & 0x80) != 0 ? RS_GF_FDBK : 0 )) & 0xFF;
int g3 = ((b >>> 1) & 0x7F) ^ ((b & 0x01) != 0 ? (RS_GF_FDBK >>> 1) : 0 ) ^ g2;
r = (r << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b;
}
}
return r;
}
/**
* Re-key the cipher. If the provided Key is not compatible
* with this cipher the exception should throw an InvalidKeyException.
*
* @param inKey the key to be used.
* @exception InvalidKeyException if the key is of the wrong type.
*/
protected void setKey(Key inKey)
throws InvalidKeyException
{
if (!((inKey instanceof TwofishKey)
|| (inKey instanceof SecretKeySpec)))
{
throw new InvalidKeyException("not a Twofish Key");
}
prepareKey(inKey.getEncoded());
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -