package org.bouncycastle.crypto.modes.gcm; import org.bouncycastle.util.Pack; public abstract class GCMUtil { private static final int E1 = 0xe1000000; private static final long E1L = (E1 & 0xFFFFFFFFL) << 32; private static int[] generateLookup() { int[] lookup = new int[256]; for (int c = 0; c < 256; ++c) { int v = 0; for (int i = 7; i >= 0; --i) { if ((c & (1 << i)) != 0) { v ^= (E1 >>> (7 - i)); } } lookup[c] = v; } return lookup; } private static final int[] LOOKUP = generateLookup(); public static byte[] oneAsBytes() { byte[] tmp = new byte[16]; tmp[0] = (byte)0x80; return tmp; } public static int[] oneAsInts() { int[] tmp = new int[4]; tmp[0] = 1 << 31; return tmp; } public static long[] oneAsLongs() { long[] tmp = new long[2]; tmp[0] = 1L << 63; return tmp; } public static byte[] asBytes(int[] x) { byte[] z = new byte[16]; Pack.intToBigEndian(x, z, 0); return z; } public static void asBytes(int[] x, byte[] z) { Pack.intToBigEndian(x, z, 0); } public static byte[] asBytes(long[] x) { byte[] z = new byte[16]; Pack.longToBigEndian(x, z, 0); return z; } public static void asBytes(long[] x, byte[] z) { Pack.longToBigEndian(x, z, 0); } public static int[] asInts(byte[] x) { int[] z = new int[4]; Pack.bigEndianToInt(x, 0, z); return z; } public static void asInts(byte[] x, int[] z) { Pack.bigEndianToInt(x, 0, z); } public static long[] asLongs(byte[] x) { long[] z = new long[2]; Pack.bigEndianToLong(x, 0, z); return z; } public static void asLongs(byte[] x, long[] z) { Pack.bigEndianToLong(x, 0, z); } public static void multiply(byte[] x, byte[] y) { int[] t1 = GCMUtil.asInts(x); int[] t2 = GCMUtil.asInts(y); GCMUtil.multiply(t1, t2); GCMUtil.asBytes(t1, x); } public static void multiply(int[] x, int[] y) { int r00 = x[0], r01 = x[1], r02 = x[2], r03 = x[3]; int r10 = 0, r11 = 0, r12 = 0, r13 = 0; for (int i = 0; i < 4; ++i) { int bits = y[i]; for (int j = 0; j < 32; ++j) { int m1 = bits >> 31; bits <<= 1; r10 ^= (r00 & m1); r11 ^= (r01 & m1); r12 ^= (r02 & m1); r13 ^= (r03 & m1); int m2 = (r03 << 31) >> 8; r03 = (r03 >>> 1) | (r02 << 31); r02 = (r02 >>> 1) | (r01 << 31); r01 = (r01 >>> 1) | (r00 << 31); r00 = (r00 >>> 1) ^ (m2 & E1); } } x[0] = r10; x[1] = r11; x[2] = r12; x[3] = r13; } public static void multiply(long[] x, long[] y) { long r00 = x[0], r01 = x[1], r10 = 0, r11 = 0; for (int i = 0; i < 2; ++i) { long bits = y[i]; for (int j = 0; j < 64; ++j) { long m1 = bits >> 63; bits <<= 1; r10 ^= (r00 & m1); r11 ^= (r01 & m1); long m2 = (r01 << 63) >> 8; r01 = (r01 >>> 1) | (r00 << 63); r00 = (r00 >>> 1) ^ (m2 & E1L); } } x[0] = r10; x[1] = r11; } // P is the value with only bit i=1 set public static void multiplyP(int[] x) { int m = shiftRight(x) >> 8; x[0] ^= (m & E1); } public static void multiplyP(int[] x, int[] z) { int m = shiftRight(x, z) >> 8; z[0] ^= (m & E1); } // P is the value with only bit i=1 set public static void multiplyP8(int[] x) { // for (int i = 8; i != 0; --i) // { // multiplyP(x); // } int c = shiftRightN(x, 8); x[0] ^= LOOKUP[c >>> 24]; } public static void multiplyP8(int[] x, int[] y) { int c = shiftRightN(x, 8, y); y[0] ^= LOOKUP[c >>> 24]; } static int shiftRight(int[] x) { // int c = 0; // for (int i = 0; i < 4; ++i) // { // int b = x[i]; // x[i] = (b >>> 1) | c; // c = b << 31; // } // return c; int b = x[0]; x[0] = b >>> 1; int c = b << 31; b = x[1]; x[1] = (b >>> 1) | c; c = b << 31; b = x[2]; x[2] = (b >>> 1) | c; c = b << 31; b = x[3]; x[3] = (b >>> 1) | c; return b << 31; } static int shiftRight(int[] x, int[] z) { // int c = 0; // for (int i = 0; i < 4; ++i) // { // int b = x[i]; // z[i] = (b >>> 1) | c; // c = b << 31; // } // return c; int b = x[0]; z[0] = b >>> 1; int c = b << 31; b = x[1]; z[1] = (b >>> 1) | c; c = b << 31; b = x[2]; z[2] = (b >>> 1) | c; c = b << 31; b = x[3]; z[3] = (b >>> 1) | c; return b << 31; } static long shiftRight(long[] x) { long b = x[0]; x[0] = b >>> 1; long c = b << 63; b = x[1]; x[1] = (b >>> 1) | c; return b << 63; } static long shiftRight(long[] x, long[] z) { long b = x[0]; z[0] = b >>> 1; long c = b << 63; b = x[1]; z[1] = (b >>> 1) | c; return b << 63; } static int shiftRightN(int[] x, int n) { // int c = 0, nInv = 32 - n; // for (int i = 0; i < 4; ++i) // { // int b = x[i]; // x[i] = (b >>> n) | c; // c = b << nInv; // } // return c; int b = x[0], nInv = 32 - n; x[0] = b >>> n; int c = b << nInv; b = x[1]; x[1] = (b >>> n) | c; c = b << nInv; b = x[2]; x[2] = (b >>> n) | c; c = b << nInv; b = x[3]; x[3] = (b >>> n) | c; return b << nInv; } static int shiftRightN(int[] x, int n, int[] z) { // int c = 0, nInv = 32 - n; // for (int i = 0; i < 4; ++i) // { // int b = x[i]; // z[i] = (b >>> n) | c; // c = b << nInv; // } // return c; int b = x[0], nInv = 32 - n; z[0] = b >>> n; int c = b << nInv; b = x[1]; z[1] = (b >>> n) | c; c = b << nInv; b = x[2]; z[2] = (b >>> n) | c; c = b << nInv; b = x[3]; z[3] = (b >>> n) | c; return b << nInv; } public static void xor(byte[] x, byte[] y) { int i = 0; do { x[i] ^= y[i]; ++i; x[i] ^= y[i]; ++i; x[i] ^= y[i]; ++i; x[i] ^= y[i]; ++i; } while (i < 16); } public static void xor(byte[] x, byte[] y, int yOff, int yLen) { while (--yLen >= 0) { x[yLen] ^= y[yOff + yLen]; } } public static void xor(byte[] x, byte[] y, byte[] z) { int i = 0; do { z[i] = (byte)(x[i] ^ y[i]); ++i; z[i] = (byte)(x[i] ^ y[i]); ++i; z[i] = (byte)(x[i] ^ y[i]); ++i; z[i] = (byte)(x[i] ^ y[i]); ++i; } while (i < 16); } public static void xor(int[] x, int[] y) { x[0] ^= y[0]; x[1] ^= y[1]; x[2] ^= y[2]; x[3] ^= y[3]; } public static void xor(int[] x, int[] y, int[] z) { z[0] = x[0] ^ y[0]; z[1] = x[1] ^ y[1]; z[2] = x[2] ^ y[2]; z[3] = x[3] ^ y[3]; } public static void xor(long[] x, long[] y) { x[0] ^= y[0]; x[1] ^= y[1]; } public static void xor(long[] x, long[] y, long[] z) { z[0] = x[0] ^ y[0]; z[1] = x[1] ^ y[1]; } }