AesGcmHkdfStreaming extends NonceBasedStreamingAead { public long expectedCiphertextSize(long plaintextSize) { long offset = getCiphertextOffset(); long fullSegments = (plaintextSize + offset) / plaintextSegmentSize; long ciphertextSize = fullSegments * ciphertextSegmentSize; long lastSegmentSize = (plaintextSize + offset) % plaintextSegmentSize; if (lastSegmentSize > 0) { ciphertextSize += lastSegmentSize + TAG_SIZE_IN_BYTES; } return ciphertextSize; } AesGcmHkdfStreaming(byte[] ikm, String hkdfAlg, int keySizeInBytes,
      int ciphertextSegmentSize, int firstSegmentOffset); @Override AesGcmHkdfStreamEncrypter newStreamSegmentEncrypter(byte[] aad); @Override AesGcmHkdfStreamDecrypter newStreamSegmentDecrypter(); @Override int getPlaintextSegmentSize(); @Override int getCiphertextSegmentSize(); @Override int getHeaderLength(); @Override int getCiphertextOffset(); @Override int getCiphertextOverhead(); int getFirstSegmentOffset(); long expectedCiphertextSize(long plaintextSize);  }
@Test public void testEncryptLimitedCiphertextChannel() throws Exception { int segmentSize = 512; int firstSegmentOffset = 0; int keySizeInBytes = 16; byte[] ikm = TestUtil.hexDecode("000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff"); AesGcmHkdfStreaming ags = new AesGcmHkdfStreaming(ikm, "HmacSha256", keySizeInBytes, segmentSize, firstSegmentOffset); int plaintextSize = 1 << 15; int maxChunkSize = 100; byte[] aad = TestUtil.hexDecode("aabbccddeeff"); byte[] plaintext = StreamingTestUtil.generatePlaintext(plaintextSize); int ciphertextLength = (int) ags.expectedCiphertextSize(plaintextSize); ByteBuffer ciphertext = ByteBuffer.allocate(ciphertextLength); WritableByteChannel ctChannel = new SeekableByteBufferChannel(ciphertext, maxChunkSize); WritableByteChannel encChannel = ags.newEncryptingChannel(ctChannel, aad); ByteBuffer plaintextBuffer = ByteBuffer.wrap(plaintext); int loops = 0; while (plaintextBuffer.remaining() > 0) { encChannel.write(plaintextBuffer); loops += 1; if (loops > 100000) { System.out.println(encChannel.toString()); fail("Too many loops"); } } encChannel.close(); assertFalse(encChannel.isOpen()); StreamingTestUtil.isValidCiphertext(ags, plaintext, aad, ciphertext.array()); }