diff options
Diffstat (limited to 'core/src/main/java/org/bouncycastle/crypto/engines/IDEAEngine.java')
-rw-r--r-- | core/src/main/java/org/bouncycastle/crypto/engines/IDEAEngine.java | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/IDEAEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/IDEAEngine.java new file mode 100644 index 00000000..fdf3f6d3 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/engines/IDEAEngine.java @@ -0,0 +1,367 @@ +package org.bouncycastle.crypto.engines; + +import org.bouncycastle.crypto.BlockCipher; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.OutputLengthException; +import org.bouncycastle.crypto.params.KeyParameter; + +/** + * A class that provides a basic International Data Encryption Algorithm (IDEA) engine. + * <p> + * This implementation is based on the "HOWTO: INTERNATIONAL DATA ENCRYPTION ALGORITHM" + * implementation summary by Fauzan Mirza (F.U.Mirza@sheffield.ac.uk). (baring 1 typo at the + * end of the mulinv function!). + * <p> + * It can be found at ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/idea/ + * <p> + * Note 1: This algorithm is patented in the USA, Japan, and Europe including + * at least Austria, France, Germany, Italy, Netherlands, Spain, Sweden, Switzerland + * and the United Kingdom. Non-commercial use is free, however any commercial + * products are liable for royalties. Please see + * <a href="http://www.mediacrypt.com">www.mediacrypt.com</a> for + * further details. This announcement has been included at the request of + * the patent holders. + * <p> + * Note 2: Due to the requests concerning the above, this algorithm is now only + * included in the extended Bouncy Castle provider and JCE signed jars. It is + * not included in the default distributions. + */ +public class IDEAEngine + implements BlockCipher +{ + protected static final int BLOCK_SIZE = 8; + + private int[] workingKey = null; + + /** + * standard constructor. + */ + public IDEAEngine() + { + } + + /** + * initialise an IDEA cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean forEncryption, + CipherParameters params) + { + if (params instanceof KeyParameter) + { + workingKey = generateWorkingKey(forEncryption, + ((KeyParameter)params).getKey()); + return; + } + + throw new IllegalArgumentException("invalid parameter passed to IDEA init - " + params.getClass().getName()); + } + + public String getAlgorithmName() + { + return "IDEA"; + } + + public int getBlockSize() + { + return BLOCK_SIZE; + } + + public int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + if (workingKey == null) + { + throw new IllegalStateException("IDEA engine not initialised"); + } + + if ((inOff + BLOCK_SIZE) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + BLOCK_SIZE) > out.length) + { + throw new OutputLengthException("output buffer too short"); + } + + ideaFunc(workingKey, in, inOff, out, outOff); + + return BLOCK_SIZE; + } + + public void reset() + { + } + + private static final int MASK = 0xffff; + private static final int BASE = 0x10001; + + private int bytesToWord( + byte[] in, + int inOff) + { + return ((in[inOff] << 8) & 0xff00) + (in[inOff + 1] & 0xff); + } + + private void wordToBytes( + int word, + byte[] out, + int outOff) + { + out[outOff] = (byte)(word >>> 8); + out[outOff + 1] = (byte)word; + } + + /** + * return x = x * y where the multiplication is done modulo + * 65537 (0x10001) (as defined in the IDEA specification) and + * a zero input is taken to be 65536 (0x10000). + * + * @param x the x value + * @param y the y value + * @return x = x * y + */ + private int mul( + int x, + int y) + { + if (x == 0) + { + x = (BASE - y); + } + else if (y == 0) + { + x = (BASE - x); + } + else + { + int p = x * y; + + y = p & MASK; + x = p >>> 16; + x = y - x + ((y < x) ? 1 : 0); + } + + return x & MASK; + } + + private void ideaFunc( + int[] workingKey, + byte[] in, + int inOff, + byte[] out, + int outOff) + { + int x0, x1, x2, x3, t0, t1; + int keyOff = 0; + + x0 = bytesToWord(in, inOff); + x1 = bytesToWord(in, inOff + 2); + x2 = bytesToWord(in, inOff + 4); + x3 = bytesToWord(in, inOff + 6); + + for (int round = 0; round < 8; round++) + { + x0 = mul(x0, workingKey[keyOff++]); + x1 += workingKey[keyOff++]; + x1 &= MASK; + x2 += workingKey[keyOff++]; + x2 &= MASK; + x3 = mul(x3, workingKey[keyOff++]); + + t0 = x1; + t1 = x2; + x2 ^= x0; + x1 ^= x3; + + x2 = mul(x2, workingKey[keyOff++]); + x1 += x2; + x1 &= MASK; + + x1 = mul(x1, workingKey[keyOff++]); + x2 += x1; + x2 &= MASK; + + x0 ^= x1; + x3 ^= x2; + x1 ^= t1; + x2 ^= t0; + } + + wordToBytes(mul(x0, workingKey[keyOff++]), out, outOff); + wordToBytes(x2 + workingKey[keyOff++], out, outOff + 2); /* NB: Order */ + wordToBytes(x1 + workingKey[keyOff++], out, outOff + 4); + wordToBytes(mul(x3, workingKey[keyOff]), out, outOff + 6); + } + + /** + * The following function is used to expand the user key to the encryption + * subkey. The first 16 bytes are the user key, and the rest of the subkey + * is calculated by rotating the previous 16 bytes by 25 bits to the left, + * and so on until the subkey is completed. + */ + private int[] expandKey( + byte[] uKey) + { + int[] key = new int[52]; + + if (uKey.length < 16) + { + byte[] tmp = new byte[16]; + + System.arraycopy(uKey, 0, tmp, tmp.length - uKey.length, uKey.length); + + uKey = tmp; + } + + for (int i = 0; i < 8; i++) + { + key[i] = bytesToWord(uKey, i * 2); + } + + for (int i = 8; i < 52; i++) + { + if ((i & 7) < 6) + { + key[i] = ((key[i - 7] & 127) << 9 | key[i - 6] >> 7) & MASK; + } + else if ((i & 7) == 6) + { + key[i] = ((key[i - 7] & 127) << 9 | key[i - 14] >> 7) & MASK; + } + else + { + key[i] = ((key[i - 15] & 127) << 9 | key[i - 14] >> 7) & MASK; + } + } + + return key; + } + + /** + * This function computes multiplicative inverse using Euclid's Greatest + * Common Divisor algorithm. Zero and one are self inverse. + * <p> + * i.e. x * mulInv(x) == 1 (modulo BASE) + */ + private int mulInv( + int x) + { + int t0, t1, q, y; + + if (x < 2) + { + return x; + } + + t0 = 1; + t1 = BASE / x; + y = BASE % x; + + while (y != 1) + { + q = x / y; + x = x % y; + t0 = (t0 + (t1 * q)) & MASK; + if (x == 1) + { + return t0; + } + q = y / x; + y = y % x; + t1 = (t1 + (t0 * q)) & MASK; + } + + return (1 - t1) & MASK; + } + + /** + * Return the additive inverse of x. + * <p> + * i.e. x + addInv(x) == 0 + */ + int addInv( + int x) + { + return (0 - x) & MASK; + } + + /** + * The function to invert the encryption subkey to the decryption subkey. + * It also involves the multiplicative inverse and the additive inverse functions. + */ + private int[] invertKey( + int[] inKey) + { + int t1, t2, t3, t4; + int p = 52; /* We work backwards */ + int[] key = new int[52]; + int inOff = 0; + + t1 = mulInv(inKey[inOff++]); + t2 = addInv(inKey[inOff++]); + t3 = addInv(inKey[inOff++]); + t4 = mulInv(inKey[inOff++]); + key[--p] = t4; + key[--p] = t3; + key[--p] = t2; + key[--p] = t1; + + for (int round = 1; round < 8; round++) + { + t1 = inKey[inOff++]; + t2 = inKey[inOff++]; + key[--p] = t2; + key[--p] = t1; + + t1 = mulInv(inKey[inOff++]); + t2 = addInv(inKey[inOff++]); + t3 = addInv(inKey[inOff++]); + t4 = mulInv(inKey[inOff++]); + key[--p] = t4; + key[--p] = t2; /* NB: Order */ + key[--p] = t3; + key[--p] = t1; + } + + t1 = inKey[inOff++]; + t2 = inKey[inOff++]; + key[--p] = t2; + key[--p] = t1; + + t1 = mulInv(inKey[inOff++]); + t2 = addInv(inKey[inOff++]); + t3 = addInv(inKey[inOff++]); + t4 = mulInv(inKey[inOff]); + key[--p] = t4; + key[--p] = t3; + key[--p] = t2; + key[--p] = t1; + + return key; + } + + private int[] generateWorkingKey( + boolean forEncryption, + byte[] userKey) + { + if (forEncryption) + { + return expandKey(userKey); + } + else + { + return invertKey(expandKey(userKey)); + } + } +} |