private static void tryDecryptModifiedCiphertext(
      StreamingAead ags,
      int firstSegmentOffset,
      byte[] modifiedCiphertext,
      byte[] associatedData,
      int chunkSize,
      byte[] plaintext)
      throws Exception {
    SeekableByteChannel ct = new SeekableByteBufferChannel(modifiedCiphertext);
    ct.position(firstSegmentOffset);
    ReadableByteChannel ptChannel = ags.newDecryptingChannel(ct, associatedData);
    int position = 0;
    int read;
    do {
      ByteBuffer chunk = ByteBuffer.allocate(chunkSize);
      try {
        read = ptChannel.read(chunk);
      } catch (IOException ex) {
        // Detected that the ciphertext was modified.
        // TODO(bleichen): Maybe check that the stream cannot longer be accessed.
        return;
      }
      if (read > 0) {
        assertTrue("Read more plaintext than expected", position + read <= plaintext.length);
        // Everything decrypted must be equal to the original plaintext.
        TestUtil.assertByteArrayEquals(
            "Returned modified plaintext position:" + position + " size:" + read,
            Arrays.copyOf(chunk.array(), read),
            Arrays.copyOfRange(plaintext, position, position + read));
        position += read;
      }
    } while (read >= 0);
    fail("Reached end of plaintext.");
  }
Tries to decrypt a modified ciphertext. Each call to read must either return the original
plaintext (e.g. when the modification in the ciphertext has not yet been read) or it must throw
an IOException.
java_src/src/main/java/com/google/crypto/tink/testing/StreamingTestUtil.java