001: package org.bouncycastle.crypto.engines;
002:
003: import org.bouncycastle.crypto.BlockCipher;
004: import org.bouncycastle.crypto.CipherParameters;
005: import org.bouncycastle.crypto.DataLengthException;
006: import org.bouncycastle.crypto.params.KeyParameter;
007:
008: /**
009: * An XTEA engine.
010: */
011: public class XTEAEngine implements BlockCipher {
012: private static final int rounds = 32, block_size = 8,
013: key_size = 16, delta = 0x9E3779B9, d_sum = 0xC6EF3720; // sum on decrypt
014:
015: /*
016: * the expanded key array of 4 subkeys
017: */
018: private int[] _S = new int[4];
019: private boolean _initialised;
020: private boolean _forEncryption;
021:
022: /**
023: * Create an instance of the TEA encryption algorithm
024: * and set some defaults
025: */
026: public XTEAEngine() {
027: _initialised = false;
028: }
029:
030: public String getAlgorithmName() {
031: return "XTEA";
032: }
033:
034: public int getBlockSize() {
035: return block_size;
036: }
037:
038: /**
039: * initialise
040: *
041: * @param forEncryption whether or not we are for encryption.
042: * @param params the parameters required to set up the cipher.
043: * @exception IllegalArgumentException if the params argument is
044: * inappropriate.
045: */
046: public void init(boolean forEncryption, CipherParameters params) {
047: if (!(params instanceof KeyParameter)) {
048: throw new IllegalArgumentException(
049: "invalid parameter passed to TEA init - "
050: + params.getClass().getName());
051: }
052:
053: _forEncryption = forEncryption;
054: _initialised = true;
055:
056: KeyParameter p = (KeyParameter) params;
057:
058: setKey(p.getKey());
059: }
060:
061: public int processBlock(byte[] in, int inOff, byte[] out, int outOff) {
062: if (!_initialised) {
063: throw new IllegalStateException(getAlgorithmName()
064: + " not initialised");
065: }
066:
067: if ((inOff + block_size) > in.length) {
068: throw new DataLengthException("input buffer too short");
069: }
070:
071: if ((outOff + block_size) > out.length) {
072: throw new DataLengthException("output buffer too short");
073: }
074:
075: return (_forEncryption) ? encryptBlock(in, inOff, out, outOff)
076: : decryptBlock(in, inOff, out, outOff);
077: }
078:
079: public void reset() {
080: }
081:
082: /**
083: * Re-key the cipher.
084: * <p>
085: * @param key the key to be used
086: */
087: private void setKey(byte[] key) {
088: _S[0] = bytesToInt(key, 0);
089: _S[1] = bytesToInt(key, 4);
090: _S[2] = bytesToInt(key, 8);
091: _S[3] = bytesToInt(key, 12);
092: }
093:
094: private int encryptBlock(byte[] in, int inOff, byte[] out,
095: int outOff) {
096: // Pack bytes into integers
097: int v0 = bytesToInt(in, inOff);
098: int v1 = bytesToInt(in, inOff + 4);
099:
100: int sum = 0;
101:
102: for (int i = 0; i != rounds; i++) {
103: v0 += ((v1 << 4 ^ v1 >>> 5) + v1) ^ (sum + _S[sum & 3]);
104: sum += delta;
105: v1 += ((v0 << 4 ^ v0 >>> 5) + v0)
106: ^ (sum + _S[sum >>> 11 & 3]);
107: }
108:
109: unpackInt(v0, out, outOff);
110: unpackInt(v1, out, outOff + 4);
111:
112: return block_size;
113: }
114:
115: private int decryptBlock(byte[] in, int inOff, byte[] out,
116: int outOff) {
117: // Pack bytes into integers
118: int v0 = bytesToInt(in, inOff);
119: int v1 = bytesToInt(in, inOff + 4);
120:
121: int sum = d_sum;
122:
123: for (int i = 0; i != rounds; i++) {
124: v1 -= ((v0 << 4 ^ v0 >>> 5) + v0)
125: ^ (sum + _S[sum >>> 11 & 3]);
126: sum -= delta;
127: v0 -= ((v1 << 4 ^ v1 >>> 5) + v1) ^ (sum + _S[sum & 3]);
128: }
129:
130: unpackInt(v0, out, outOff);
131: unpackInt(v1, out, outOff + 4);
132:
133: return block_size;
134: }
135:
136: private int bytesToInt(byte[] in, int inOff) {
137: return ((in[inOff++]) << 24) | ((in[inOff++] & 255) << 16)
138: | ((in[inOff++] & 255) << 8) | ((in[inOff] & 255));
139: }
140:
141: private void unpackInt(int v, byte[] out, int outOff) {
142: out[outOff++] = (byte) (v >>> 24);
143: out[outOff++] = (byte) (v >>> 16);
144: out[outOff++] = (byte) (v >>> 8);
145: out[outOff] = (byte) v;
146: }
147: }
|