private void decrypt(InputStream in, OutputStream out, byte[] key, boolean ivPrepended) throws CryptoException {

        byte[] iv = null;
        //No Initialization Vector provided as a method argument - check if we need to read the IV from the stream:
        if (ivPrepended) {
            //we are generating IVs, so we need to read the previously-generated IV from the stream before
            //we decrypt the rest of the stream (we need the IV to decrypt):
            int ivSize = getInitializationVectorSize();
            int ivByteSize = ivSize / BITS_PER_BYTE;
            iv = new byte[ivByteSize];
            int read;

            try {
                read = in.read(iv);
            } catch (IOException e) {
                String msg = "Unable to correctly read the Initialization Vector from the input stream.";
                throw new CryptoException(msg, e);
            }

            if (read != ivByteSize) {
                throw new CryptoException("Unable to read initialization vector bytes from the InputStream.  "
                        + "This is required when initialization vectors are autogenerated during an encryption operation.");
            }
        }

        decrypt(in, out, key, iv);
    }
Initializes the JDK Cipher with the specified mode and key.  This is primarily a utility method to catch any
potential {@link java.security.InvalidKeyException InvalidKeyException} that might arise.

@param cipher the JDK Cipher to {@link javax.crypto.Cipher#init(int, java.security.Key) init}.
@param mode   the Cipher mode
@param key    the Cipher's Key
@param spec   the JDK AlgorithmParameterSpec for cipher initialization (optional, may be null).
@param random the SecureRandom to use for cipher initialization (optional, may be null).
@throws CryptoException if the key is invalid
crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/JcaCipherService.java