diff --git a/Crypto/src/crypto/modes/gcm/BasicGcmExponentiator.cs b/Crypto/src/crypto/modes/gcm/BasicGcmExponentiator.cs
new file mode 100644
index 000000000..98049e1db
--- /dev/null
+++ b/Crypto/src/crypto/modes/gcm/BasicGcmExponentiator.cs
@@ -0,0 +1,40 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+ public class BasicGcmExponentiator
+ : IGcmExponentiator
+ {
+ 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 = GcmUtilities.OneAsBytes();
+
+ if (pow > 0)
+ {
+ byte[] powX = Arrays.Clone(x);
+ do
+ {
+ if ((pow & 1L) != 0)
+ {
+ GcmUtilities.Multiply(y, powX);
+ }
+ GcmUtilities.Multiply(powX, powX);
+ pow >>= 1;
+ }
+ while (pow > 0);
+ }
+
+ Array.Copy(y, 0, output, 0, 16);
+ }
+ }
+}
diff --git a/Crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs b/Crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs
new file mode 100644
index 000000000..4076de990
--- /dev/null
+++ b/Crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+ public class BasicGcmMultiplier
+ : IGcmMultiplier
+ {
+ private byte[] H;
+
+ public void Init(byte[] H)
+ {
+ this.H = (byte[])H.Clone();
+ }
+
+ public void MultiplyH(byte[] x)
+ {
+ GcmUtilities.Multiply(x, H);
+ }
+ }
+}
diff --git a/Crypto/src/crypto/modes/gcm/GcmUtilities.cs b/Crypto/src/crypto/modes/gcm/GcmUtilities.cs
new file mode 100644
index 000000000..8da125641
--- /dev/null
+++ b/Crypto/src/crypto/modes/gcm/GcmUtilities.cs
@@ -0,0 +1,149 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+ internal abstract class GcmUtilities
+ {
+ internal static byte[] OneAsBytes()
+ {
+ byte[] tmp = new byte[16];
+ tmp[0] = 0x80;
+ return tmp;
+ }
+
+ internal static uint[] OneAsUints()
+ {
+ uint[] tmp = new uint[4];
+ tmp[0] = 0x80000000;
+ return tmp;
+ }
+
+ internal static uint[] AsUints(byte[] bs)
+ {
+ uint[] us = new uint[4];
+ us[0] = Pack.BE_To_UInt32(bs, 0);
+ us[1] = Pack.BE_To_UInt32(bs, 4);
+ us[2] = Pack.BE_To_UInt32(bs, 8);
+ us[3] = Pack.BE_To_UInt32(bs, 12);
+ return us;
+ }
+
+ internal 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);
+ }
+
+ bool lsb = (tmp[15] & 1) != 0;
+ ShiftRight(tmp);
+ if (lsb)
+ {
+ // R = new byte[]{ 0xe1, ... };
+ //GCMUtilities.Xor(tmp, R);
+ tmp[0] ^= (byte)0xe1;
+ }
+ }
+ }
+
+ Array.Copy(c, 0, block, 0, 16);
+ }
+
+ // P is the value with only bit i=1 set
+ internal static void MultiplyP(uint[] x)
+ {
+ bool lsb = (x[3] & 1) != 0;
+ ShiftRight(x);
+ if (lsb)
+ {
+ // R = new uint[]{ 0xe1000000, 0, 0, 0 };
+ //Xor(v, R);
+ x[0] ^= 0xe1000000;
+ }
+ }
+
+ internal static void MultiplyP8(uint[] x)
+ {
+// for (int i = 8; i != 0; --i)
+// {
+// MultiplyP(x);
+// }
+
+ uint lsw = x[3];
+ ShiftRightN(x, 8);
+ for (int i = 7; i >= 0; --i)
+ {
+ if ((lsw & (1 << i)) != 0)
+ {
+ x[0] ^= (0xe1000000 >> (7 - i));
+ }
+ }
+ }
+
+ internal static void ShiftRight(byte[] block)
+ {
+ int i = 0;
+ byte bit = 0;
+ for (;;)
+ {
+ byte b = block[i];
+ block[i] = (byte)((b >> 1) | bit);
+ if (++i == 16) break;
+ bit = (byte)(b << 7);
+ }
+ }
+
+ internal static void ShiftRight(uint[] block)
+ {
+ int i = 0;
+ uint bit = 0;
+ for (;;)
+ {
+ uint b = block[i];
+ block[i] = (b >> 1) | bit;
+ if (++i == 4) break;
+ bit = b << 31;
+ }
+ }
+
+ internal static void ShiftRightN(uint[] block, int n)
+ {
+ int i = 0;
+ uint bit = 0;
+ for (;;)
+ {
+ uint b = block[i];
+ block[i] = (b >> n) | bit;
+ if (++i == 4) break;
+ bit = b << (32 - n);
+ }
+ }
+
+ internal static void Xor(byte[] block, byte[] val)
+ {
+ for (int i = 15; i >= 0; --i)
+ {
+ block[i] ^= val[i];
+ }
+ }
+
+ internal static void Xor(uint[] block, uint[] val)
+ {
+ for (int i = 3; i >= 0; --i)
+ {
+ block[i] ^= val[i];
+ }
+ }
+ }
+}
diff --git a/Crypto/src/crypto/modes/gcm/IGcmExponentiator.cs b/Crypto/src/crypto/modes/gcm/IGcmExponentiator.cs
new file mode 100644
index 000000000..5b4ce9d7a
--- /dev/null
+++ b/Crypto/src/crypto/modes/gcm/IGcmExponentiator.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+ public interface IGcmExponentiator
+ {
+ void Init(byte[] x);
+ void ExponentiateX(long pow, byte[] output);
+ }
+}
diff --git a/Crypto/src/crypto/modes/gcm/IGcmMultiplier.cs b/Crypto/src/crypto/modes/gcm/IGcmMultiplier.cs
new file mode 100644
index 000000000..ec7b906ee
--- /dev/null
+++ b/Crypto/src/crypto/modes/gcm/IGcmMultiplier.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+ public interface IGcmMultiplier
+ {
+ void Init(byte[] H);
+ void MultiplyH(byte[] x);
+ }
+}
diff --git a/Crypto/src/crypto/modes/gcm/Tables1kGcmExponentiator.cs b/Crypto/src/crypto/modes/gcm/Tables1kGcmExponentiator.cs
new file mode 100644
index 000000000..9425a3d9d
--- /dev/null
+++ b/Crypto/src/crypto/modes/gcm/Tables1kGcmExponentiator.cs
@@ -0,0 +1,44 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+ public class Tables1kGcmExponentiator
+ : IGcmExponentiator
+ {
+ // A lookup table of the power-of-two powers of 'x'
+ private byte[][] lookupPowX2 = new byte[64][];
+
+ public void Init(byte[] x)
+ {
+ lookupPowX2[0] = GcmUtilities.OneAsBytes();
+ lookupPowX2[1] = Arrays.Clone(x);
+
+ for (int i = 2; i != 64; ++i)
+ {
+ byte[] tmp = Arrays.Clone(lookupPowX2[i - 1]);
+ GcmUtilities.Multiply(tmp, tmp);
+ lookupPowX2[i] = tmp;
+ }
+ }
+
+ public void ExponentiateX(long pow, byte[] output)
+ {
+ byte[] y = GcmUtilities.OneAsBytes();
+ int powX2 = 1;
+
+ while (pow > 0)
+ {
+ if ((pow & 1L) != 0)
+ {
+ GcmUtilities.Multiply(y, lookupPowX2[powX2]);
+ }
+ ++powX2;
+ pow >>= 1;
+ }
+
+ Array.Copy(y, 0, output, 0, 16);
+ }
+ }
+}
diff --git a/Crypto/src/crypto/modes/gcm/Tables64kGcmMultiplier.cs b/Crypto/src/crypto/modes/gcm/Tables64kGcmMultiplier.cs
new file mode 100644
index 000000000..f089dfe8d
--- /dev/null
+++ b/Crypto/src/crypto/modes/gcm/Tables64kGcmMultiplier.cs
@@ -0,0 +1,64 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+ public class Tables64kGcmMultiplier
+ : IGcmMultiplier
+ {
+ private readonly uint[][][] M = new uint[16][][];
+
+ public void Init(byte[] H)
+ {
+ M[0] = new uint[256][];
+ M[0][0] = new uint[4];
+ M[0][128] = GcmUtilities.AsUints(H);
+ for (int j = 64; j >= 1; j >>= 1)
+ {
+ uint[] tmp = (uint[])M[0][j + j].Clone();
+ GcmUtilities.MultiplyP(tmp);
+ M[0][j] = tmp;
+ }
+ for (int i = 0;;)
+ {
+ for (int j = 2; j < 256; j += j)
+ {
+ for (int k = 1; k < j; ++k)
+ {
+ uint[] tmp = (uint[])M[i][j].Clone();
+ GcmUtilities.Xor(tmp, M[i][k]);
+ M[i][j + k] = tmp;
+ }
+ }
+
+ if (++i == 16) return;
+
+ M[i] = new uint[256][];
+ M[i][0] = new uint[4];
+ for (int j = 128; j > 0; j >>= 1)
+ {
+ uint[] tmp = (uint[])M[i - 1][j].Clone();
+ GcmUtilities.MultiplyP8(tmp);
+ M[i][j] = tmp;
+ }
+ }
+ }
+
+ public void MultiplyH(byte[] x)
+ {
+ uint[] z = new uint[4];
+ for (int i = 0; i != 16; ++i)
+ {
+ //GcmUtilities.Xor(z, M[i][x[i]]);
+ uint[] m = M[i][x[i]];
+ z[0] ^= m[0];
+ z[1] ^= m[1];
+ z[2] ^= m[2];
+ z[3] ^= m[3];
+ }
+
+ Pack.UInt32_To_BE(z, x, 0);
+ }
+ }
+}
diff --git a/Crypto/src/crypto/modes/gcm/Tables8kGcmMultiplier.cs b/Crypto/src/crypto/modes/gcm/Tables8kGcmMultiplier.cs
new file mode 100644
index 000000000..91d58fab8
--- /dev/null
+++ b/Crypto/src/crypto/modes/gcm/Tables8kGcmMultiplier.cs
@@ -0,0 +1,90 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+ public class Tables8kGcmMultiplier
+ : IGcmMultiplier
+ {
+ private readonly uint[][][] M = new uint[32][][];
+
+ public void Init(byte[] H)
+ {
+ M[0] = new uint[16][];
+ M[1] = new uint[16][];
+ M[0][0] = new uint[4];
+ M[1][0] = new uint[4];
+ M[1][8] = GcmUtilities.AsUints(H);
+
+ for (int j = 4; j >= 1; j >>= 1)
+ {
+ uint[] tmp = (uint[])M[1][j + j].Clone();
+ GcmUtilities.MultiplyP(tmp);
+ M[1][j] = tmp;
+ }
+
+ {
+ uint[] tmp = (uint[])M[1][1].Clone();
+ GcmUtilities.MultiplyP(tmp);
+ M[0][8] = tmp;
+ }
+
+ for (int j = 4; j >= 1; j >>= 1)
+ {
+ uint[] tmp = (uint[])M[0][j + j].Clone();
+ GcmUtilities.MultiplyP(tmp);
+ M[0][j] = tmp;
+ }
+
+ for (int i = 0;;)
+ {
+ for (int j = 2; j < 16; j += j)
+ {
+ for (int k = 1; k < j; ++k)
+ {
+ uint[] tmp = (uint[])M[i][j].Clone();
+ GcmUtilities.Xor(tmp, M[i][k]);
+ M[i][j + k] = tmp;
+ }
+ }
+
+ if (++i == 32) return;
+
+ if (i > 1)
+ {
+ M[i] = new uint[16][];
+ M[i][0] = new uint[4];
+ for(int j = 8; j > 0; j >>= 1)
+ {
+ uint[] tmp = (uint[])M[i - 2][j].Clone();
+ GcmUtilities.MultiplyP8(tmp);
+ M[i][j] = tmp;
+ }
+ }
+ }
+ }
+
+ public void MultiplyH(byte[] x)
+ {
+ uint[] z = new uint[4];
+ for (int i = 15; i >= 0; --i)
+ {
+ //GcmUtilities.Xor(z, M[i + i][x[i] & 0x0f]);
+ uint[] m = M[i + i][x[i] & 0x0f];
+ z[0] ^= m[0];
+ z[1] ^= m[1];
+ z[2] ^= m[2];
+ z[3] ^= m[3];
+ //GcmUtilities.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.UInt32_To_BE(z, x, 0);
+ }
+ }
+}
|