@Override
  public byte[] decrypt(final byte[] ciphertext, final byte[] associatedData)
      throws GeneralSecurityException {
    if (ciphertext.length < macLength + outputPrefix.length) {
      throw new GeneralSecurityException("Decryption failed (ciphertext too short).");
    }
    if (!Util.isPrefix(outputPrefix, ciphertext)) {
      throw new GeneralSecurityException("Decryption failed (OutputPrefix mismatch).");
    }
    byte[] rawCiphertext =
        Arrays.copyOfRange(ciphertext, outputPrefix.length, ciphertext.length - macLength);
    byte[] macValue =
        Arrays.copyOfRange(ciphertext, ciphertext.length - macLength, ciphertext.length);
    byte[] ad = associatedData;
    if (ad == null) {
      ad = new byte[0];
    }
    byte[] adLengthInBits =
        Arrays.copyOf(ByteBuffer.allocate(8).putLong(8L * ad.length).array(), 8);
    mac.verifyMac(macValue, Bytes.concat(ad, rawCiphertext, adLengthInBits));
    return cipher.decrypt(rawCiphertext);
  }
Decrypts {@code ciphertext} with {@code associatedData} as associated data. The decryption
verifies the authenticity and integrity of associated data (ad), but there are no guarantees
with respect to secrecy of that data.

<p>The ciphertext format is output prefix || ciphertext || mac. If present, the correctness of
output prefix is verified. The MAC is verified against (ad || ciphertext || t) where t is ad's
length in bits represented as 64-bit big-endian unsigned integer.

@return resulting plaintext.
java_src/src/main/java/com/google/crypto/tink/subtle/EncryptThenAuthenticate.java