aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/engines/ChaChaEngine.java
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/engines/ChaChaEngine.java')
-rw-r--r--libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/engines/ChaChaEngine.java186
1 files changed, 186 insertions, 0 deletions
diff --git a/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/engines/ChaChaEngine.java b/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/engines/ChaChaEngine.java
new file mode 100644
index 000000000..a6a0138b9
--- /dev/null
+++ b/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/engines/ChaChaEngine.java
@@ -0,0 +1,186 @@
+package org.spongycastle.crypto.engines;
+
+import org.spongycastle.crypto.util.Pack;
+
+/**
+ * Implementation of Daniel J. Bernstein's ChaCha stream cipher.
+ */
+public class ChaChaEngine extends Salsa20Engine
+{
+
+ /**
+ * Creates a 20 rounds ChaCha engine.
+ */
+ public ChaChaEngine()
+ {
+ super();
+ }
+
+ /**
+ * Creates a ChaCha engine with a specific number of rounds.
+ * @param rounds the number of rounds (must be an even number).
+ */
+ public ChaChaEngine(int rounds)
+ {
+ super(rounds);
+ }
+
+ public String getAlgorithmName()
+ {
+ return "ChaCha" + rounds;
+ }
+
+ protected void advanceCounter()
+ {
+ if (++engineState[12] == 0)
+ {
+ ++engineState[13];
+ }
+ }
+
+ protected void resetCounter()
+ {
+ engineState[12] = engineState[13] = 0;
+ }
+
+ protected void setKey(byte[] keyBytes, byte[] ivBytes)
+ {
+ if ((keyBytes.length != 16) && (keyBytes.length != 32))
+ {
+ throw new IllegalArgumentException(getAlgorithmName() + " requires 128 bit or 256 bit key");
+ }
+
+ int offset = 0;
+ byte[] constants;
+
+ // Key
+ engineState[4] = Pack.littleEndianToInt(keyBytes, 0);
+ engineState[5] = Pack.littleEndianToInt(keyBytes, 4);
+ engineState[6] = Pack.littleEndianToInt(keyBytes, 8);
+ engineState[7] = Pack.littleEndianToInt(keyBytes, 12);
+
+ if (keyBytes.length == 32)
+ {
+ constants = sigma;
+ offset = 16;
+ } else
+ {
+ constants = tau;
+ }
+
+ engineState[8] = Pack.littleEndianToInt(keyBytes, offset);
+ engineState[9] = Pack.littleEndianToInt(keyBytes, offset + 4);
+ engineState[10] = Pack.littleEndianToInt(keyBytes, offset + 8);
+ engineState[11] = Pack.littleEndianToInt(keyBytes, offset + 12);
+
+ engineState[0] = Pack.littleEndianToInt(constants, 0);
+ engineState[1] = Pack.littleEndianToInt(constants, 4);
+ engineState[2] = Pack.littleEndianToInt(constants, 8);
+ engineState[3] = Pack.littleEndianToInt(constants, 12);
+
+ // Counter
+ engineState[12] = engineState[13] = 0;
+
+ // IV
+ engineState[14] = Pack.littleEndianToInt(ivBytes, 0);
+ engineState[15] = Pack.littleEndianToInt(ivBytes, 4);
+ }
+
+ protected void generateKeyStream(byte[] output)
+ {
+ chachaCore(rounds, engineState, x);
+ Pack.intToLittleEndian(x, output, 0);
+ }
+
+ /**
+ * ChacCha function
+ *
+ * @param input input data
+ *
+ * @return keystream
+ */
+ public static void chachaCore(int rounds, int[] input, int[] x)
+ {
+ if (input.length != 16) {
+ throw new IllegalArgumentException();
+ }
+ if (x.length != 16) {
+ throw new IllegalArgumentException();
+ }
+ if (rounds % 2 != 0) {
+ throw new IllegalArgumentException("Number of rounds must be even");
+ }
+
+ int x00 = input[ 0];
+ int x01 = input[ 1];
+ int x02 = input[ 2];
+ int x03 = input[ 3];
+ int x04 = input[ 4];
+ int x05 = input[ 5];
+ int x06 = input[ 6];
+ int x07 = input[ 7];
+ int x08 = input[ 8];
+ int x09 = input[ 9];
+ int x10 = input[10];
+ int x11 = input[11];
+ int x12 = input[12];
+ int x13 = input[13];
+ int x14 = input[14];
+ int x15 = input[15];
+
+ for (int i = rounds; i > 0; i -= 2)
+ {
+ x00 += x04; x12 = rotl(x12 ^ x00, 16);
+ x08 += x12; x04 = rotl(x04 ^ x08, 12);
+ x00 += x04; x12 = rotl(x12 ^ x00, 8);
+ x08 += x12; x04 = rotl(x04 ^ x08, 7);
+ x01 += x05; x13 = rotl(x13 ^ x01, 16);
+ x09 += x13; x05 = rotl(x05 ^ x09, 12);
+ x01 += x05; x13 = rotl(x13 ^ x01, 8);
+ x09 += x13; x05 = rotl(x05 ^ x09, 7);
+ x02 += x06; x14 = rotl(x14 ^ x02, 16);
+ x10 += x14; x06 = rotl(x06 ^ x10, 12);
+ x02 += x06; x14 = rotl(x14 ^ x02, 8);
+ x10 += x14; x06 = rotl(x06 ^ x10, 7);
+ x03 += x07; x15 = rotl(x15 ^ x03, 16);
+ x11 += x15; x07 = rotl(x07 ^ x11, 12);
+ x03 += x07; x15 = rotl(x15 ^ x03, 8);
+ x11 += x15; x07 = rotl(x07 ^ x11, 7);
+ x00 += x05; x15 = rotl(x15 ^ x00, 16);
+ x10 += x15; x05 = rotl(x05 ^ x10, 12);
+ x00 += x05; x15 = rotl(x15 ^ x00, 8);
+ x10 += x15; x05 = rotl(x05 ^ x10, 7);
+ x01 += x06; x12 = rotl(x12 ^ x01, 16);
+ x11 += x12; x06 = rotl(x06 ^ x11, 12);
+ x01 += x06; x12 = rotl(x12 ^ x01, 8);
+ x11 += x12; x06 = rotl(x06 ^ x11, 7);
+ x02 += x07; x13 = rotl(x13 ^ x02, 16);
+ x08 += x13; x07 = rotl(x07 ^ x08, 12);
+ x02 += x07; x13 = rotl(x13 ^ x02, 8);
+ x08 += x13; x07 = rotl(x07 ^ x08, 7);
+ x03 += x04; x14 = rotl(x14 ^ x03, 16);
+ x09 += x14; x04 = rotl(x04 ^ x09, 12);
+ x03 += x04; x14 = rotl(x14 ^ x03, 8);
+ x09 += x14; x04 = rotl(x04 ^ x09, 7);
+
+ }
+
+ x[ 0] = x00 + input[ 0];
+ x[ 1] = x01 + input[ 1];
+ x[ 2] = x02 + input[ 2];
+ x[ 3] = x03 + input[ 3];
+ x[ 4] = x04 + input[ 4];
+ x[ 5] = x05 + input[ 5];
+ x[ 6] = x06 + input[ 6];
+ x[ 7] = x07 + input[ 7];
+ x[ 8] = x08 + input[ 8];
+ x[ 9] = x09 + input[ 9];
+ x[10] = x10 + input[10];
+ x[11] = x11 + input[11];
+ x[12] = x12 + input[12];
+ x[13] = x13 + input[13];
+ x[14] = x14 + input[14];
+ x[15] = x15 + input[15];
+ }
+
+}