diff options
Diffstat (limited to 'core/src/main/java/org/bouncycastle/crypto/modes/gcm')
8 files changed, 548 insertions, 0 deletions
diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMExponentiator.java b/core/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMExponentiator.java new file mode 100644 index 00000000..f2be2fc4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMExponentiator.java @@ -0,0 +1,36 @@ +package org.bouncycastle.crypto.modes.gcm; + +import org.bouncycastle.util.Arrays; + +public class BasicGCMExponentiator implements GCMExponentiator +{ + private byte[] x; + + public void init(byte[] x) + { + this.x = Arrays.clone(x); + } + + public void exponentiateX(long pow, byte[] output) + { + // Initial value is little-endian 1 + byte[] y = GCMUtil.oneAsBytes(); + + if (pow > 0) + { + byte[] powX = Arrays.clone(x); + do + { + if ((pow & 1L) != 0) + { + GCMUtil.multiply(y, powX); + } + GCMUtil.multiply(powX, powX); + pow >>>= 1; + } + while (pow > 0); + } + + System.arraycopy(y, 0, output, 0, 16); + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMMultiplier.java b/core/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMMultiplier.java new file mode 100644 index 00000000..a98d5b2a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMMultiplier.java @@ -0,0 +1,18 @@ +package org.bouncycastle.crypto.modes.gcm; + +import org.bouncycastle.util.Arrays; + +public class BasicGCMMultiplier implements GCMMultiplier +{ + private byte[] H; + + public void init(byte[] H) + { + this.H = Arrays.clone(H); + } + + public void multiplyH(byte[] x) + { + GCMUtil.multiply(x, H); + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMExponentiator.java b/core/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMExponentiator.java new file mode 100644 index 00000000..e1cc5c76 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMExponentiator.java @@ -0,0 +1,7 @@ +package org.bouncycastle.crypto.modes.gcm; + +public interface GCMExponentiator +{ + void init(byte[] x); + void exponentiateX(long pow, byte[] output); +} diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMMultiplier.java b/core/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMMultiplier.java new file mode 100644 index 00000000..f52f6105 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMMultiplier.java @@ -0,0 +1,7 @@ +package org.bouncycastle.crypto.modes.gcm; + +public interface GCMMultiplier +{ + void init(byte[] H); + void multiplyH(byte[] x); +} diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java b/core/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java new file mode 100644 index 00000000..48753011 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java @@ -0,0 +1,260 @@ +package org.bouncycastle.crypto.modes.gcm; + +import org.bouncycastle.crypto.util.Pack; +import org.bouncycastle.util.Arrays; + +abstract class GCMUtil +{ + static byte[] oneAsBytes() + { + byte[] tmp = new byte[16]; + tmp[0] = (byte)0x80; + return tmp; + } + + static int[] oneAsInts() + { + int[] tmp = new int[4]; + tmp[0] = 0x80000000; + return tmp; + } + + static byte[] asBytes(int[] ns) + { + byte[] output = new byte[16]; + Pack.intToBigEndian(ns, output, 0); + return output; + } + + static int[] asInts(byte[] bs) + { + int[] output = new int[4]; + Pack.bigEndianToInt(bs, 0, output); + return output; + } + + static void asInts(byte[] bs, int[] output) + { + Pack.bigEndianToInt(bs, 0, output); + } + + static void multiply(byte[] block, byte[] val) + { + byte[] tmp = Arrays.clone(block); + byte[] c = new byte[16]; + + for (int i = 0; i < 16; ++i) + { + byte bits = val[i]; + for (int j = 7; j >= 0; --j) + { + if ((bits & (1 << j)) != 0) + { + xor(c, tmp); + } + + boolean lsb = (tmp[15] & 1) != 0; + shiftRight(tmp); + if (lsb) + { + // R = new byte[]{ 0xe1, ... }; +// GCMUtil.xor(v, R); + tmp[0] ^= (byte)0xe1; + } + } + } + + System.arraycopy(c, 0, block, 0, 16); + } + + // P is the value with only bit i=1 set + static void multiplyP(int[] x) + { + boolean lsb = (x[3] & 1) != 0; + shiftRight(x); + if (lsb) + { + // R = new int[]{ 0xe1000000, 0, 0, 0 }; +// xor(v, R); + x[0] ^= 0xe1000000; + } + } + + static void multiplyP(int[] x, int[] output) + { + boolean lsb = (x[3] & 1) != 0; + shiftRight(x, output); + if (lsb) + { + output[0] ^= 0xe1000000; + } + } + + // P is the value with only bit i=1 set + static void multiplyP8(int[] x) + { +// for (int i = 8; i != 0; --i) +// { +// multiplyP(x); +// } + + int lsw = x[3]; + shiftRightN(x, 8); + for (int i = 7; i >= 0; --i) + { + if ((lsw & (1 << i)) != 0) + { + x[0] ^= (0xe1000000 >>> (7 - i)); + } + } + } + + static void multiplyP8(int[] x, int[] output) + { + int lsw = x[3]; + shiftRightN(x, 8, output); + for (int i = 7; i >= 0; --i) + { + if ((lsw & (1 << i)) != 0) + { + output[0] ^= (0xe1000000 >>> (7 - i)); + } + } + } + + static void shiftRight(byte[] block) + { + int i = 0; + int bit = 0; + for (;;) + { + int b = block[i] & 0xff; + block[i] = (byte) ((b >>> 1) | bit); + if (++i == 16) + { + break; + } + bit = (b & 1) << 7; + } + } + + static void shiftRight(byte[] block, byte[] output) + { + int i = 0; + int bit = 0; + for (;;) + { + int b = block[i] & 0xff; + output[i] = (byte) ((b >>> 1) | bit); + if (++i == 16) + { + break; + } + bit = (b & 1) << 7; + } + } + + static void shiftRight(int[] block) + { + int i = 0; + int bit = 0; + for (;;) + { + int b = block[i]; + block[i] = (b >>> 1) | bit; + if (++i == 4) + { + break; + } + bit = b << 31; + } + } + + static void shiftRight(int[] block, int[] output) + { + int i = 0; + int bit = 0; + for (;;) + { + int b = block[i]; + output[i] = (b >>> 1) | bit; + if (++i == 4) + { + break; + } + bit = b << 31; + } + } + + static void shiftRightN(int[] block, int n) + { + int i = 0; + int bits = 0; + for (;;) + { + int b = block[i]; + block[i] = (b >>> n) | bits; + if (++i == 4) + { + break; + } + bits = b << (32 - n); + } + } + + static void shiftRightN(int[] block, int n, int[] output) + { + int i = 0; + int bits = 0; + for (;;) + { + int b = block[i]; + output[i] = (b >>> n) | bits; + if (++i == 4) + { + break; + } + bits = b << (32 - n); + } + } + + static void xor(byte[] block, byte[] val) + { + for (int i = 15; i >= 0; --i) + { + block[i] ^= val[i]; + } + } + + static void xor(byte[] block, byte[] val, int off, int len) + { + while (len-- > 0) + { + block[len] ^= val[off + len]; + } + } + + static void xor(byte[] block, byte[] val, byte[] output) + { + for (int i = 15; i >= 0; --i) + { + output[i] = (byte)(block[i] ^ val[i]); + } + } + + static void xor(int[] block, int[] val) + { + for (int i = 3; i >= 0; --i) + { + block[i] ^= val[i]; + } + } + + static void xor(int[] block, int[] val, int[] output) + { + for (int i = 3; i >= 0; --i) + { + output[i] = block[i] ^ val[i]; + } + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java b/core/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java new file mode 100644 index 00000000..a0512086 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java @@ -0,0 +1,57 @@ +package org.bouncycastle.crypto.modes.gcm; + +import java.util.Vector; + +import org.bouncycastle.util.Arrays; + +public class Tables1kGCMExponentiator implements GCMExponentiator +{ + // A lookup table of the power-of-two powers of 'x' + // - lookupPowX2[i] = x^(2^i) + private Vector lookupPowX2; + + public void init(byte[] x) + { + if (lookupPowX2 != null && Arrays.areEqual(x, (byte[])lookupPowX2.elementAt(0))) + { + return; + } + + lookupPowX2 = new Vector(8); + lookupPowX2.addElement(Arrays.clone(x)); + } + + public void exponentiateX(long pow, byte[] output) + { + byte[] y = GCMUtil.oneAsBytes(); + int bit = 0; + while (pow > 0) + { + if ((pow & 1L) != 0) + { + ensureAvailable(bit); + GCMUtil.multiply(y, (byte[])lookupPowX2.elementAt(bit)); + } + ++bit; + pow >>>= 1; + } + + System.arraycopy(y, 0, output, 0, 16); + } + + private void ensureAvailable(int bit) + { + int count = lookupPowX2.size(); + if (count <= bit) + { + byte[] tmp = (byte[])lookupPowX2.elementAt(count - 1); + do + { + tmp = Arrays.clone(tmp); + GCMUtil.multiply(tmp, tmp); + lookupPowX2.addElement(tmp); + } + while (++count <= bit); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables64kGCMMultiplier.java b/core/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables64kGCMMultiplier.java new file mode 100644 index 00000000..a34a6ea4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables64kGCMMultiplier.java @@ -0,0 +1,73 @@ +package org.bouncycastle.crypto.modes.gcm; + +import org.bouncycastle.crypto.util.Pack; +import org.bouncycastle.util.Arrays; + +public class Tables64kGCMMultiplier implements GCMMultiplier +{ + private byte[] H; + private int[][][] M; + + public void init(byte[] H) + { + if (M == null) + { + M = new int[16][256][4]; + } + else if (Arrays.areEqual(this.H, H)) + { + return; + } + + this.H = Arrays.clone(H); + + // M[0][0] is ZEROES; + GCMUtil.asInts(H, M[0][128]); + + for (int j = 64; j >= 1; j >>= 1) + { + GCMUtil.multiplyP(M[0][j + j], M[0][j]); + } + + int i = 0; + for (;;) + { + for (int j = 2; j < 256; j += j) + { + for (int k = 1; k < j; ++k) + { + GCMUtil.xor(M[i][j], M[i][k], M[i][j + k]); + } + } + + if (++i == 16) + { + return; + } + + // M[i][0] is ZEROES; + for (int j = 128; j > 0; j >>= 1) + { + GCMUtil.multiplyP8(M[i - 1][j], M[i][j]); + } + } + } + + public void multiplyH(byte[] x) + { +// assert x.Length == 16; + + int[] z = new int[4]; + for (int i = 15; i >= 0; --i) + { +// GCMUtil.xor(z, M[i][x[i] & 0xff]); + int[] m = M[i][x[i] & 0xff]; + z[0] ^= m[0]; + z[1] ^= m[1]; + z[2] ^= m[2]; + z[3] ^= m[3]; + } + + Pack.intToBigEndian(z, x, 0); + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java b/core/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java new file mode 100644 index 00000000..8535db5a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java @@ -0,0 +1,90 @@ +package org.bouncycastle.crypto.modes.gcm; + +import org.bouncycastle.crypto.util.Pack; +import org.bouncycastle.util.Arrays; + +public class Tables8kGCMMultiplier implements GCMMultiplier +{ + private byte[] H; + private int[][][] M; + + public void init(byte[] H) + { + if (M == null) + { + M = new int[32][16][4]; + } + else if (Arrays.areEqual(this.H, H)) + { + return; + } + + this.H = Arrays.clone(H); + + // M[0][0] is ZEROES; + // M[1][0] is ZEROES; + GCMUtil.asInts(H, M[1][8]); + + for (int j = 4; j >= 1; j >>= 1) + { + GCMUtil.multiplyP(M[1][j + j], M[1][j]); + } + + GCMUtil.multiplyP(M[1][1], M[0][8]); + + for (int j = 4; j >= 1; j >>= 1) + { + GCMUtil.multiplyP(M[0][j + j], M[0][j]); + } + + int i = 0; + for (;;) + { + for (int j = 2; j < 16; j += j) + { + for (int k = 1; k < j; ++k) + { + GCMUtil.xor(M[i][j], M[i][k], M[i][j + k]); + } + } + + if (++i == 32) + { + return; + } + + if (i > 1) + { + // M[i][0] is ZEROES; + for(int j = 8; j > 0; j >>= 1) + { + GCMUtil.multiplyP8(M[i - 2][j], M[i][j]); + } + } + } + } + + public void multiplyH(byte[] x) + { +// assert x.Length == 16; + + int[] z = new int[4]; + for (int i = 15; i >= 0; --i) + { +// GCMUtil.xor(z, M[i + i][x[i] & 0x0f]); + int[] m = M[i + i][x[i] & 0x0f]; + z[0] ^= m[0]; + z[1] ^= m[1]; + z[2] ^= m[2]; + z[3] ^= m[3]; +// GCMUtil.xor(z, M[i + i + 1][(x[i] & 0xf0) >>> 4]); + m = M[i + i + 1][(x[i] & 0xf0) >>> 4]; + z[0] ^= m[0]; + z[1] ^= m[1]; + z[2] ^= m[2]; + z[3] ^= m[3]; + } + + Pack.intToBigEndian(z, x, 0); + } +}
\ No newline at end of file |