@Override
    public synchronized void decryptSegment(
        ByteBuffer ciphertext, int segmentNr, boolean isLastSegment, ByteBuffer plaintext)
        throws GeneralSecurityException {
      int position = ciphertext.position();
      byte[] nonce = nonceForSegment(noncePrefix, segmentNr, isLastSegment);
      int ctLength = ciphertext.remaining();
      if (ctLength < tagSizeInBytes) {
        throw new GeneralSecurityException("Ciphertext too short");
      }
      int ptLength = ctLength - tagSizeInBytes;
      int startOfTag = position + ptLength;
      ByteBuffer ct = ciphertext.duplicate();
      ct.limit(startOfTag);
      ByteBuffer tagBuffer = ciphertext.duplicate();
      tagBuffer.position(startOfTag);

      assert mac != null;
      assert hmacKeySpec != null;
      mac.init(hmacKeySpec);
      mac.update(nonce);
      mac.update(ct);
      byte[] tag = mac.doFinal();
      tag = Arrays.copyOf(tag, tagSizeInBytes);
      byte[] expectedTag = new byte[tagSizeInBytes];
      assert tagBuffer.remaining() == tagSizeInBytes;
      tagBuffer.get(expectedTag);
      assert expectedTag.length == tag.length;
      if (!Bytes.equal(expectedTag, tag)) {
        throw new GeneralSecurityException("Tag mismatch");
      }

      ciphertext.limit(startOfTag);
      cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(nonce));
      cipher.doFinal(ciphertext, plaintext);
    }
An instance of a crypter used to decrypt a ciphertext stream.
java_src/src/main/java/com/google/crypto/tink/subtle/AesCtrHmacStreaming.java