private byte[] crypt(byte[] bytes, byte[] key, byte[] iv, int mode) throws IllegalArgumentException, CryptoException {
        if (key == null || key.length == 0) {
            throw new IllegalArgumentException("key argument cannot be null or empty.");
        }
        javax.crypto.Cipher cipher = initNewCipher(mode, key, iv, false);
        return crypt(cipher, bytes);
    }
Functions as follows:
<ol>
<li>Creates a {@link #newCipherInstance(boolean) new JDK cipher instance}</li>
<li>Converts the specified key bytes into an {@link #getAlgorithmName() algorithm}-compatible JDK
{@link Key key} instance</li>
<li>{@link #init(javax.crypto.Cipher, int, java.security.Key, AlgorithmParameterSpec, SecureRandom) Initializes}
the JDK cipher instance with the JDK key</li>
<li>Calls the {@link #crypt(javax.crypto.Cipher, byte[]) crypt(cipher,bytes)} method to either encrypt or
decrypt the data based on the specified Cipher behavior mode
({@link javax.crypto.Cipher#ENCRYPT_MODE Cipher.ENCRYPT_MODE} or
{@link javax.crypto.Cipher#DECRYPT_MODE Cipher.DECRYPT_MODE})</li>
</ol>

@param bytes the bytes to crypt
@param key   the key to use to perform the encryption or decryption.
@param iv    the initialization vector to use for the crypt operation (optional, may be {@code null}).
@param mode  the JDK Cipher behavior mode (Cipher.ENCRYPT_MODE or Cipher.DECRYPT_MODE).
@return the resulting crypted byte array
@throws IllegalArgumentException if {@code bytes} are null or empty.
@throws CryptoException          if Cipher initialization or the crypt operation fails
src/main/java/org/apache/shiro/crypto/cipher/JcaCipherService.java