private void test_Cipher(Cipher c) throws Exception {
        String algorithm = c.getAlgorithm().toUpperCase(Locale.US);
        String providerName = c.getProvider().getName();
        if (!isSupported(algorithm, providerName)) {
            return;
        }
        String cipherID = algorithm + ":" + providerName;

        try {
            c.getOutputSize(0);
            fail("getOutputSize() should throw if called before Cipher initialization");
        } catch (IllegalStateException expected) {
        }

        // TODO: test keys from different factories (e.g. OpenSSLRSAPrivateKey vs BCRSAPrivateKey)
        Key encryptKey = getEncryptKey(algorithm);

        AlgorithmParameterSpec encryptSpec = getEncryptAlgorithmParameterSpec(algorithm);
        int encryptMode = getEncryptMode(algorithm);

        // Bouncycastle doesn't return a default PBEParameterSpec
        if (isPBE(algorithm) && !"BC".equals(providerName)) {
            assertNotNull(cipherID + " getParameters()", c.getParameters());
            assertNotNull(c.getParameters().getParameterSpec(PBEParameterSpec.class));
        } else {
            assertNull(cipherID + " getParameters()", c.getParameters());
        }
        try {
            assertNull(cipherID + " getIV()", c.getIV());
        } catch (NullPointerException e) {
            // Bouncycastle apparently has a bug here with AESWRAP, et al.
            if (!("BC".equals(providerName) && isOnlyWrappingAlgorithm(algorithm))) {
                throw e;
            }
        }

        test_Cipher_init_NullParameters(c, encryptMode, encryptKey);

        c.init(encryptMode, encryptKey, encryptSpec);
        assertEquals(cipherID + " getBlockSize() encryptMode",
                getExpectedBlockSize(algorithm, encryptMode, providerName), c.getBlockSize());
        assertTrue(cipherID + " getOutputSize(0) encryptMode",
                getExpectedOutputSize(algorithm, encryptMode, providerName) <= c.getOutputSize(0));
        if ((algorithm.endsWith("/PKCS5PADDING") || algorithm.endsWith("/PKCS7PADDING"))
                && isStreamMode(algorithm)) {
            assertEquals(getExpectedOutputSize(algorithm, encryptMode, providerName),
                    c.doFinal(new byte[1]).length);
        }

        if (isPBE(algorithm)) {
            if (algorithm.endsWith("RC4")) {
                assertNull(cipherID + " getIV()", c.getIV());
            } else {
                assertNotNull(cipherID + " getIV()", c.getIV());
            }
        } else if (encryptSpec instanceof IvParameterSpec) {
            assertEquals(cipherID + " getIV()",
                    Arrays.toString(((IvParameterSpec) encryptSpec).getIV()),
                    Arrays.toString(c.getIV()));
        } else if (encryptSpec instanceof GCMParameterSpec) {
            assertNotNull(c.getIV());
            assertEquals(cipherID + " getIV()",
                    Arrays.toString(((GCMParameterSpec) encryptSpec).getIV()),
                    Arrays.toString(c.getIV()));
        } else {
            try {
                assertNull(cipherID + " getIV()", c.getIV());
            } catch (NullPointerException e) {
                // Bouncycastle apparently has a bug here with AESWRAP, et al.
                if (!("BC".equals(providerName) && isOnlyWrappingAlgorithm(algorithm))) {
                    throw e;
                }
            }
        }

        AlgorithmParameters encParams = c.getParameters();
        assertCorrectAlgorithmParameters(providerName, cipherID, encryptSpec, encParams);

        AlgorithmParameterSpec decryptSpec = getDecryptAlgorithmParameterSpec(encryptSpec, c);
        int decryptMode = getDecryptMode(algorithm);

        Key decryptKey = getDecryptKey(algorithm);

        test_Cipher_init_Decrypt_NullParameters(c, decryptMode, decryptKey, decryptSpec != null);

        c.init(decryptMode, decryptKey, decryptSpec);
        assertEquals(cipherID + " getBlockSize() decryptMode",
                     getExpectedBlockSize(algorithm, decryptMode, providerName), c.getBlockSize());
        assertEquals(cipherID + " getOutputSize(0) decryptMode",
                     getExpectedOutputSize(algorithm, decryptMode, providerName), c.getOutputSize(0));

        if (isPBE(algorithm)) {
            if (algorithm.endsWith("RC4")) {
                assertNull(cipherID + " getIV()", c.getIV());
            } else {
                assertNotNull(cipherID + " getIV()", c.getIV());
            }
        } else if (decryptSpec instanceof IvParameterSpec) {
            assertEquals(cipherID + " getIV()",
                    Arrays.toString(((IvParameterSpec) decryptSpec).getIV()),
                    Arrays.toString(c.getIV()));
        } else if (decryptSpec instanceof GCMParameterSpec) {
            assertNotNull(c.getIV());
            assertEquals(cipherID + " getIV()",
                    Arrays.toString(((GCMParameterSpec) decryptSpec).getIV()),
                    Arrays.toString(c.getIV()));
        } else {
            try {
                assertNull(cipherID + " getIV()", c.getIV());
            } catch (NullPointerException e) {
                // Bouncycastle apparently has a bug here with AESWRAP, et al.
                if (!("BC".equals(providerName) && isOnlyWrappingAlgorithm(algorithm))) {
                    throw e;
                }
            }
        }

        AlgorithmParameters decParams = c.getParameters();
        assertCorrectAlgorithmParameters(providerName, cipherID, decryptSpec, decParams);

        assertNull(cipherID, c.getExemptionMechanism());

        // Test wrapping a key.  Every cipher should be able to wrap. Except those that can't.
        /* Bouncycastle is broken for wrapping because getIV() fails. */
        if (isSupportedForWrapping(algorithm) && !providerName.equals("BC")) {
            // Generate a small SecretKey for AES.
            KeyGenerator kg = KeyGenerator.getInstance("AES");
            kg.init(128);
            SecretKey sk = kg.generateKey();

            // Wrap it.  Use a new encrypt spec so that AEAD algorithms that prohibit IV reuse
            // don't complain.
            encryptSpec = getEncryptAlgorithmParameterSpec(algorithm);
            c.init(Cipher.WRAP_MODE, encryptKey, encryptSpec);
            byte[] cipherText = c.wrap(sk);

            // Unwrap it
            c.init(Cipher.UNWRAP_MODE, decryptKey, getDecryptAlgorithmParameterSpec(encryptSpec, c));
            Key decryptedKey = c.unwrap(cipherText, sk.getAlgorithm(), Cipher.SECRET_KEY);

            assertEquals(cipherID
                    + " sk.getAlgorithm()=" + sk.getAlgorithm()
                    + " decryptedKey.getAlgorithm()=" + decryptedKey.getAlgorithm()
                    + " encryptKey.getEncoded()=" + Arrays.toString(sk.getEncoded())
                    + " decryptedKey.getEncoded()=" + Arrays.toString(decryptedKey.getEncoded()),
                    sk, decryptedKey);
        }

        if (!isOnlyWrappingAlgorithm(algorithm)) {
            // Use a new encrypt spec so that AEAD algorithms that prohibit IV reuse don't complain
            encryptSpec = getEncryptAlgorithmParameterSpec(algorithm);
            c.init(Cipher.ENCRYPT_MODE, encryptKey, encryptSpec);
            if (isAEAD(algorithm)) {
                c.updateAAD(new byte[24]);
            }
            byte[] cipherText = c.doFinal(getActualPlainText(algorithm));
            if (!isRandomizedEncryption(algorithm) && !isAEAD(algorithm)) {
                byte[] cipherText2 = c.doFinal(getActualPlainText(algorithm));
                assertEquals(cipherID, Arrays.toString(cipherText), Arrays.toString(cipherText2));
            }
            decryptSpec = getDecryptAlgorithmParameterSpec(encryptSpec, c);
            c.init(Cipher.DECRYPT_MODE, decryptKey, decryptSpec);
            if (isAEAD(algorithm)) {
                c.updateAAD(new byte[24]);
            }
            byte[] decryptedPlainText = c.doFinal(cipherText);
            assertEquals(cipherID,
                         Arrays.toString(getExpectedPlainText(algorithm, providerName)),
                         Arrays.toString(decryptedPlainText));
            if (isAEAD(algorithm)) {
                c.updateAAD(new byte[24]);
            }
            byte[] decryptedPlainText2 = c.doFinal(cipherText);
            assertEquals(cipherID,
                         Arrays.toString(decryptedPlainText),
                         Arrays.toString(decryptedPlainText2));

            // Use a new encrypt spec so that AEAD algorithms that prohibit IV reuse don't complain
            encryptSpec = getEncryptAlgorithmParameterSpec(algorithm);
            test_Cipher_ShortBufferException(c, algorithm, Cipher.ENCRYPT_MODE, encryptSpec,
                    encryptKey, getActualPlainText(algorithm));
            decryptSpec = getDecryptAlgorithmParameterSpec(encryptSpec, c);
            test_Cipher_ShortBufferException(c, algorithm, Cipher.DECRYPT_MODE, decryptSpec,
                    decryptKey, cipherText);

            test_Cipher_aborted_doFinal(c, algorithm, providerName, encryptKey, decryptKey);
        }
    }
Returns the key meant for deciphering for {@code algorithm}.
common/src/test/java/org/conscrypt/javax/crypto/CipherTest.java