private void gCTRBlock(byte[] block, byte[] out, int outOff) { byte[] tmp = getNextCounterBlock(); GCMUtil.xor(tmp, block); System.arraycopy(tmp, 0, out, outOff, BLOCK_SIZE); gHASHBlock(S, forEncryption ? tmp : block); totalLength += BLOCK_SIZE; }
private void gCTRPartial(byte[] buf, int off, int len, byte[] out, int outOff) { byte[] tmp = getNextCounterBlock(); GCMUtil.xor(tmp, buf, off, len); System.arraycopy(tmp, 0, out, outOff, len); gHASHPartial(S, forEncryption ? tmp : buf, 0, len); totalLength += len; }
private void gHASHPartial(byte[] Y, byte[] b, int off, int len) { GCMUtil.xor(Y, b, off, len); multiplier.multiplyH(Y); }
private void gHASHBlock(byte[] Y, byte[] b) { GCMUtil.xor(Y, b); multiplier.multiplyH(Y); }
@Override public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException { if (totalLength == 0) { initCipher(); } int extra = bufOff; if (forEncryption) { if (out.length < (outOff + extra + macSize)) { throw new OutputLengthException("Output buffer too short"); } } else { if (extra < macSize) { throw new InvalidCipherTextException("data too short"); } extra -= macSize; if (out.length < (outOff + extra)) { throw new OutputLengthException("Output buffer too short"); } } if (extra > 0) { gCTRPartial(bufBlock, 0, extra, out, outOff); } atLength += atBlockPos; if (atLength > atLengthPre) { /* * Some AAD was sent after the cipher started. We determine the difference b/w the hash value * we actually used when the cipher started (S_atPre) and the final hash value calculated * (S_at). Then we carry this difference forward by multiplying by H^c, where c is the number * of (full or partial) cipher-text blocks produced, and adjust the current hash. */ // Finish hash for partial AAD block if (atBlockPos > 0) { gHASHPartial(S_at, atBlock, 0, atBlockPos); } // Find the difference between the AAD hashes if (atLengthPre > 0) { GCMUtil.xor(S_at, S_atPre); } // Number of cipher-text blocks produced long c = ((totalLength * 8) + 127) >>> 7; // Calculate the adjustment factor byte[] H_c = new byte[16]; if (exp == null) { exp = new Tables1kGCMExponentiator(); exp.init(H); } exp.exponentiateX(c, H_c); // Carry the difference forward GCMUtil.multiply(S_at, H_c); // Adjust the current hash GCMUtil.xor(S, S_at); } // Final gHASH byte[] X = new byte[BLOCK_SIZE]; Pack.longToBigEndian(atLength * 8, X, 0); Pack.longToBigEndian(totalLength * 8, X, 8); gHASHBlock(S, X); // T = MSBt(GCTRk(J0,S)) byte[] tag = new byte[BLOCK_SIZE]; cipher.processBlock(J0, 0, tag, 0); GCMUtil.xor(tag, S); int resultLen = extra; // We place into macBlock our calculated value for T this.macBlock = new byte[macSize]; System.arraycopy(tag, 0, macBlock, 0, macSize); if (forEncryption) { // Append T to the message System.arraycopy(macBlock, 0, out, outOff + bufOff, macSize); resultLen += macSize; } else { // Retrieve the T value from the message and compare to calculated one byte[] msgMac = new byte[macSize]; System.arraycopy(bufBlock, extra, msgMac, 0, macSize); if (!Arrays.constantTimeAreEqual(this.macBlock, msgMac)) { throw new InvalidCipherTextException("mac check in GCM failed"); } } reset(false); return resultLen; }