| 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; |
| |
| /** |
| * An XTEA engine. |
| */ |
| public class XTEAEngine |
| implements BlockCipher |
| { |
| private static final int rounds = 32, |
| block_size = 8, |
| // key_size = 16, |
| delta = 0x9E3779B9; |
| |
| /* |
| * the expanded key array of 4 subkeys |
| */ |
| private int[] _S = new int[4], |
| _sum0 = new int[32], |
| _sum1 = new int[32]; |
| private boolean _initialised, |
| _forEncryption; |
| |
| /** |
| * Create an instance of the TEA encryption algorithm |
| * and set some defaults |
| */ |
| public XTEAEngine() |
| { |
| _initialised = false; |
| } |
| |
| public String getAlgorithmName() |
| { |
| return "XTEA"; |
| } |
| |
| public int getBlockSize() |
| { |
| return block_size; |
| } |
| |
| /** |
| * initialise |
| * |
| * @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)) |
| { |
| throw new IllegalArgumentException("invalid parameter passed to TEA init - " + params.getClass().getName()); |
| } |
| |
| _forEncryption = forEncryption; |
| _initialised = true; |
| |
| KeyParameter p = (KeyParameter)params; |
| |
| setKey(p.getKey()); |
| } |
| |
| public int processBlock( |
| byte[] in, |
| int inOff, |
| byte[] out, |
| int outOff) |
| { |
| if (!_initialised) |
| { |
| throw new IllegalStateException(getAlgorithmName()+" 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"); |
| } |
| |
| return (_forEncryption) ? encryptBlock(in, inOff, out, outOff) |
| : decryptBlock(in, inOff, out, outOff); |
| } |
| |
| public void reset() |
| { |
| } |
| |
| /** |
| * Re-key the cipher. |
| * <p> |
| * @param key the key to be used |
| */ |
| private void setKey( |
| byte[] key) |
| { |
| if (key.length != 16) |
| { |
| throw new IllegalArgumentException("Key size must be 128 bits."); |
| } |
| |
| int i, j; |
| for (i = j = 0; i < 4; i++,j+=4) |
| { |
| _S[i] = bytesToInt(key, j); |
| } |
| |
| for (i = j = 0; i < rounds; i++) |
| { |
| _sum0[i] = (j + _S[j & 3]); |
| j += delta; |
| _sum1[i] = (j + _S[j >>> 11 & 3]); |
| } |
| } |
| |
| private int encryptBlock( |
| byte[] in, |
| int inOff, |
| byte[] out, |
| int outOff) |
| { |
| // Pack bytes into integers |
| int v0 = bytesToInt(in, inOff); |
| int v1 = bytesToInt(in, inOff + 4); |
| |
| for (int i = 0; i < rounds; i++) |
| { |
| v0 += ((v1 << 4 ^ v1 >>> 5) + v1) ^ _sum0[i]; |
| v1 += ((v0 << 4 ^ v0 >>> 5) + v0) ^ _sum1[i]; |
| } |
| |
| unpackInt(v0, out, outOff); |
| unpackInt(v1, out, outOff + 4); |
| |
| return block_size; |
| } |
| |
| private int decryptBlock( |
| byte[] in, |
| int inOff, |
| byte[] out, |
| int outOff) |
| { |
| // Pack bytes into integers |
| int v0 = bytesToInt(in, inOff); |
| int v1 = bytesToInt(in, inOff + 4); |
| |
| for (int i = rounds-1; i >= 0; i--) |
| { |
| v1 -= ((v0 << 4 ^ v0 >>> 5) + v0) ^ _sum1[i]; |
| v0 -= ((v1 << 4 ^ v1 >>> 5) + v1) ^ _sum0[i]; |
| } |
| |
| unpackInt(v0, out, outOff); |
| unpackInt(v1, out, outOff + 4); |
| |
| return block_size; |
| } |
| |
| private int bytesToInt(byte[] in, int inOff) |
| { |
| return ((in[inOff++]) << 24) | |
| ((in[inOff++] & 255) << 16) | |
| ((in[inOff++] & 255) << 8) | |
| ((in[inOff] & 255)); |
| } |
| |
| private void unpackInt(int v, byte[] out, int outOff) |
| { |
| out[outOff++] = (byte)(v >>> 24); |
| out[outOff++] = (byte)(v >>> 16); |
| out[outOff++] = (byte)(v >>> 8); |
| out[outOff ] = (byte)v; |
| } |
| } |