public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
this.forEncryption = forEncryption;
this.macSize = 16; // TODO Make configurable?
this.macBlock = null;
// TODO If macSize limitation is removed, be very careful about bufBlock
int bufLength = forEncryption ? BlockSize : (BlockSize + macSize);
this.bufBlock = new byte[bufLength];
if (parameters is AeadParameters)
{
AeadParameters param = (AeadParameters)parameters;
nonce = param.GetNonce();
A = param.GetAssociatedText();
// macSize = param.getMacSize() / 8;
if (param.MacSize != 128)
{
// TODO Make configurable?
throw new ArgumentException("only 128-bit MAC supported currently");
}
keyParam = param.Key;
}
else if (parameters is ParametersWithIV)
{
ParametersWithIV param = (ParametersWithIV)parameters;
nonce = param.GetIV();
A = null;
keyParam = (KeyParameter)param.Parameters;
}
else
{
throw new ArgumentException("invalid parameters passed to GCM");
}
if (nonce == null || nonce.Length < 1)
{
throw new ArgumentException("IV must be at least 1 byte");
}
if (A == null)
{
// Avoid lots of null checks
A = new byte[0];
}
// Cipher always used input forward mode
cipher.Init(true, keyParam);
// TODO This should be configurable by Init parameters
// (but must be 16 if nonce length not 12) (BlockSize?)
// this.tagLength = 16;
byte[] h = new byte[BlockSize];
cipher.ProcessBlock(Zeroes, 0, h, 0);
//trace("H: " + new string(Hex.encode(h)));
this.H = new BigInteger(1, h);
this.initS = gHASH(A, false);
if (nonce.Length == 12)
{
this.J0 = new byte[16];
Array.Copy(nonce, 0, J0, 0, nonce.Length);
this.J0[15] = 0x01;
}
else
{
BigInteger N = gHASH(nonce, true);
BigInteger X = BigInteger.ValueOf(nonce.Length * 8);
//trace("len({})||len(IV): " + dumpBigInt(X));
N = multiply(N.Xor(X), H);
//trace("GHASH(H,{},IV): " + dumpBigInt(N));
this.J0 = asBlock(N);
}
this.S = initS;
this.counter = Arrays.Clone(J0);
//trace("Y" + yCount + ": " + new string(Hex.encode(counter)));
this.bufOff = 0;
this.totalLength = 0;
}