public int DoFinal(byte[] output, int outOff) { int bufOff = this.bufOff; if (!this.forEncryption) { if (bufOff < this.macSize) { throw new InvalidCipherTextException("data too short"); } bufOff -= this.macSize; } if (bufOff > 0) { byte[] buf = new byte[16]; Array.Copy((Array)this.bufBlock, 0, (Array)buf, 0, bufOff); this.gCTRBlock(buf, bufOff, output, outOff); } byte[] numArray1 = new byte[16]; GcmBlockCipher.packLength((ulong)this.A.Length * 8UL, numArray1, 0); GcmBlockCipher.packLength(this.totalLength * 8UL, numArray1, 8); GcmUtilities.Xor(this.S, numArray1); this.multiplier.MultiplyH(this.S); byte[] numArray2 = new byte[16]; this.cipher.ProcessBlock(this.J0, 0, numArray2, 0); GcmUtilities.Xor(numArray2, this.S); int num = bufOff; this.macBlock = new byte[this.macSize]; Array.Copy((Array)numArray2, 0, (Array)this.macBlock, 0, this.macSize); if (this.forEncryption) { Array.Copy((Array)this.macBlock, 0, (Array)output, outOff + this.bufOff, this.macSize); num += this.macSize; } else { byte[] b = new byte[this.macSize]; Array.Copy((Array)this.bufBlock, bufOff, (Array)b, 0, this.macSize); if (!Arrays.ConstantTimeAreEqual(this.macBlock, b)) { throw new InvalidCipherTextException("mac check in GCM failed"); } } this.Reset(false); return(num); }
public virtual void Init(bool forEncryption, ICipherParameters parameters) { this.forEncryption = forEncryption; this.macBlock = (byte[])null; if (parameters is AeadParameters) { AeadParameters aeadParameters = (AeadParameters)parameters; this.nonce = aeadParameters.GetNonce(); this.A = aeadParameters.GetAssociatedText(); int macSize = aeadParameters.MacSize; if (macSize < 96 || macSize > 128 || macSize % 8 != 0) { throw new ArgumentException("Invalid value for MAC size: " + (object)macSize); } this.macSize = macSize / 8; this.keyParam = aeadParameters.Key; } else { if (!(parameters is ParametersWithIV)) { throw new ArgumentException("invalid parameters passed to GCM"); } ParametersWithIV parametersWithIv = (ParametersWithIV)parameters; this.nonce = parametersWithIv.GetIV(); this.A = (byte[])null; this.macSize = 16; this.keyParam = (KeyParameter)parametersWithIv.Parameters; } this.bufBlock = new byte[forEncryption ? 16 : 16 + this.macSize]; if (this.nonce == null || this.nonce.Length < 1) { throw new ArgumentException("IV must be at least 1 byte"); } if (this.A == null) { this.A = new byte[0]; } this.cipher.Init(true, (ICipherParameters)this.keyParam); this.H = new byte[16]; this.cipher.ProcessBlock(this.H, 0, this.H, 0); this.multiplier.Init(this.H); this.initS = this.gHASH(this.A); if (this.nonce.Length == 12) { this.J0 = new byte[16]; Array.Copy((Array)this.nonce, 0, (Array)this.J0, 0, this.nonce.Length); this.J0[15] = (byte)1; } else { this.J0 = this.gHASH(this.nonce); byte[] numArray = new byte[16]; GcmBlockCipher.packLength((ulong)this.nonce.Length * 8UL, numArray, 8); GcmUtilities.Xor(this.J0, numArray); this.multiplier.MultiplyH(this.J0); } this.S = Arrays.Clone(this.initS); this.counter = Arrays.Clone(this.J0); this.bufOff = 0; this.totalLength = 0UL; }