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); } }