diff options
author | David Hook <dgh@cryptoworkshop.com> | 2013-05-31 11:07:45 +0400 |
---|---|---|
committer | David Hook <dgh@cryptoworkshop.com> | 2013-05-31 11:07:45 +0400 |
commit | 2b976f5364cfdbc37d3086019d93483c983eb80b (patch) | |
tree | cb846af3fd1d43f9c2562a1fb2d06b997ad8f229 /core/src/main/java/org/bouncycastle/crypto/engines/ISAACEngine.java | |
parent | 5f714bd92fbd780d22406f4bc3681be005f6f04a (diff) |
initial reshuffle
Diffstat (limited to 'core/src/main/java/org/bouncycastle/crypto/engines/ISAACEngine.java')
-rw-r--r-- | core/src/main/java/org/bouncycastle/crypto/engines/ISAACEngine.java | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/ISAACEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/ISAACEngine.java new file mode 100644 index 00000000..d6e1ae11 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/engines/ISAACEngine.java @@ -0,0 +1,219 @@ +package org.bouncycastle.crypto.engines; + +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.OutputLengthException; +import org.bouncycastle.crypto.StreamCipher; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.crypto.util.Pack; + +/** + * Implementation of Bob Jenkin's ISAAC (Indirection Shift Accumulate Add and Count). + * see: http://www.burtleburtle.net/bob/rand/isaacafa.html +*/ +public class ISAACEngine + implements StreamCipher +{ + // Constants + private final int sizeL = 8, + stateArraySize = sizeL<<5; // 256 + + // Cipher's internal state + private int[] engineState = null, // mm + results = null; // randrsl + private int a = 0, b = 0, c = 0; + + // Engine state + private int index = 0; + private byte[] keyStream = new byte[stateArraySize<<2], // results expanded into bytes + workingKey = null; + private boolean initialised = false; + + /** + * initialise an ISAAC 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)) + { + throw new IllegalArgumentException("invalid parameter passed to ISAAC init - " + params.getClass().getName()); + } + /* + * ISAAC encryption and decryption is completely + * symmetrical, so the 'forEncryption' is + * irrelevant. + */ + KeyParameter p = (KeyParameter)params; + setKey(p.getKey()); + + return; + } + + public byte returnByte(byte in) + { + if (index == 0) + { + isaac(); + keyStream = Pack.intToBigEndian(results); + } + byte out = (byte)(keyStream[index]^in); + index = (index + 1) & 1023; + + return out; + } + + public void processBytes( + byte[] in, + int inOff, + int len, + byte[] out, + int outOff) + { + if (!initialised) + { + throw new IllegalStateException(getAlgorithmName()+" not initialised"); + } + + if ((inOff + len) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + len) > out.length) + { + throw new OutputLengthException("output buffer too short"); + } + + for (int i = 0; i < len; i++) + { + if (index == 0) + { + isaac(); + keyStream = Pack.intToBigEndian(results); + } + out[i+outOff] = (byte)(keyStream[index]^in[i+inOff]); + index = (index + 1) & 1023; + } + } + + public String getAlgorithmName() + { + return "ISAAC"; + } + + public void reset() + { + setKey(workingKey); + } + + // Private implementation + private void setKey(byte[] keyBytes) + { + workingKey = keyBytes; + + if (engineState == null) + { + engineState = new int[stateArraySize]; + } + + if (results == null) + { + results = new int[stateArraySize]; + } + + int i, j, k; + + // Reset state + for (i = 0; i < stateArraySize; i++) + { + engineState[i] = results[i] = 0; + } + a = b = c = 0; + + // Reset index counter for output + index = 0; + + // Convert the key bytes to ints and put them into results[] for initialization + byte[] t = new byte[keyBytes.length + (keyBytes.length & 3)]; + System.arraycopy(keyBytes, 0, t, 0, keyBytes.length); + for (i = 0; i < t.length; i+=4) + { + results[i >>> 2] = Pack.littleEndianToInt(t, i); + } + + // It has begun? + int[] abcdefgh = new int[sizeL]; + + for (i = 0; i < sizeL; i++) + { + abcdefgh[i] = 0x9e3779b9; // Phi (golden ratio) + } + + for (i = 0; i < 4; i++) + { + mix(abcdefgh); + } + + for (i = 0; i < 2; i++) + { + for (j = 0; j < stateArraySize; j+=sizeL) + { + for (k = 0; k < sizeL; k++) + { + abcdefgh[k] += (i<1) ? results[j+k] : engineState[j+k]; + } + + mix(abcdefgh); + + for (k = 0; k < sizeL; k++) + { + engineState[j+k] = abcdefgh[k]; + } + } + } + + isaac(); + + initialised = true; + } + + private void isaac() + { + int i, x, y; + + b += ++c; + for (i = 0; i < stateArraySize; i++) + { + x = engineState[i]; + switch (i & 3) + { + case 0: a ^= (a << 13); break; + case 1: a ^= (a >>> 6); break; + case 2: a ^= (a << 2); break; + case 3: a ^= (a >>> 16); break; + } + a += engineState[(i+128) & 0xFF]; + engineState[i] = y = engineState[(x >>> 2) & 0xFF] + a + b; + results[i] = b = engineState[(y >>> 10) & 0xFF] + x; + } + } + + private void mix(int[] x) + { + x[0]^=x[1]<< 11; x[3]+=x[0]; x[1]+=x[2]; + x[1]^=x[2]>>> 2; x[4]+=x[1]; x[2]+=x[3]; + x[2]^=x[3]<< 8; x[5]+=x[2]; x[3]+=x[4]; + x[3]^=x[4]>>>16; x[6]+=x[3]; x[4]+=x[5]; + x[4]^=x[5]<< 10; x[7]+=x[4]; x[5]+=x[6]; + x[5]^=x[6]>>> 4; x[0]+=x[5]; x[6]+=x[7]; + x[6]^=x[7]<< 8; x[1]+=x[6]; x[7]+=x[0]; + x[7]^=x[0]>>> 9; x[2]+=x[7]; x[0]+=x[1]; + } +} |