You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by al...@apache.org on 2017/05/02 17:27:29 UTC

[04/13] nifi git commit: NIFI-3594 Implemented encrypted provenance repository. Added src/test/resources/logback-test.xml files resetting log level from DEBUG (in nifi-data-provenance-utils) to WARN because later tests depend on MockComponentLog recordin

http://git-wip-us.apache.org/repos/asf/nifi/blob/7d242076/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/NiFiLegacyCipherProviderGroovyTest.groovy
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/NiFiLegacyCipherProviderGroovyTest.groovy b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/NiFiLegacyCipherProviderGroovyTest.groovy
deleted file mode 100644
index 176e61b..0000000
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/NiFiLegacyCipherProviderGroovyTest.groovy
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.processors.standard.util.crypto
-
-import org.apache.commons.codec.binary.Hex
-import org.apache.nifi.security.util.EncryptionMethod
-import org.bouncycastle.jce.provider.BouncyCastleProvider
-import org.junit.*
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-
-import javax.crypto.Cipher
-import javax.crypto.SecretKey
-import javax.crypto.SecretKeyFactory
-import javax.crypto.spec.PBEKeySpec
-import javax.crypto.spec.PBEParameterSpec
-import java.security.Security
-
-import static org.junit.Assert.fail
-
-@RunWith(JUnit4.class)
-public class NiFiLegacyCipherProviderGroovyTest {
-    private static final Logger logger = LoggerFactory.getLogger(NiFiLegacyCipherProviderGroovyTest.class);
-
-    private static List<EncryptionMethod> pbeEncryptionMethods = new ArrayList<>();
-    private static List<EncryptionMethod> limitedStrengthPbeEncryptionMethods = new ArrayList<>();
-
-    private static final String PROVIDER_NAME = "BC";
-    private static final int ITERATION_COUNT = 1000;
-
-    private static final byte[] SALT_16_BYTES = Hex.decodeHex("aabbccddeeff00112233445566778899".toCharArray());
-
-    @BeforeClass
-    public static void setUpOnce() throws Exception {
-        Security.addProvider(new BouncyCastleProvider());
-
-        pbeEncryptionMethods = EncryptionMethod.values().findAll { it.algorithm.toUpperCase().startsWith("PBE") }
-        limitedStrengthPbeEncryptionMethods = pbeEncryptionMethods.findAll { !it.isUnlimitedStrength() }
-    }
-
-    @Before
-    public void setUp() throws Exception {
-    }
-
-    @After
-    public void tearDown() throws Exception {
-
-    }
-
-    private static Cipher getLegacyCipher(String password, byte[] salt, String algorithm) {
-        try {
-            final PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
-            final SecretKeyFactory factory = SecretKeyFactory.getInstance(algorithm, PROVIDER_NAME);
-            SecretKey tempKey = factory.generateSecret(pbeKeySpec);
-
-            final PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, ITERATION_COUNT);
-            Cipher cipher = Cipher.getInstance(algorithm, PROVIDER_NAME);
-            cipher.init(Cipher.ENCRYPT_MODE, tempKey, parameterSpec);
-            return cipher;
-        } catch (Exception e) {
-            logger.error("Error generating legacy cipher", e);
-            fail(e.getMessage());
-        }
-
-        return null;
-    }
-
-    @Test
-    public void testGetCipherShouldBeInternallyConsistent() throws Exception {
-        // Arrange
-        NiFiLegacyCipherProvider cipherProvider = new NiFiLegacyCipherProvider();
-
-        final String PASSWORD = "shortPassword";
-        final String plaintext = "This is a plaintext message.";
-
-        // Act
-        for (EncryptionMethod encryptionMethod : limitedStrengthPbeEncryptionMethods) {
-            logger.info("Using algorithm: {}", encryptionMethod.getAlgorithm());
-
-            if (!CipherUtility.passwordLengthIsValidForAlgorithmOnLimitedStrengthCrypto(PASSWORD.length(), encryptionMethod)) {
-                logger.warn("This test is skipped because the password length exceeds the undocumented limit BouncyCastle imposes on a JVM with limited strength crypto policies")
-                continue
-            }
-
-            byte[] salt = cipherProvider.generateSalt(encryptionMethod)
-            logger.info("Generated salt ${Hex.encodeHexString(salt)} (${salt.length})")
-
-            // Initialize a cipher for encryption
-            Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, salt, true);
-
-            byte[] cipherBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: {} {}", Hex.encodeHexString(cipherBytes), cipherBytes.length);
-
-            cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, salt, false);
-            byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testGetCipherWithUnlimitedStrengthShouldBeInternallyConsistent() throws Exception {
-        // Arrange
-        Assume.assumeTrue("Test is being skipped due to this JVM lacking JCE Unlimited Strength Jurisdiction Policy file.",
-                PasswordBasedEncryptor.supportsUnlimitedStrength());
-
-        NiFiLegacyCipherProvider cipherProvider = new NiFiLegacyCipherProvider();
-
-        final String PASSWORD = "shortPassword";
-        final String plaintext = "This is a plaintext message.";
-
-        // Act
-        for (EncryptionMethod encryptionMethod : pbeEncryptionMethods) {
-            logger.info("Using algorithm: {}", encryptionMethod.getAlgorithm());
-
-            byte[] salt = cipherProvider.generateSalt(encryptionMethod)
-            logger.info("Generated salt ${Hex.encodeHexString(salt)} (${salt.length})")
-
-            // Initialize a cipher for encryption
-            Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, salt, true);
-
-            byte[] cipherBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: {} {}", Hex.encodeHexString(cipherBytes), cipherBytes.length);
-
-            cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, salt, false);
-            byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testGetCipherShouldSupportLegacyCode() throws Exception {
-        // Arrange
-        NiFiLegacyCipherProvider cipherProvider = new NiFiLegacyCipherProvider();
-
-        final String PASSWORD = "short";
-        final String plaintext = "This is a plaintext message.";
-
-        // Act
-        for (EncryptionMethod encryptionMethod : limitedStrengthPbeEncryptionMethods) {
-            logger.info("Using algorithm: {}", encryptionMethod.getAlgorithm());
-
-            if (!CipherUtility.passwordLengthIsValidForAlgorithmOnLimitedStrengthCrypto(PASSWORD.length(), encryptionMethod)) {
-                logger.warn("This test is skipped because the password length exceeds the undocumented limit BouncyCastle imposes on a JVM with limited strength crypto policies")
-                continue
-            }
-
-            byte[] salt = cipherProvider.generateSalt(encryptionMethod)
-            logger.info("Generated salt ${Hex.encodeHexString(salt)} (${salt.length})")
-
-            // Initialize a legacy cipher for encryption
-            Cipher legacyCipher = getLegacyCipher(PASSWORD, salt, encryptionMethod.getAlgorithm());
-
-            byte[] cipherBytes = legacyCipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: {} {}", Hex.encodeHexString(cipherBytes), cipherBytes.length);
-
-            Cipher providedCipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, salt, false);
-            byte[] recoveredBytes = providedCipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testGetCipherWithoutSaltShouldSupportLegacyCode() throws Exception {
-        // Arrange
-        NiFiLegacyCipherProvider cipherProvider = new NiFiLegacyCipherProvider();
-
-        final String PASSWORD = "short";
-        final byte[] SALT = new byte[0];
-
-        final String plaintext = "This is a plaintext message.";
-
-        // Act
-        for (EncryptionMethod em : limitedStrengthPbeEncryptionMethods) {
-            logger.info("Using algorithm: {}", em.getAlgorithm());
-
-            if (!CipherUtility.passwordLengthIsValidForAlgorithmOnLimitedStrengthCrypto(PASSWORD.length(), em)) {
-                logger.warn("This test is skipped because the password length exceeds the undocumented limit BouncyCastle imposes on a JVM with limited strength crypto policies")
-                continue
-            }
-
-            // Initialize a legacy cipher for encryption
-            Cipher legacyCipher = getLegacyCipher(PASSWORD, SALT, em.getAlgorithm());
-
-            byte[] cipherBytes = legacyCipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: {} {}", Hex.encodeHexString(cipherBytes), cipherBytes.length);
-
-            Cipher providedCipher = cipherProvider.getCipher(em, PASSWORD, false);
-            byte[] recoveredBytes = providedCipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testGetCipherShouldIgnoreKeyLength() throws Exception {
-        // Arrange
-        NiFiLegacyCipherProvider cipherProvider = new NiFiLegacyCipherProvider();
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = SALT_16_BYTES
-
-        final String plaintext = "This is a plaintext message.";
-
-        final def KEY_LENGTHS = [-1, 40, 64, 128, 192, 256]
-
-        // Initialize a cipher for encryption
-        EncryptionMethod encryptionMethod = EncryptionMethod.MD5_128AES
-        final Cipher cipher128 = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, true);
-        byte[] cipherBytes = cipher128.doFinal(plaintext.getBytes("UTF-8"));
-        logger.info("Cipher text: {} {}", Hex.encodeHexString(cipherBytes), cipherBytes.length);
-
-        // Act
-        KEY_LENGTHS.each { int keyLength ->
-            logger.info("Decrypting with 'requested' key length: ${keyLength}")
-
-            Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, keyLength, false);
-            byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    /**
-     * This test determines for each PBE encryption algorithm if it actually requires the JCE unlimited strength jurisdiction policies to be installed.
-     * Even some algorithms that use 128-bit keys (which should be allowed on all systems) throw exceptions because BouncyCastle derives the key
-     * from the password using a long digest result at the time of key length checking.
-     * @throws IOException
-     */
-    @Ignore("Only needed once to determine max supported password lengths")
-    @Test
-    public void testShouldDetermineDependenceOnUnlimitedStrengthCrypto() throws IOException {
-        def encryptionMethods = EncryptionMethod.values().findAll { it.algorithm.startsWith("PBE") }
-
-        boolean unlimitedCryptoSupported = PasswordBasedEncryptor.supportsUnlimitedStrength()
-        logger.info("This JVM supports unlimited strength crypto: ${unlimitedCryptoSupported}")
-
-        def longestSupportedPasswordByEM = [:]
-
-        encryptionMethods.each { EncryptionMethod encryptionMethod ->
-            logger.info("Attempting ${encryptionMethod.name()} (${encryptionMethod.algorithm}) which claims unlimited strength required: ${encryptionMethod.unlimitedStrength}")
-
-            (1..20).find { int length ->
-                String password = "x" * length
-
-                try {
-                    NiFiLegacyCipherProvider cipherProvider = new NiFiLegacyCipherProvider();
-                    Cipher cipher = cipherProvider.getCipher(encryptionMethod, password, true)
-                    return false
-                } catch (Exception e) {
-                    logger.error("Unable to create the cipher with ${encryptionMethod.algorithm} and password ${password} (${password.length()}) due to ${e.getMessage()}")
-                    if (!longestSupportedPasswordByEM.containsKey(encryptionMethod)) {
-                        longestSupportedPasswordByEM.put(encryptionMethod, password.length() - 1)
-                    }
-                    return true
-                }
-            }
-            logger.info("\n")
-        }
-
-        logger.info("Longest supported password by encryption method:")
-        longestSupportedPasswordByEM.each { EncryptionMethod encryptionMethod, int length ->
-            logger.info("\t${encryptionMethod.algorithm}\t${length}")
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/7d242076/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/OpenSSLPKCS5CipherProviderGroovyTest.groovy
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/OpenSSLPKCS5CipherProviderGroovyTest.groovy b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/OpenSSLPKCS5CipherProviderGroovyTest.groovy
deleted file mode 100644
index 31cbd5a..0000000
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/OpenSSLPKCS5CipherProviderGroovyTest.groovy
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.processors.standard.util.crypto
-
-import org.apache.commons.codec.binary.Hex
-import org.apache.nifi.security.util.EncryptionMethod
-import org.bouncycastle.jce.provider.BouncyCastleProvider
-import org.junit.*
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-
-import javax.crypto.Cipher
-import javax.crypto.SecretKey
-import javax.crypto.SecretKeyFactory
-import javax.crypto.spec.PBEKeySpec
-import javax.crypto.spec.PBEParameterSpec
-import java.security.Security
-
-import static groovy.test.GroovyAssert.shouldFail
-import static org.junit.Assert.fail
-
-@RunWith(JUnit4.class)
-public class OpenSSLPKCS5CipherProviderGroovyTest {
-    private static final Logger logger = LoggerFactory.getLogger(OpenSSLPKCS5CipherProviderGroovyTest.class);
-
-    private static List<EncryptionMethod> pbeEncryptionMethods = new ArrayList<>();
-    private static List<EncryptionMethod> limitedStrengthPbeEncryptionMethods = new ArrayList<>();
-
-    private static final String PROVIDER_NAME = "BC";
-    private static final int ITERATION_COUNT = 0;
-
-    @BeforeClass
-    public static void setUpOnce() throws Exception {
-        Security.addProvider(new BouncyCastleProvider());
-
-        pbeEncryptionMethods = EncryptionMethod.values().findAll { it.algorithm.toUpperCase().startsWith("PBE") }
-        limitedStrengthPbeEncryptionMethods = pbeEncryptionMethods.findAll { !it.isUnlimitedStrength() }
-    }
-
-    @Before
-    public void setUp() throws Exception {
-    }
-
-    @After
-    public void tearDown() throws Exception {
-
-    }
-
-    private static Cipher getLegacyCipher(String password, byte[] salt, String algorithm) {
-        try {
-            final PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
-            final SecretKeyFactory factory = SecretKeyFactory.getInstance(algorithm, PROVIDER_NAME);
-            SecretKey tempKey = factory.generateSecret(pbeKeySpec);
-
-            final PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, ITERATION_COUNT);
-            Cipher cipher = Cipher.getInstance(algorithm, PROVIDER_NAME);
-            cipher.init(Cipher.ENCRYPT_MODE, tempKey, parameterSpec);
-            return cipher;
-        } catch (Exception e) {
-            logger.error("Error generating legacy cipher", e);
-            fail(e.getMessage());
-        }
-
-        return null;
-    }
-
-    @Test
-    public void testGetCipherShouldBeInternallyConsistent() throws Exception {
-        // Arrange
-        OpenSSLPKCS5CipherProvider cipherProvider = new OpenSSLPKCS5CipherProvider();
-
-        final String PASSWORD = "short";
-        final byte[] SALT = Hex.decodeHex("aabbccddeeff0011".toCharArray());
-
-        final String plaintext = "This is a plaintext message.";
-
-        // Act
-        for (EncryptionMethod em : limitedStrengthPbeEncryptionMethods) {
-            logger.info("Using algorithm: {}", em.getAlgorithm());
-
-            if (!CipherUtility.passwordLengthIsValidForAlgorithmOnLimitedStrengthCrypto(PASSWORD.length(), em)) {
-                logger.warn("This test is skipped because the password length exceeds the undocumented limit BouncyCastle imposes on a JVM with limited strength crypto policies")
-                continue
-            }
-
-            // Initialize a cipher for encryption
-            Cipher cipher = cipherProvider.getCipher(em, PASSWORD, SALT, true);
-
-            byte[] cipherBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: {} {}", Hex.encodeHexString(cipherBytes), cipherBytes.length);
-
-            cipher = cipherProvider.getCipher(em, PASSWORD, SALT, false);
-            byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testGetCipherWithUnlimitedStrengthShouldBeInternallyConsistent() throws Exception {
-        // Arrange
-        Assume.assumeTrue("Test is being skipped due to this JVM lacking JCE Unlimited Strength Jurisdiction Policy file.",
-                PasswordBasedEncryptor.supportsUnlimitedStrength());
-
-        OpenSSLPKCS5CipherProvider cipherProvider = new OpenSSLPKCS5CipherProvider();
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = Hex.decodeHex("aabbccddeeff0011".toCharArray());
-
-        final String plaintext = "This is a plaintext message.";
-
-        // Act
-        for (EncryptionMethod em : pbeEncryptionMethods) {
-            logger.info("Using algorithm: {}", em.getAlgorithm());
-
-            // Initialize a cipher for encryption
-            Cipher cipher = cipherProvider.getCipher(em, PASSWORD, SALT, true);
-
-            byte[] cipherBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: {} {}", Hex.encodeHexString(cipherBytes), cipherBytes.length);
-
-            cipher = cipherProvider.getCipher(em, PASSWORD, SALT, false);
-            byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testGetCipherShouldSupportLegacyCode() throws Exception {
-        // Arrange
-        OpenSSLPKCS5CipherProvider cipherProvider = new OpenSSLPKCS5CipherProvider();
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = Hex.decodeHex("0011223344556677".toCharArray());
-
-        final String plaintext = "This is a plaintext message.";
-
-        // Act
-        for (EncryptionMethod em : limitedStrengthPbeEncryptionMethods) {
-            logger.info("Using algorithm: {}", em.getAlgorithm());
-
-            if (!CipherUtility.passwordLengthIsValidForAlgorithmOnLimitedStrengthCrypto(PASSWORD.length(), em)) {
-                logger.warn("This test is skipped because the password length exceeds the undocumented limit BouncyCastle imposes on a JVM with limited strength crypto policies")
-                continue
-            }
-
-            // Initialize a legacy cipher for encryption
-            Cipher legacyCipher = getLegacyCipher(PASSWORD, SALT, em.getAlgorithm());
-
-            byte[] cipherBytes = legacyCipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: {} {}", Hex.encodeHexString(cipherBytes), cipherBytes.length);
-
-            Cipher providedCipher = cipherProvider.getCipher(em, PASSWORD, SALT, false);
-            byte[] recoveredBytes = providedCipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testGetCipherWithoutSaltShouldSupportLegacyCode() throws Exception {
-        // Arrange
-        OpenSSLPKCS5CipherProvider cipherProvider = new OpenSSLPKCS5CipherProvider();
-
-        final String PASSWORD = "short";
-        final byte[] SALT = new byte[0];
-
-        final String plaintext = "This is a plaintext message.";
-
-        // Act
-        for (EncryptionMethod em : limitedStrengthPbeEncryptionMethods) {
-            logger.info("Using algorithm: {}", em.getAlgorithm());
-
-            if (!CipherUtility.passwordLengthIsValidForAlgorithmOnLimitedStrengthCrypto(PASSWORD.length(), em)) {
-                logger.warn("This test is skipped because the password length exceeds the undocumented limit BouncyCastle imposes on a JVM with limited strength crypto policies")
-                continue
-            }
-
-            // Initialize a legacy cipher for encryption
-            Cipher legacyCipher = getLegacyCipher(PASSWORD, SALT, em.getAlgorithm());
-
-            byte[] cipherBytes = legacyCipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: {} {}", Hex.encodeHexString(cipherBytes), cipherBytes.length);
-
-            Cipher providedCipher = cipherProvider.getCipher(em, PASSWORD, false);
-            byte[] recoveredBytes = providedCipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testGetCipherShouldIgnoreKeyLength() throws Exception {
-        // Arrange
-        OpenSSLPKCS5CipherProvider cipherProvider = new OpenSSLPKCS5CipherProvider();
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = Hex.decodeHex("aabbccddeeff0011".toCharArray());
-
-        final String plaintext = "This is a plaintext message.";
-
-        final def KEY_LENGTHS = [-1, 40, 64, 128, 192, 256]
-
-        // Initialize a cipher for encryption
-        EncryptionMethod encryptionMethod = EncryptionMethod.MD5_128AES
-        final Cipher cipher128 = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, true);
-        byte[] cipherBytes = cipher128.doFinal(plaintext.getBytes("UTF-8"));
-        logger.info("Cipher text: {} {}", Hex.encodeHexString(cipherBytes), cipherBytes.length);
-
-        // Act
-        KEY_LENGTHS.each { int keyLength ->
-            logger.info("Decrypting with 'requested' key length: ${keyLength}")
-
-            Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, keyLength, false);
-            byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testGetCipherShouldRequireEncryptionMethod() throws Exception {
-        // Arrange
-        OpenSSLPKCS5CipherProvider cipherProvider = new OpenSSLPKCS5CipherProvider();
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = Hex.decodeHex("0011223344556677".toCharArray());
-
-        // Act
-        logger.info("Using algorithm: null");
-
-        def msg = shouldFail(IllegalArgumentException) {
-            Cipher providedCipher = cipherProvider.getCipher(null, PASSWORD, SALT, false);
-        }
-
-        // Assert
-        assert msg =~ "The encryption method must be specified"
-    }
-
-    @Test
-    public void testGetCipherShouldRequirePassword() throws Exception {
-        // Arrange
-        OpenSSLPKCS5CipherProvider cipherProvider = new OpenSSLPKCS5CipherProvider();
-
-        final byte[] SALT = Hex.decodeHex("0011223344556677".toCharArray());
-        EncryptionMethod encryptionMethod = EncryptionMethod.MD5_128AES
-
-        // Act
-        logger.info("Using algorithm: ${encryptionMethod}");
-
-        def msg = shouldFail(IllegalArgumentException) {
-            Cipher providedCipher = cipherProvider.getCipher(encryptionMethod, "", SALT, false);
-        }
-
-        // Assert
-        assert msg =~ "Encryption with an empty password is not supported"
-    }
-
-    @Test
-    public void testGetCipherShouldValidateSaltLength() throws Exception {
-        // Arrange
-        OpenSSLPKCS5CipherProvider cipherProvider = new OpenSSLPKCS5CipherProvider();
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = Hex.decodeHex("00112233445566".toCharArray());
-        EncryptionMethod encryptionMethod = EncryptionMethod.MD5_128AES
-
-        // Act
-        logger.info("Using algorithm: ${encryptionMethod}");
-
-        def msg = shouldFail(IllegalArgumentException) {
-            Cipher providedCipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, false);
-        }
-
-        // Assert
-        assert msg =~ "Salt must be 8 bytes US-ASCII encoded"
-    }
-
-    @Test
-    public void testGenerateSaltShouldProvideValidSalt() throws Exception {
-        // Arrange
-        PBECipherProvider cipherProvider = new OpenSSLPKCS5CipherProvider()
-
-        // Act
-        byte[] salt = cipherProvider.generateSalt()
-        logger.info("Checking salt ${Hex.encodeHexString(salt)}")
-
-        // Assert
-        assert salt.length == cipherProvider.getDefaultSaltLength()
-        assert salt != [(0x00 as byte) * cipherProvider.defaultSaltLength]
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/7d242076/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/PBKDF2CipherProviderGroovyTest.groovy
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/PBKDF2CipherProviderGroovyTest.groovy b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/PBKDF2CipherProviderGroovyTest.groovy
deleted file mode 100644
index dfcd0da..0000000
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/PBKDF2CipherProviderGroovyTest.groovy
+++ /dev/null
@@ -1,540 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.processors.standard.util.crypto
-
-import org.apache.commons.codec.binary.Hex
-import org.apache.nifi.security.util.EncryptionMethod
-import org.bouncycastle.jce.provider.BouncyCastleProvider
-import org.junit.*
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-
-import javax.crypto.Cipher
-import java.security.Security
-
-import static groovy.test.GroovyAssert.shouldFail
-import static org.junit.Assert.assertTrue
-
-@RunWith(JUnit4.class)
-public class PBKDF2CipherProviderGroovyTest {
-    private static final Logger logger = LoggerFactory.getLogger(PBKDF2CipherProviderGroovyTest.class);
-
-    private static List<EncryptionMethod> strongKDFEncryptionMethods
-
-    public static final String MICROBENCHMARK = "microbenchmark"
-    private static final int DEFAULT_KEY_LENGTH = 128;
-    private static final int TEST_ITERATION_COUNT = 1000
-    private final String DEFAULT_PRF = "SHA-512"
-    private final String SALT_HEX = "0123456789ABCDEFFEDCBA9876543210"
-    private final String IV_HEX = "01" * 16
-    private static ArrayList<Integer> AES_KEY_LENGTHS
-
-    @BeforeClass
-    public static void setUpOnce() throws Exception {
-        Security.addProvider(new BouncyCastleProvider());
-
-        strongKDFEncryptionMethods = EncryptionMethod.values().findAll { it.isCompatibleWithStrongKDFs() }
-
-        logger.metaClass.methodMissing = { String name, args ->
-            logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
-        }
-
-        if (PasswordBasedEncryptor.supportsUnlimitedStrength()) {
-            AES_KEY_LENGTHS = [128, 192, 256]
-        } else {
-            AES_KEY_LENGTHS = [128]
-        }
-    }
-
-    @Before
-    public void setUp() throws Exception {
-    }
-
-    @After
-    public void tearDown() throws Exception {
-
-    }
-
-    @Test
-    public void testGetCipherShouldBeInternallyConsistent() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new PBKDF2CipherProvider(DEFAULT_PRF, TEST_ITERATION_COUNT);
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = Hex.decodeHex(SALT_HEX as char[]);
-
-        final String plaintext = "This is a plaintext message.";
-
-        // Act
-        for (EncryptionMethod em : strongKDFEncryptionMethods) {
-            logger.info("Using algorithm: ${em.getAlgorithm()}");
-
-            // Initialize a cipher for encryption
-            Cipher cipher = cipherProvider.getCipher(em, PASSWORD, SALT, DEFAULT_KEY_LENGTH, true);
-            byte[] iv = cipher.getIV();
-            logger.info("IV: ${Hex.encodeHexString(iv)}")
-
-            byte[] cipherBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)} ${cipherBytes.length}");
-
-            cipher = cipherProvider.getCipher(em, PASSWORD, SALT, iv, DEFAULT_KEY_LENGTH, false);
-            byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-            logger.info("Recovered: ${recovered}")
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testGetCipherShouldRejectInvalidIV() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new PBKDF2CipherProvider(DEFAULT_PRF, TEST_ITERATION_COUNT)
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = Hex.decodeHex(SALT_HEX as char[]);
-        final def INVALID_IVS = (0..15).collect { int length -> new byte[length] }
-
-        EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-
-        // Act
-        INVALID_IVS.each { byte[] badIV ->
-            logger.info("IV: ${Hex.encodeHexString(badIV)} ${badIV.length}")
-
-            // Encrypt should print a warning about the bad IV but overwrite it
-            Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, badIV, DEFAULT_KEY_LENGTH, true)
-
-            // Decrypt should fail
-            def msg = shouldFail(IllegalArgumentException) {
-                cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, badIV, DEFAULT_KEY_LENGTH, false)
-            }
-
-            // Assert
-            assert msg =~ "Cannot decrypt without a valid IV"
-        }
-    }
-
-    @Test
-    public void testGetCipherWithExternalIVShouldBeInternallyConsistent() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new PBKDF2CipherProvider(DEFAULT_PRF, TEST_ITERATION_COUNT);
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = Hex.decodeHex(SALT_HEX as char[]);
-        final byte[] IV = Hex.decodeHex(IV_HEX as char[]);
-
-        final String plaintext = "This is a plaintext message.";
-
-        // Act
-        for (EncryptionMethod em : strongKDFEncryptionMethods) {
-            logger.info("Using algorithm: ${em.getAlgorithm()}");
-
-            // Initialize a cipher for encryption
-            Cipher cipher = cipherProvider.getCipher(em, PASSWORD, SALT, IV, DEFAULT_KEY_LENGTH, true);
-            logger.info("IV: ${Hex.encodeHexString(IV)}")
-
-            byte[] cipherBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)} ${cipherBytes.length}");
-
-            cipher = cipherProvider.getCipher(em, PASSWORD, SALT, IV, DEFAULT_KEY_LENGTH, false);
-            byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-            logger.info("Recovered: ${recovered}")
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testGetCipherWithUnlimitedStrengthShouldBeInternallyConsistent() throws Exception {
-        // Arrange
-        Assume.assumeTrue("Test is being skipped due to this JVM lacking JCE Unlimited Strength Jurisdiction Policy file.",
-                PasswordBasedEncryptor.supportsUnlimitedStrength());
-
-        RandomIVPBECipherProvider cipherProvider = new PBKDF2CipherProvider(DEFAULT_PRF, TEST_ITERATION_COUNT);
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = Hex.decodeHex(SALT_HEX as char[]);
-
-        final int LONG_KEY_LENGTH = 256
-
-        final String plaintext = "This is a plaintext message.";
-
-        // Act
-        for (EncryptionMethod em : strongKDFEncryptionMethods) {
-            logger.info("Using algorithm: ${em.getAlgorithm()}");
-
-            // Initialize a cipher for encryption
-            Cipher cipher = cipherProvider.getCipher(em, PASSWORD, SALT, LONG_KEY_LENGTH, true);
-            byte[] iv = cipher.getIV();
-            logger.info("IV: ${Hex.encodeHexString(iv)}")
-
-            byte[] cipherBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)} ${cipherBytes.length}");
-
-            cipher = cipherProvider.getCipher(em, PASSWORD, SALT, iv, LONG_KEY_LENGTH, false);
-            byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-            logger.info("Recovered: ${recovered}")
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testShouldRejectEmptyPRF() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = Hex.decodeHex(SALT_HEX as char[]);
-        final byte[] IV = Hex.decodeHex(IV_HEX as char[]);
-
-        final String plaintext = "This is a plaintext message.";
-        final EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-        String prf = ""
-
-        // Act
-        logger.info("Using PRF ${prf}")
-        def msg = shouldFail(IllegalArgumentException) {
-            cipherProvider = new PBKDF2CipherProvider(prf, TEST_ITERATION_COUNT);
-        }
-
-        // Assert
-        assert msg =~ "Cannot resolve empty PRF"
-    }
-
-    @Test
-    public void testShouldResolveDefaultPRF() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = Hex.decodeHex(SALT_HEX as char[]);
-        final byte[] IV = Hex.decodeHex(IV_HEX as char[]);
-
-        final String plaintext = "This is a plaintext message.";
-        final EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-
-        final PBKDF2CipherProvider SHA512_PROVIDER = new PBKDF2CipherProvider(DEFAULT_PRF, TEST_ITERATION_COUNT)
-
-        String prf = "sha768"
-        logger.info("Using ${prf}")
-
-        // Act
-        cipherProvider = new PBKDF2CipherProvider(prf, TEST_ITERATION_COUNT);
-        logger.info("Resolved PRF to ${cipherProvider.getPRFName()}")
-        logger.info("Using algorithm: ${encryptionMethod.getAlgorithm()}");
-
-        // Initialize a cipher for encryption
-        Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, IV, DEFAULT_KEY_LENGTH, true);
-        logger.info("IV: ${Hex.encodeHexString(IV)}")
-
-        byte[] cipherBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));
-        logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)} ${cipherBytes.length}");
-
-        cipher = SHA512_PROVIDER.getCipher(encryptionMethod, PASSWORD, SALT, IV, DEFAULT_KEY_LENGTH, false);
-        byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-        String recovered = new String(recoveredBytes, "UTF-8");
-        logger.info("Recovered: ${recovered}")
-
-        // Assert
-        assert plaintext.equals(recovered);
-    }
-
-    @Test
-    public void testShouldResolveVariousPRFs() throws Exception {
-        // Arrange
-        final List<String> PRFS = ["SHA-1", "MD5", "SHA-256", "SHA-384", "SHA-512"]
-        RandomIVPBECipherProvider cipherProvider
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = Hex.decodeHex(SALT_HEX as char[]);
-        final byte[] IV = Hex.decodeHex(IV_HEX as char[]);
-
-        final String plaintext = "This is a plaintext message.";
-        final EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-
-        // Act
-        PRFS.each { String prf ->
-            logger.info("Using ${prf}")
-            cipherProvider = new PBKDF2CipherProvider(prf, TEST_ITERATION_COUNT);
-            logger.info("Resolved PRF to ${cipherProvider.getPRFName()}")
-
-            logger.info("Using algorithm: ${encryptionMethod.getAlgorithm()}");
-
-            // Initialize a cipher for encryption
-            Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, IV, DEFAULT_KEY_LENGTH, true);
-            logger.info("IV: ${Hex.encodeHexString(IV)}")
-
-            byte[] cipherBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)} ${cipherBytes.length}");
-
-            cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, IV, DEFAULT_KEY_LENGTH, false);
-            byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-            logger.info("Recovered: ${recovered}")
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testGetCipherShouldSupportExternalCompatibility() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new PBKDF2CipherProvider("SHA-256", TEST_ITERATION_COUNT);
-
-        final String PLAINTEXT = "This is a plaintext message.";
-        final String PASSWORD = "thisIsABadPassword";
-
-        // These values can be generated by running `$ ./openssl_pbkdf2.rb` in the terminal
-        final byte[] SALT = Hex.decodeHex("ae2481bee3d8b5d5b732bf464ea2ff01" as char[]);
-        final byte[] IV = Hex.decodeHex("26db997dcd18472efd74dabe5ff36853" as char[]);
-
-        final String CIPHER_TEXT = "92edbabae06add6275a1d64815755a9ba52afc96e2c1a316d3abbe1826e96f6c"
-        byte[] cipherBytes = Hex.decodeHex(CIPHER_TEXT as char[])
-
-        EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-        logger.info("Using algorithm: ${encryptionMethod.getAlgorithm()}");
-        logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)} ${cipherBytes.length}");
-
-        // Act
-        Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, IV, DEFAULT_KEY_LENGTH, false);
-        byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-        String recovered = new String(recoveredBytes, "UTF-8");
-        logger.info("Recovered: ${recovered}")
-
-        // Assert
-        assert PLAINTEXT.equals(recovered);
-    }
-
-    @Test
-    public void testGetCipherForDecryptShouldRequireIV() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new PBKDF2CipherProvider(DEFAULT_PRF, TEST_ITERATION_COUNT);
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = Hex.decodeHex(SALT_HEX as char[]);
-        final byte[] IV = Hex.decodeHex(IV_HEX as char[]);
-
-        final String plaintext = "This is a plaintext message.";
-
-        // Act
-        for (EncryptionMethod em : strongKDFEncryptionMethods) {
-            logger.info("Using algorithm: ${em.getAlgorithm()}");
-
-            // Initialize a cipher for encryption
-            Cipher cipher = cipherProvider.getCipher(em, PASSWORD, SALT, IV, DEFAULT_KEY_LENGTH, true);
-            logger.info("IV: ${Hex.encodeHexString(IV)}")
-
-            byte[] cipherBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)} ${cipherBytes.length}");
-
-            def msg = shouldFail(IllegalArgumentException) {
-                cipher = cipherProvider.getCipher(em, PASSWORD, SALT, DEFAULT_KEY_LENGTH, false);
-            }
-
-            // Assert
-            assert msg =~ "Cannot decrypt without a valid IV"
-        }
-    }
-
-    @Test
-    public void testGetCipherShouldRejectInvalidSalt() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new PBKDF2CipherProvider(DEFAULT_PRF, TEST_ITERATION_COUNT)
-
-        final String PASSWORD = "thisIsABadPassword";
-
-        final def INVALID_SALTS = ['pbkdf2', '$3a$11$', 'x', '$2a$10$', '', null]
-
-        EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-        logger.info("Using algorithm: ${encryptionMethod.getAlgorithm()}");
-
-        // Act
-        INVALID_SALTS.each { String salt ->
-            logger.info("Checking salt ${salt}")
-
-            def msg = shouldFail(IllegalArgumentException) {
-                Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, salt?.bytes, DEFAULT_KEY_LENGTH, true);
-            }
-
-            // Assert
-            assert msg =~ "The salt must be at least 16 bytes\\. To generate a salt, use PBKDF2CipherProvider#generateSalt"
-        }
-    }
-
-    @Test
-    public void testGetCipherShouldAcceptValidKeyLengths() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new PBKDF2CipherProvider(DEFAULT_PRF, TEST_ITERATION_COUNT)
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = Hex.decodeHex(SALT_HEX as char[])
-        final byte[] IV = Hex.decodeHex(IV_HEX as char[]);
-
-        final String PLAINTEXT = "This is a plaintext message.";
-
-        // Currently only AES ciphers are compatible with PBKDF2, so redundant to test all algorithms
-        final def VALID_KEY_LENGTHS = AES_KEY_LENGTHS
-        EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-
-        // Act
-        VALID_KEY_LENGTHS.each { int keyLength ->
-            logger.info("Using algorithm: ${encryptionMethod.getAlgorithm()} with key length ${keyLength}")
-
-            // Initialize a cipher for encryption
-            Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, IV, keyLength, true);
-            logger.info("IV: ${Hex.encodeHexString(IV)}")
-
-            byte[] cipherBytes = cipher.doFinal(PLAINTEXT.getBytes("UTF-8"));
-            logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)} ${cipherBytes.length}");
-
-            cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, IV, keyLength, false);
-            byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-            logger.info("Recovered: ${recovered}")
-
-            // Assert
-            assert PLAINTEXT.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testGetCipherShouldNotAcceptInvalidKeyLengths() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new PBKDF2CipherProvider(DEFAULT_PRF, TEST_ITERATION_COUNT);
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = Hex.decodeHex(SALT_HEX as char[])
-        final byte[] IV = Hex.decodeHex(IV_HEX as char[]);
-
-        // Currently only AES ciphers are compatible with PBKDF2, so redundant to test all algorithms
-        final def VALID_KEY_LENGTHS = [-1, 40, 64, 112, 512]
-        EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-
-        // Act
-        VALID_KEY_LENGTHS.each { int keyLength ->
-            logger.info("Using algorithm: ${encryptionMethod.getAlgorithm()} with key length ${keyLength}")
-
-            // Initialize a cipher for encryption
-            def msg = shouldFail(IllegalArgumentException) {
-                Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, IV, keyLength, true);
-            }
-
-            // Assert
-            assert msg =~ "${keyLength} is not a valid key length for AES"
-        }
-    }
-
-    @Ignore("This test can be run on a specific machine to evaluate if the default iteration count is sufficient")
-    @Test
-    public void testDefaultConstructorShouldProvideStrongIterationCount() {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new PBKDF2CipherProvider();
-
-        // Values taken from http://wildlyinaccurate.com/bcrypt-choosing-a-work-factor/ and http://security.stackexchange.com/questions/17207/recommended-of-rounds-for-bcrypt
-
-        // Calculate the iteration count to reach 500 ms
-        int minimumIterationCount = calculateMinimumIterationCount()
-        logger.info("Determined minimum safe iteration count to be ${minimumIterationCount}")
-
-        // Act
-        int iterationCount = cipherProvider.getIterationCount()
-        logger.info("Default iteration count ${iterationCount}")
-
-        // Assert
-        assertTrue("The default iteration count for PBKDF2CipherProvider is too weak. Please update the default value to a stronger level.", iterationCount >= minimumIterationCount)
-    }
-
-    /**
-     * Returns the iteration count required for a derivation to exceed 500 ms on this machine using the default PRF.
-     * Code adapted from http://security.stackexchange.com/questions/17207/recommended-of-rounds-for-bcrypt
-     *
-     * @return the minimum iteration count
-     */
-    private static int calculateMinimumIterationCount() {
-        // High start-up cost, so run multiple times for better benchmarking
-        final int RUNS = 10
-
-        // Benchmark using an iteration count of 10k
-        int iterationCount = 10_000
-
-        final byte[] SALT = [0x00 as byte] * 16
-        final byte[] IV = [0x01 as byte] * 16
-
-        String defaultPrf = new PBKDF2CipherProvider().getPRFName()
-        RandomIVPBECipherProvider cipherProvider = new PBKDF2CipherProvider(defaultPrf, iterationCount)
-
-        // Run once to prime the system
-        double duration = time {
-            Cipher cipher = cipherProvider.getCipher(EncryptionMethod.AES_CBC, MICROBENCHMARK, SALT, IV, DEFAULT_KEY_LENGTH, false)
-        }
-        logger.info("First run of iteration count ${iterationCount} took ${duration} ms (ignored)")
-
-        def durations = []
-
-        RUNS.times { int i ->
-            duration = time {
-                // Use encrypt mode with provided salt and IV to minimize overhead during benchmark call
-                Cipher cipher = cipherProvider.getCipher(EncryptionMethod.AES_CBC, "${MICROBENCHMARK}${i}", SALT, IV, DEFAULT_KEY_LENGTH, false)
-            }
-            logger.info("Iteration count ${iterationCount} took ${duration} ms")
-            durations << duration
-        }
-
-        duration = durations.sum() / durations.size()
-        logger.info("Iteration count ${iterationCount} averaged ${duration} ms")
-
-        // Keep increasing iteration count until the estimated duration is over 500 ms
-        while (duration < 500) {
-            iterationCount *= 2
-            duration *= 2
-        }
-
-        logger.info("Returning iteration count ${iterationCount} for ${duration} ms")
-
-        return iterationCount
-    }
-
-    private static double time(Closure c) {
-        long start = System.nanoTime()
-        c.call()
-        long end = System.nanoTime()
-        return (end - start) / 1_000_000.0
-    }
-
-    @Test
-    public void testGenerateSaltShouldProvideValidSalt() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new PBKDF2CipherProvider(DEFAULT_PRF, TEST_ITERATION_COUNT)
-
-        // Act
-        byte[] salt = cipherProvider.generateSalt()
-        logger.info("Checking salt ${Hex.encodeHexString(salt)}")
-
-        // Assert
-        assert salt.length == 16
-        assert salt != [(0x00 as byte) * 16]
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/7d242076/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/PasswordBasedEncryptorGroovyTest.groovy
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/PasswordBasedEncryptorGroovyTest.groovy b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/PasswordBasedEncryptorGroovyTest.groovy
deleted file mode 100644
index 35c20e5..0000000
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/PasswordBasedEncryptorGroovyTest.groovy
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License") you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.processors.standard.util.crypto
-
-import org.apache.commons.codec.binary.Hex
-import org.apache.nifi.processor.io.StreamCallback
-import org.apache.nifi.security.util.EncryptionMethod
-import org.apache.nifi.security.util.KeyDerivationFunction
-import org.apache.nifi.stream.io.ByteArrayOutputStream
-import org.bouncycastle.jce.provider.BouncyCastleProvider
-import org.junit.After
-import org.junit.Assume
-import org.junit.Before
-import org.junit.BeforeClass
-import org.junit.Test
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-
-import javax.crypto.Cipher
-import java.security.Security
-
-public class PasswordBasedEncryptorGroovyTest {
-    private static final Logger logger = LoggerFactory.getLogger(PasswordBasedEncryptorGroovyTest.class)
-
-    private static final String TEST_RESOURCES_PREFIX = "src/test/resources/TestEncryptContent/"
-    private static final File plainFile = new File("${TEST_RESOURCES_PREFIX}/plain.txt")
-    private static final File encryptedFile = new File("${TEST_RESOURCES_PREFIX}/salted_128_raw.asc")
-
-    private static final String PASSWORD = "thisIsABadPassword"
-    private static final String LEGACY_PASSWORD = "Hello, World!"
-
-    @BeforeClass
-    public static void setUpOnce() throws Exception {
-        Security.addProvider(new BouncyCastleProvider())
-
-        logger.metaClass.methodMissing = { String name, args ->
-            logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
-        }
-    }
-
-    @Before
-    public void setUp() throws Exception {
-    }
-
-    @After
-    public void tearDown() throws Exception {
-    }
-
-    @Test
-    public void testShouldEncryptAndDecrypt() throws Exception {
-        // Arrange
-        final String PLAINTEXT = "This is a plaintext message."
-        logger.info("Plaintext: {}", PLAINTEXT)
-        InputStream plainStream = new ByteArrayInputStream(PLAINTEXT.getBytes("UTF-8"))
-
-        String shortPassword = "short"
-
-        def encryptionMethodsAndKdfs = [
-                (KeyDerivationFunction.OPENSSL_EVP_BYTES_TO_KEY): EncryptionMethod.MD5_128AES,
-                (KeyDerivationFunction.NIFI_LEGACY)             : EncryptionMethod.MD5_128AES,
-                (KeyDerivationFunction.BCRYPT)                  : EncryptionMethod.AES_CBC,
-                (KeyDerivationFunction.SCRYPT)                  : EncryptionMethod.AES_CBC,
-                (KeyDerivationFunction.PBKDF2)                  : EncryptionMethod.AES_CBC
-        ]
-
-        // Act
-        encryptionMethodsAndKdfs.each { KeyDerivationFunction kdf, EncryptionMethod encryptionMethod ->
-            OutputStream cipherStream = new ByteArrayOutputStream()
-            OutputStream recoveredStream = new ByteArrayOutputStream()
-
-            logger.info("Using ${kdf.name} and ${encryptionMethod.name()}")
-            PasswordBasedEncryptor encryptor = new PasswordBasedEncryptor(encryptionMethod, shortPassword.toCharArray(), kdf)
-
-            StreamCallback encryptionCallback = encryptor.getEncryptionCallback()
-            StreamCallback decryptionCallback = encryptor.getDecryptionCallback()
-
-            encryptionCallback.process(plainStream, cipherStream)
-
-            final byte[] cipherBytes = ((ByteArrayOutputStream) cipherStream).toByteArray()
-            logger.info("Encrypted: {}", Hex.encodeHexString(cipherBytes))
-            InputStream cipherInputStream = new ByteArrayInputStream(cipherBytes)
-            decryptionCallback.process(cipherInputStream, recoveredStream)
-
-            // Assert
-            byte[] recoveredBytes = ((ByteArrayOutputStream) recoveredStream).toByteArray()
-            String recovered = new String(recoveredBytes, "UTF-8")
-            logger.info("Recovered: {}\n\n", recovered)
-            assert PLAINTEXT.equals(recovered)
-
-            // This is necessary to run multiple iterations
-            plainStream.reset()
-        }
-    }
-
-    @Test
-    public void testShouldDecryptLegacyOpenSSLSaltedCipherText() throws Exception {
-        // Arrange
-        Assume.assumeTrue("Skipping test because unlimited strength crypto policy not installed", PasswordBasedEncryptor.supportsUnlimitedStrength())
-
-        final String PLAINTEXT = new File("${TEST_RESOURCES_PREFIX}/plain.txt").text
-        logger.info("Plaintext: {}", PLAINTEXT)
-        byte[] cipherBytes = new File("${TEST_RESOURCES_PREFIX}/salted_128_raw.enc").bytes
-        InputStream cipherStream = new ByteArrayInputStream(cipherBytes)
-        OutputStream recoveredStream = new ByteArrayOutputStream()
-
-        final EncryptionMethod encryptionMethod = EncryptionMethod.MD5_128AES
-        final KeyDerivationFunction kdf = KeyDerivationFunction.OPENSSL_EVP_BYTES_TO_KEY
-
-        PasswordBasedEncryptor encryptor = new PasswordBasedEncryptor(encryptionMethod, PASSWORD.toCharArray(), kdf)
-
-        StreamCallback decryptionCallback = encryptor.getDecryptionCallback()
-        logger.info("Cipher bytes: ${Hex.encodeHexString(cipherBytes)}")
-
-        // Act
-        decryptionCallback.process(cipherStream, recoveredStream)
-
-        // Assert
-        byte[] recoveredBytes = ((ByteArrayOutputStream) recoveredStream).toByteArray()
-        String recovered = new String(recoveredBytes, "UTF-8")
-        logger.info("Recovered: {}", recovered)
-        assert PLAINTEXT.equals(recovered)
-    }
-
-    @Test
-    public void testShouldDecryptLegacyOpenSSLUnsaltedCipherText() throws Exception {
-        // Arrange
-        Assume.assumeTrue("Skipping test because unlimited strength crypto policy not installed", PasswordBasedEncryptor.supportsUnlimitedStrength())
-
-        final String PLAINTEXT = new File("${TEST_RESOURCES_PREFIX}/plain.txt").text
-        logger.info("Plaintext: {}", PLAINTEXT)
-        byte[] cipherBytes = new File("${TEST_RESOURCES_PREFIX}/unsalted_128_raw.enc").bytes
-        InputStream cipherStream = new ByteArrayInputStream(cipherBytes)
-        OutputStream recoveredStream = new ByteArrayOutputStream()
-
-        final EncryptionMethod encryptionMethod = EncryptionMethod.MD5_128AES
-        final KeyDerivationFunction kdf = KeyDerivationFunction.OPENSSL_EVP_BYTES_TO_KEY
-
-        PasswordBasedEncryptor encryptor = new PasswordBasedEncryptor(encryptionMethod, PASSWORD.toCharArray(), kdf)
-
-        StreamCallback decryptionCallback = encryptor.getDecryptionCallback()
-        logger.info("Cipher bytes: ${Hex.encodeHexString(cipherBytes)}")
-
-        // Act
-        decryptionCallback.process(cipherStream, recoveredStream)
-
-        // Assert
-        byte[] recoveredBytes = ((ByteArrayOutputStream) recoveredStream).toByteArray()
-        String recovered = new String(recoveredBytes, "UTF-8")
-        logger.info("Recovered: {}", recovered)
-        assert PLAINTEXT.equals(recovered)
-    }
-
-    @Test
-    public void testShouldDecryptNiFiLegacySaltedCipherTextWithVariableSaltLength() throws Exception {
-        // Arrange
-        final String PLAINTEXT = new File("${TEST_RESOURCES_PREFIX}/plain.txt").text
-        logger.info("Plaintext: {}", PLAINTEXT)
-
-        final String PASSWORD = "short"
-        logger.info("Password: ${PASSWORD}")
-
-        /* The old NiFi legacy KDF code checked the algorithm block size and used it for the salt length.
-         If the block size was not available, it defaulted to 8 bytes based on the default salt size. */
-
-        def pbeEncryptionMethods = EncryptionMethod.values().findAll { it.algorithm.startsWith("PBE") }
-        def encryptionMethodsByBlockSize = pbeEncryptionMethods.groupBy {
-            Cipher cipher = Cipher.getInstance(it.algorithm, it.provider)
-            cipher.getBlockSize()
-        }
-
-        logger.info("Grouped algorithms by block size: ${encryptionMethodsByBlockSize.collectEntries { k, v -> [k, v*.algorithm] }}")
-
-        encryptionMethodsByBlockSize.each { int blockSize, List<EncryptionMethod> encryptionMethods ->
-            encryptionMethods.each { EncryptionMethod encryptionMethod ->
-                final int EXPECTED_SALT_SIZE = (blockSize > 0) ? blockSize : 8
-                logger.info("Testing ${encryptionMethod.algorithm} with expected salt size ${EXPECTED_SALT_SIZE}")
-
-                def legacySaltHex = "aa" * EXPECTED_SALT_SIZE
-                byte[] legacySalt = Hex.decodeHex(legacySaltHex as char[])
-                logger.info("Generated legacy salt ${legacySaltHex} (${legacySalt.length})")
-
-                // Act
-
-                // Encrypt using the raw legacy code
-                NiFiLegacyCipherProvider legacyCipherProvider = new NiFiLegacyCipherProvider()
-                Cipher legacyCipher = legacyCipherProvider.getCipher(encryptionMethod, PASSWORD, legacySalt, true)
-                byte[] cipherBytes = legacyCipher.doFinal(PLAINTEXT.bytes)
-                logger.info("Cipher bytes: ${Hex.encodeHexString(cipherBytes)}")
-
-                byte[] completeCipherStreamBytes = CipherUtility.concatBytes(legacySalt, cipherBytes)
-                logger.info("Complete cipher stream: ${Hex.encodeHexString(completeCipherStreamBytes)}")
-
-                InputStream cipherStream = new ByteArrayInputStream(completeCipherStreamBytes)
-                OutputStream resultStream = new ByteArrayOutputStream()
-
-                // Now parse and decrypt using PBE encryptor
-                PasswordBasedEncryptor decryptor = new PasswordBasedEncryptor(encryptionMethod, PASSWORD as char[], KeyDerivationFunction.NIFI_LEGACY)
-
-                StreamCallback decryptCallback = decryptor.decryptionCallback
-                decryptCallback.process(cipherStream, resultStream)
-
-                logger.info("Decrypted: ${Hex.encodeHexString(resultStream.toByteArray())}")
-                String recovered = new String(resultStream.toByteArray())
-                logger.info("Recovered: ${recovered}")
-
-                // Assert
-                assert recovered == PLAINTEXT
-            }
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/7d242076/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/ScryptCipherProviderGroovyTest.groovy
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/ScryptCipherProviderGroovyTest.groovy b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/ScryptCipherProviderGroovyTest.groovy
deleted file mode 100644
index 8fd0455..0000000
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/ScryptCipherProviderGroovyTest.groovy
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.processors.standard.util.crypto
-
-import org.apache.commons.codec.binary.Base64
-import org.apache.commons.codec.binary.Hex
-import org.apache.nifi.processors.standard.util.crypto.scrypt.Scrypt
-import org.apache.nifi.security.util.EncryptionMethod
-import org.bouncycastle.jce.provider.BouncyCastleProvider
-import org.junit.After
-import org.junit.Assume
-import org.junit.Before
-import org.junit.BeforeClass
-import org.junit.Ignore
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-
-import javax.crypto.Cipher
-import javax.crypto.SecretKey
-import javax.crypto.spec.IvParameterSpec
-import javax.crypto.spec.SecretKeySpec
-import java.security.SecureRandom
-import java.security.Security
-
-import static groovy.test.GroovyAssert.shouldFail
-import static org.junit.Assert.assertTrue
-
-@RunWith(JUnit4.class)
-public class ScryptCipherProviderGroovyTest {
-    private static final Logger logger = LoggerFactory.getLogger(ScryptCipherProviderGroovyTest.class);
-
-    private static List<EncryptionMethod> strongKDFEncryptionMethods
-
-    private static final int DEFAULT_KEY_LENGTH = 128;
-    public static final String MICROBENCHMARK = "microbenchmark"
-    private static ArrayList<Integer> AES_KEY_LENGTHS
-
-    RandomIVPBECipherProvider cipherProvider
-
-    @BeforeClass
-    public static void setUpOnce() throws Exception {
-        Security.addProvider(new BouncyCastleProvider());
-
-        strongKDFEncryptionMethods = EncryptionMethod.values().findAll { it.isCompatibleWithStrongKDFs() }
-
-        logger.metaClass.methodMissing = { String name, args ->
-            logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
-        }
-
-        if (PasswordBasedEncryptor.supportsUnlimitedStrength()) {
-            AES_KEY_LENGTHS = [128, 192, 256]
-        } else {
-            AES_KEY_LENGTHS = [128]
-        }
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        // Very fast parameters to test for correctness rather than production values
-        cipherProvider = new ScryptCipherProvider(4, 1, 1)
-    }
-
-    @After
-    public void tearDown() throws Exception {
-
-    }
-
-    @Test
-    public void testGetCipherShouldBeInternallyConsistent() throws Exception {
-        // Arrange
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = cipherProvider.generateSalt()
-
-        final String plaintext = "This is a plaintext message.";
-
-        // Act
-        for (EncryptionMethod em : strongKDFEncryptionMethods) {
-            logger.info("Using algorithm: ${em.getAlgorithm()}");
-
-            // Initialize a cipher for encryption
-            Cipher cipher = cipherProvider.getCipher(em, PASSWORD, SALT, DEFAULT_KEY_LENGTH, true);
-            byte[] iv = cipher.getIV();
-            logger.info("IV: ${Hex.encodeHexString(iv)}")
-
-            byte[] cipherBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)} ${cipherBytes.length}");
-
-            cipher = cipherProvider.getCipher(em, PASSWORD, SALT, iv, DEFAULT_KEY_LENGTH, false);
-            byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-            logger.info("Recovered: ${recovered}")
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testGetCipherWithExternalIVShouldBeInternallyConsistent() throws Exception {
-        // Arrange
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = cipherProvider.generateSalt()
-        final byte[] IV = Hex.decodeHex("01" * 16 as char[]);
-
-        final String plaintext = "This is a plaintext message.";
-
-        // Act
-        for (EncryptionMethod em : strongKDFEncryptionMethods) {
-            logger.info("Using algorithm: ${em.getAlgorithm()}");
-
-            // Initialize a cipher for encryption
-            Cipher cipher = cipherProvider.getCipher(em, PASSWORD, SALT, IV, DEFAULT_KEY_LENGTH, true);
-            logger.info("IV: ${Hex.encodeHexString(IV)}")
-
-            byte[] cipherBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)} ${cipherBytes.length}");
-
-            cipher = cipherProvider.getCipher(em, PASSWORD, SALT, IV, DEFAULT_KEY_LENGTH, false);
-            byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-            logger.info("Recovered: ${recovered}")
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testGetCipherWithUnlimitedStrengthShouldBeInternallyConsistent() throws Exception {
-        // Arrange
-        Assume.assumeTrue("Test is being skipped due to this JVM lacking JCE Unlimited Strength Jurisdiction Policy file.",
-                PasswordBasedEncryptor.supportsUnlimitedStrength());
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = cipherProvider.generateSalt()
-
-        final int LONG_KEY_LENGTH = 256
-
-        final String plaintext = "This is a plaintext message.";
-
-        // Act
-        for (EncryptionMethod em : strongKDFEncryptionMethods) {
-            logger.info("Using algorithm: ${em.getAlgorithm()}");
-
-            // Initialize a cipher for encryption
-            Cipher cipher = cipherProvider.getCipher(em, PASSWORD, SALT, LONG_KEY_LENGTH, true);
-            byte[] iv = cipher.getIV();
-            logger.info("IV: ${Hex.encodeHexString(iv)}")
-
-            byte[] cipherBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)} ${cipherBytes.length}");
-
-            cipher = cipherProvider.getCipher(em, PASSWORD, SALT, iv, LONG_KEY_LENGTH, false);
-            byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-            logger.info("Recovered: ${recovered}")
-
-            // Assert
-            assert plaintext.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testScryptShouldSupportExternalCompatibility() throws Exception {
-        // Arrange
-
-        // Default values are N=2^14, r=8, p=1, but the provided salt will contain the parameters used
-        cipherProvider = new ScryptCipherProvider()
-
-        final String PLAINTEXT = "This is a plaintext message.";
-        final String PASSWORD = "thisIsABadPassword"
-        final int DK_LEN = 128
-
-        // These values can be generated by running `$ ./openssl_scrypt.rb` in the terminal
-        final byte[] SALT = Hex.decodeHex("f5b8056ea6e66edb8d013ac432aba24a" as char[])
-        logger.info("Expected salt: ${Hex.encodeHexString(SALT)}")
-        final byte[] IV = Hex.decodeHex("76a00f00878b8c3db314ae67804c00a1" as char[])
-
-        final String CIPHER_TEXT = "604188bf8e9137bc1b24a0ab01973024bc5935e9ae5fedf617bdca028c63c261"
-        logger.sanity("Ruby cipher text: ${CIPHER_TEXT}")
-        byte[] cipherBytes = Hex.decodeHex(CIPHER_TEXT as char[])
-
-        EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-
-        // Sanity check
-        String rubyKeyHex = "a8efbc0a709d3f89b6bb35b05fc8edf5"
-        logger.sanity("Using key: ${rubyKeyHex}")
-        logger.sanity("Using IV:  ${Hex.encodeHexString(IV)}")
-        Cipher rubyCipher = Cipher.getInstance(encryptionMethod.algorithm, "BC")
-        def rubyKey = new SecretKeySpec(Hex.decodeHex(rubyKeyHex as char[]), "AES")
-        def ivSpec = new IvParameterSpec(IV)
-        rubyCipher.init(Cipher.ENCRYPT_MODE, rubyKey, ivSpec)
-        byte[] rubyCipherBytes = rubyCipher.doFinal(PLAINTEXT.bytes)
-        logger.sanity("Created cipher text: ${Hex.encodeHexString(rubyCipherBytes)}")
-        rubyCipher.init(Cipher.DECRYPT_MODE, rubyKey, ivSpec)
-        assert rubyCipher.doFinal(rubyCipherBytes) == PLAINTEXT.bytes
-        logger.sanity("Decrypted generated cipher text successfully")
-        assert rubyCipher.doFinal(cipherBytes) == PLAINTEXT.bytes
-        logger.sanity("Decrypted external cipher text successfully")
-
-        // n$r$p$hex_salt_SL$hex_hash_HL
-        final String FULL_HASH = "400\$8\$24\$f5b8056ea6e66edb8d013ac432aba24a\$a8efbc0a709d3f89b6bb35b05fc8edf5"
-        logger.info("Full Hash: ${FULL_HASH}")
-
-        def (String nStr, String rStr, String pStr, String saltHex, String hashHex) = FULL_HASH.split("\\\$")
-        def (n, r, p) = [nStr, rStr, pStr].collect { Integer.valueOf(it, 16) }
-
-        logger.info("N: Hex ${nStr} -> ${n}")
-        logger.info("r: Hex ${rStr} -> ${r}")
-        logger.info("p: Hex ${pStr} -> ${p}")
-        logger.info("Salt: ${saltHex}")
-        logger.info("Hash: ${hashHex}")
-
-        // Form Java-style salt with cost params from Ruby-style
-        String javaSalt = Scrypt.formatSalt(Hex.decodeHex(saltHex as char[]), n, r, p)
-        logger.info("Formed Java-style salt: ${javaSalt}")
-
-        // Convert hash from hex to Base64
-        String base64Hash = CipherUtility.encodeBase64NoPadding(Hex.decodeHex(hashHex as char[]))
-        logger.info("Converted hash from hex ${hashHex} to Base64 ${base64Hash}")
-        assert Hex.encodeHexString(Base64.decodeBase64(base64Hash)) == hashHex
-
-        logger.info("Using algorithm: ${encryptionMethod.getAlgorithm()}");
-        logger.info("External cipher text: ${CIPHER_TEXT} ${cipherBytes.length}");
-
-        // Act
-        Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, javaSalt.bytes, IV, DK_LEN, false);
-        byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-        String recovered = new String(recoveredBytes, "UTF-8");
-        logger.info("Recovered: ${recovered}")
-
-        // Assert
-        assert PLAINTEXT.equals(recovered);
-    }
-
-    @Test
-    public void testGetCipherShouldHandleSaltWithoutParameters() throws Exception {
-        // Arrange
-
-        // To help Groovy resolve implementation private methods not known at interface level
-        cipherProvider = cipherProvider as ScryptCipherProvider
-
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = new byte[cipherProvider.defaultSaltLength]
-        new SecureRandom().nextBytes(SALT)
-
-        final String EXPECTED_FORMATTED_SALT = cipherProvider.formatSaltForScrypt(SALT)
-        logger.info("Expected salt: ${EXPECTED_FORMATTED_SALT}")
-
-        final String plaintext = "This is a plaintext message.";
-        EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-        logger.info("Using algorithm: ${encryptionMethod.getAlgorithm()}");
-
-        // Act
-
-        // Initialize a cipher for encryption
-        Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, DEFAULT_KEY_LENGTH, true);
-        byte[] iv = cipher.getIV();
-        logger.info("IV: ${Hex.encodeHexString(iv)}")
-
-        byte[] cipherBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));
-        logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)} ${cipherBytes.length}");
-
-        // Manually initialize a cipher for decrypt with the expected salt
-        byte[] parsedSalt = new byte[cipherProvider.defaultSaltLength]
-        def params = []
-        cipherProvider.parseSalt(EXPECTED_FORMATTED_SALT, parsedSalt, params)
-        def (int n, int r, int p) = params
-        byte[] keyBytes = Scrypt.deriveScryptKey(PASSWORD.bytes, parsedSalt, n, r, p, DEFAULT_KEY_LENGTH)
-        SecretKey key = new SecretKeySpec(keyBytes, "AES")
-        Cipher manualCipher = Cipher.getInstance(encryptionMethod.algorithm, encryptionMethod.provider)
-        manualCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv))
-        byte[] recoveredBytes = manualCipher.doFinal(cipherBytes);
-        String recovered = new String(recoveredBytes, "UTF-8");
-        logger.info("Recovered: ${recovered}")
-
-        // Assert
-        assert plaintext.equals(recovered);
-    }
-
-    @Test
-    public void testGetCipherShouldNotAcceptInvalidSalts() throws Exception {
-        // Arrange
-        final String PASSWORD = "thisIsABadPassword";
-
-        final def INVALID_SALTS = ['bad_sal', '$3a$11$', 'x', '$2a$10$', '$400$1$1$abcdefghijklmnopqrstuvwxyz']
-        final LENGTH_MESSAGE = "The raw salt must be between 8 and 32 bytes"
-
-        EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-        logger.info("Using algorithm: ${encryptionMethod.getAlgorithm()}");
-
-        // Act
-        INVALID_SALTS.each { String salt ->
-            logger.info("Checking salt ${salt}")
-
-            def msg = shouldFail(IllegalArgumentException) {
-                Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, salt.bytes, DEFAULT_KEY_LENGTH, true);
-            }
-            logger.expected(msg)
-
-            // Assert
-            assert msg =~ LENGTH_MESSAGE
-        }
-    }
-
-    @Test
-    public void testGetCipherShouldHandleUnformattedSalts() throws Exception {
-        // Arrange
-        final String PASSWORD = "thisIsABadPassword";
-
-        final def RECOVERABLE_SALTS = ['$ab$00$acbdefghijklmnopqrstuv', '$4$1$1$0123456789abcdef', '$400$1$1$abcdefghijklmnopqrstuv']
-
-        EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-        logger.info("Using algorithm: ${encryptionMethod.getAlgorithm()}");
-
-        // Act
-        RECOVERABLE_SALTS.each { String salt ->
-            logger.info("Checking salt ${salt}")
-
-            Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, salt.bytes, DEFAULT_KEY_LENGTH, true);
-
-            // Assert
-            assert cipher
-        }
-    }
-
-    @Test
-    public void testGetCipherShouldRejectEmptySalt() throws Exception {
-        // Arrange
-        final String PASSWORD = "thisIsABadPassword";
-
-        EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-        logger.info("Using algorithm: ${encryptionMethod.getAlgorithm()}");
-
-        // Act
-        def msg = shouldFail(IllegalArgumentException) {
-            Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, new byte[0], DEFAULT_KEY_LENGTH, true);
-        }
-        logger.expected(msg)
-
-        // Assert
-        assert msg =~ "The salt cannot be empty\\. To generate a salt, use ScryptCipherProvider#generateSalt"
-    }
-
-    @Test
-    public void testGetCipherForDecryptShouldRequireIV() throws Exception {
-        // Arrange
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = cipherProvider.generateSalt()
-        final byte[] IV = Hex.decodeHex("00" * 16 as char[]);
-
-        final String plaintext = "This is a plaintext message.";
-
-        // Act
-        for (EncryptionMethod em : strongKDFEncryptionMethods) {
-            logger.info("Using algorithm: ${em.getAlgorithm()}");
-
-            // Initialize a cipher for encryption
-            Cipher cipher = cipherProvider.getCipher(em, PASSWORD, SALT, IV, DEFAULT_KEY_LENGTH, true);
-            logger.info("IV: ${Hex.encodeHexString(IV)}")
-
-            byte[] cipherBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));
-            logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)} ${cipherBytes.length}");
-
-            def msg = shouldFail(IllegalArgumentException) {
-                cipher = cipherProvider.getCipher(em, PASSWORD, SALT, DEFAULT_KEY_LENGTH, false);
-            }
-            logger.expected(msg)
-
-            // Assert
-            assert msg =~ "Cannot decrypt without a valid IV"
-        }
-    }
-
-    @Test
-    public void testGetCipherShouldAcceptValidKeyLengths() throws Exception {
-        // Arrange
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = cipherProvider.generateSalt()
-        final byte[] IV = Hex.decodeHex("01" * 16 as char[]);
-
-        final String PLAINTEXT = "This is a plaintext message.";
-
-        // Currently only AES ciphers are compatible with Bcrypt, so redundant to test all algorithms
-        final def VALID_KEY_LENGTHS = AES_KEY_LENGTHS
-        EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-
-        // Act
-        VALID_KEY_LENGTHS.each { int keyLength ->
-            logger.info("Using algorithm: ${encryptionMethod.getAlgorithm()} with key length ${keyLength}")
-
-            // Initialize a cipher for encryption
-            Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, IV, keyLength, true);
-            logger.info("IV: ${Hex.encodeHexString(IV)}")
-
-            byte[] cipherBytes = cipher.doFinal(PLAINTEXT.getBytes("UTF-8"));
-            logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)} ${cipherBytes.length}");
-
-            cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, IV, keyLength, false);
-            byte[] recoveredBytes = cipher.doFinal(cipherBytes);
-            String recovered = new String(recoveredBytes, "UTF-8");
-            logger.info("Recovered: ${recovered}")
-
-            // Assert
-            assert PLAINTEXT.equals(recovered);
-        }
-    }
-
-    @Test
-    public void testGetCipherShouldNotAcceptInvalidKeyLengths() throws Exception {
-        // Arrange
-        final String PASSWORD = "shortPassword";
-        final byte[] SALT = cipherProvider.generateSalt()
-        final byte[] IV = Hex.decodeHex("00" * 16 as char[]);
-
-        final String PLAINTEXT = "This is a plaintext message.";
-
-        // Even though Scrypt can derive keys of arbitrary length, it will fail to validate if the underlying cipher does not support it
-        final def INVALID_KEY_LENGTHS = [-1, 40, 64, 112, 512]
-        // Currently only AES ciphers are compatible with Scrypt, so redundant to test all algorithms
-        EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-
-        // Act
-        INVALID_KEY_LENGTHS.each { int keyLength ->
-            logger.info("Using algorithm: ${encryptionMethod.getAlgorithm()} with key length ${keyLength}")
-
-            // Initialize a cipher for encryption
-            def msg = shouldFail(IllegalArgumentException) {
-                Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, SALT, IV, keyLength, true);
-            }
-            logger.expected(msg)
-
-            // Assert
-            assert msg =~ "${keyLength} is not a valid key length for AES"
-        }
-    }
-
-    @Test
-    public void testScryptShouldNotAcceptInvalidPassword() {
-        // Arrange
-        String badPassword = ""
-        byte[] salt = [0x01 as byte] * 16
-
-        EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-
-        // Act
-        def msg = shouldFail(IllegalArgumentException) {
-            cipherProvider.getCipher(encryptionMethod, badPassword, salt, DEFAULT_KEY_LENGTH, true)
-        }
-
-        // Assert
-        assert msg =~ "Encryption with an empty password is not supported"
-    }
-
-    @Test
-    public void testGenerateSaltShouldUseProvidedParameters() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new ScryptCipherProvider(8, 2, 2);
-        int n = cipherProvider.getN()
-        int r = cipherProvider.getR()
-        int p = cipherProvider.getP()
-
-        // Act
-        final String salt = new String(cipherProvider.generateSalt())
-        logger.info("Salt: ${salt}")
-
-        // Assert
-        assert salt =~ "^(?i)\\\$s0\\\$[a-f0-9]{5,16}\\\$"
-        String params = Scrypt.encodeParams(n, r, p)
-        assert salt.contains("\$${params}\$")
-    }
-
-    @Test
-    public void testShouldParseSalt() throws Exception {
-        // Arrange
-        cipherProvider = cipherProvider as ScryptCipherProvider
-
-        final byte[] EXPECTED_RAW_SALT = Hex.decodeHex("f5b8056ea6e66edb8d013ac432aba24a" as char[])
-        final int EXPECTED_N = 1024
-        final int EXPECTED_R = 8
-        final int EXPECTED_P = 36
-
-        final String FORMATTED_SALT = "\$s0\$a0824\$9bgFbqbmbtuNATrEMquiSg"
-        logger.info("Using salt: ${FORMATTED_SALT}");
-
-        byte[] rawSalt = new byte[16]
-        def params = []
-
-        // Act
-        cipherProvider.parseSalt(FORMATTED_SALT, rawSalt, params)
-
-        // Assert
-        assert rawSalt == EXPECTED_RAW_SALT
-        assert params[0] == EXPECTED_N
-        assert params[1] == EXPECTED_R
-        assert params[2] == EXPECTED_P
-    }
-
-    @Ignore("This test can be run on a specific machine to evaluate if the default parameters are sufficient")
-    @Test
-    public void testDefaultConstructorShouldProvideStrongParameters() {
-        // Arrange
-        ScryptCipherProvider testCipherProvider = new ScryptCipherProvider()
-
-        /** See this Stack Overflow answer for a good visualization of the interplay between N, r, p <a href="http://stackoverflow.com/a/30308723" rel="noopener">http://stackoverflow.com/a/30308723</a> */
-
-        // Act
-        int n = testCipherProvider.getN()
-        int r = testCipherProvider.getR()
-        int p = testCipherProvider.getP()
-        logger.info("Default parameters N=${n}, r=${r}, p=${p}")
-
-        // Calculate the parameters to reach 500 ms
-        def (int minimumN, int minimumR, int minimumP) = calculateMinimumParameters(r, p)
-        logger.info("Determined minimum safe parameters to be N=${minimumN}, r=${minimumR}, p=${minimumP}")
-
-        // Assert
-        assertTrue("The default parameters for ScryptCipherProvider are too weak. Please update the default values to a stronger level.", n >= minimumN)
-    }
-
-    /**
-     * Returns the parameters required for a derivation to exceed 500 ms on this machine. Code adapted from http://security.stackexchange.com/questions/17207/recommended-of-rounds-for-bcrypt
-     *
-     * @param r the block size in bytes (defaults to 8)
-     * @param p the parallelization factor (defaults to 1)
-     * @param maxHeapSize the maximum heap size to use in bytes (defaults to 1 GB)
-     *
-     * @return the minimum scrypt parameters as [N, r, p]
-     */
-    private static List<Integer> calculateMinimumParameters(int r = 8, int p = 1, int maxHeapSize = 1024 * 1024 * 1024) {
-        // High start-up cost, so run multiple times for better benchmarking
-        final int RUNS = 10
-
-        // Benchmark using N=2^4
-        int n = 2**4
-        int dkLen = 128
-
-        assert Scrypt.calculateExpectedMemory(n, r, p) <= maxHeapSize
-
-        byte[] salt = new byte[Scrypt.defaultSaltLength]
-        new SecureRandom().nextBytes(salt)
-
-        // Run once to prime the system
-        double duration = time {
-            Scrypt.scrypt(MICROBENCHMARK, salt, n, r, p, dkLen)
-        }
-        logger.info("First run of N=${n}, r=${r}, p=${p} took ${duration} ms (ignored)")
-
-        def durations = []
-
-        RUNS.times { int i ->
-            duration = time {
-                Scrypt.scrypt(MICROBENCHMARK, salt, n, r, p, dkLen)
-            }
-            logger.info("N=${n}, r=${r}, p=${p} took ${duration} ms")
-            durations << duration
-        }
-
-        duration = durations.sum() / durations.size()
-        logger.info("N=${n}, r=${r}, p=${p} averaged ${duration} ms")
-
-        // Doubling N would double the run time
-        // Keep increasing N until the estimated duration is over 500 ms
-        while (duration < 500) {
-            n *= 2
-            duration *= 2
-        }
-
-        logger.info("Returning N=${n}, r=${r}, p=${p} for ${duration} ms")
-
-        return [n, r, p]
-    }
-
-    private static double time(Closure c) {
-        long start = System.nanoTime()
-        c.call()
-        long end = System.nanoTime()
-        return (end - start) / 1_000_000.0
-    }
-}
\ No newline at end of file