Skip to content

Instantly share code, notes, and snippets.

@hanswolff
Last active August 29, 2015 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hanswolff/9089707 to your computer and use it in GitHub Desktop.
Save hanswolff/9089707 to your computer and use it in GitHub Desktop.
GHash method for Galois/Counter Mode used in AES GCM
// The MIT License (MIT)
// Copyright (c) 2014 Hans Wolff
// Source: https://gist.github.com/hanswolff/9089707
// Contains translated parts made by Juho Vähä-Herttua
// Source: https://github.com/bitwiseshiftleft/sjcl/blob/master/core/gcm.js
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
/// <summary>
/// GHash method for Galois/Counter Mode used in AES GCM
/// </summary>
public class GHash128
{
public static int[] GHash(int[] h, int[] a, byte[] c)
{
if (h == null) throw new ArgumentNullException("h");
if (h.Length != 4) throw new ArgumentException("h length must be 4", "h");
if (a == null) throw new ArgumentNullException("a");
if (a.Length != 4) throw new ArgumentException("a length must be 4", "a");
if (c == null) throw new ArgumentNullException("c");
if (c.Length % 4 != 0) throw new ArgumentException("c length must be multiple of 4", "c");
var yi = new int[a.Length];
Array.Copy(a, yi, a.Length);
for (var i = 0; i < c.Length; i += 4)
{
yi[0] ^= (int)(0xffffffff & c[i]);
yi[1] ^= (int)(0xffffffff & c[i + 1]);
yi[2] ^= (int)(0xffffffff & c[i + 2]);
yi[3] ^= (int)(0xffffffff & c[i + 3]);
yi = GaloisMultiply(yi, h);
}
return yi;
}
public static int[] GaloisMultiply(int[] x, int[] y)
{
if (x == null) throw new ArgumentNullException("x");
if (x.Length != 4) throw new ArgumentException("x length must be 4", "x");
if (y == null) throw new ArgumentNullException("y");
if (y.Length != 4) throw new ArgumentException("y length must be 4", "x");
var zi = new int[4];
var vi = new int[y.Length];
Array.Copy(y, vi, y.Length);
// Block size is 128 bits, run 128 times to get Z_128
for (var i = 0; i < 128; i++)
{
var xi = ((x[i / 32] & (1 << (31 - i % 32))) != 0);
if (xi)
{
// Z_i+1 = Z_i ^ V_i
Xor(zi, vi);
}
// Store the value of LSB(V_i)
var lsbVi = (vi[3] & 1) != 0;
// V_i+1 = V_i >> 1
for (var j = 3; j > 0; j--)
{
vi[j] = (int)((uint)vi[j] >> 1) | ((vi[j - 1] & 1) << 31);
}
vi[0] = (int)((uint)vi[0] >> 1);
// If LSB(V_i) is 1, V_i+1 = (V_i >> 1) ^ R
if (lsbVi)
{
vi[0] = vi[0] ^ (0xe1 << 24);
}
}
return zi;
}
static void Xor(int[] x, int[] y)
{
if (x == null) throw new ArgumentNullException("x");
if (y == null) throw new ArgumentNullException("y");
if (x.Length != y.Length)
throw new ArgumentException("x length and y length must be equal");
for (var i = 0; i < x.Length; i++)
{
x[i] ^= y[i];
}
}
}
//using NUnit.Framework;
//
//[TestFixture]
//public class GHash128Tests
//{
// [TestCase(new[] { 0, 0, 0, 0 }, new[] { 0, 0, 0, 0 }, new[] { 0, 0, 0, 0 })]
// [TestCase(new[] { 0, 0, 0, 0 }, new[] { 0, 0, 0, 1 }, new[] { 0, 0, 0, 0 })]
// [TestCase(new[] { 0, 0, 0, 1 }, new[] { 0, 0, 0, 1 }, new[] { -435683328, 0, 0, 3 })]
// [TestCase(new[] { 0, 1, 1, 1 }, new[] { 0, 1, 1, 1 }, new[] { -435683328, 3, -2080374784, 1 })]
// [TestCase(new[] { 0, 1, 1, 1 }, new[] { 0, 1, 1, 1 }, new[] { -435683328, 3, -2080374784, 1 })]
// [TestCase(new[] { 1, 1, 1, 1 }, new[] { 1, 1, 1, 1 }, new[] { -435683328, 1, -2080374784, 1 })]
// [TestCase(new[] { 1, 1, 1, 1 }, new[] { 1, 1, 1, 1 }, new[] { -435683328, 1, -2080374784, 1 })]
// [TestCase(new[] { 2, 3, 4, 5 }, new[] { 6, 7, 8, 9 }, new[] { 594018332, 536871016, -2147483622, 805306467 })]
// [TestCase(new[] { 2, 3, 4, 5 }, new[] { -6, -7, -8, -9 }, new[] { 827850809, 1207959497, 335544235, -1677721522 })]
// public void GaloisMultiply(int[] x, int[] y, int[] expectedResult)
// {
// var result = GHash128.GaloisMultiply(x, y);
// Assert.AreEqual(expectedResult, result);
// }
// [TestCase(new[] { 0, 0, 0, 0 }, new[] { 0, 0, 0, 0 }, new byte[] { 0, 0, 0, 0 }, new[] { 0, 0, 0, 0 })]
// [TestCase(new[] { 0, 0, 0, 0 }, new[] { 0, 0, 0, 0 }, new byte[] { 1, 2, 3, 4 }, new[] { 0, 0, 0, 0 })]
// [TestCase(new[] { 0, 0, 0, 0 }, new[] { 0, 0, 0, 1 }, new byte[] { 0, 0, 0, 0 }, new[] { 0, 0, 0, 0 })]
// [TestCase(new[] { 0, 0, 0, 1 }, new[] { 0, 0, 0, 0 }, new byte[] { 0, 0, 0, 0 }, new[] { 0, 0, 0, 0 })]
// [TestCase(new[] { 0, 0, 0, 1 }, new[] { 0, 0, 0, 1 }, new byte[] { 0, 0, 0, 0 }, new[] { -435683328, 0, 0, 3 })]
// [TestCase(new[] { 0, 0, 0, 1 }, new[] { 0, 0, 0, 1 }, new byte[] { 1, 2, 3, 4 }, new[] { -98041853, -2080374777, 134217732, -1946157043 })]
// [TestCase(new[] { 0, 0, 0, 1 }, new[] { 0, 0, 0, 1 }, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }, new[] { 1219272712, -737148925, -1742733307, 1546649612 })]
// public void GHash(int[] h, int[] a, byte[] c, int[] expectedHash)
// {
// var result = GHash128.GHash(h, a, c);
// Assert.AreEqual(expectedHash, result);
// }
//}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment