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