You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by jo...@apache.org on 2017/09/26 14:56:02 UTC

[2/7] nifi git commit: NIFI-3116 This closes #2108. Added initial regression test for StringEncryptor to ensure continued functionality during removal of Jasypt. Added external compatibility regression test for StringEncryptor to ensure continued functio

http://git-wip-us.apache.org/repos/asf/nifi/blob/2c1f5b49/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/security/util/crypto/scrypt/Scrypt.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/security/util/crypto/scrypt/Scrypt.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/security/util/crypto/scrypt/Scrypt.java
deleted file mode 100644
index 2aeae3d..0000000
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/security/util/crypto/scrypt/Scrypt.java
+++ /dev/null
@@ -1,510 +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.security.util.crypto.scrypt;
-
-import static java.lang.Integer.MAX_VALUE;
-import static java.lang.System.arraycopy;
-
-import java.nio.charset.StandardCharsets;
-import java.security.GeneralSecurityException;
-import java.security.SecureRandom;
-import java.util.ArrayList;
-import java.util.List;
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.nifi.security.util.crypto.CipherUtility;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-
-/**
- * Copyright (C) 2011 - Will Glozer.  All rights reserved.
- * <p/>
- * Taken from Will Glozer's port of Colin Percival's C implementation. Glozer's project located at <a href="https://github.com/wg/scrypt">https://github.com/wg/scrypt</a> was released under the ASF
- * 2.0 license and has not been updated since May 25, 2013 and there are outstanding issues which have been patched in this version.
- * <p/>
- * An implementation of the <a href="http://www.tarsnap.com/scrypt/scrypt.pdf">scrypt</a>
- * key derivation function.
- * <p/>
- * Allows for hashing passwords using the
- * <a href="http://www.tarsnap.com/scrypt.html">scrypt</a> key derivation function
- * and comparing a plain text password to a hashed one.
- */
-public class Scrypt {
-    private static final Logger logger = LoggerFactory.getLogger(Scrypt.class);
-
-    private static final int DEFAULT_SALT_LENGTH = 16;
-
-    /**
-     * Hash the supplied plaintext password and generate output in the format described
-     * below:
-     * <p/>
-     * The hashed output is an
-     * extended implementation of the Modular Crypt Format that also includes the scrypt
-     * algorithm parameters.
-     * <p/>
-     * Format: <code>$s0$PARAMS$SALT$KEY</code>.
-     * <p/>
-     * <dl>
-     * <dd>PARAMS</dd><dt>32-bit hex integer containing log2(N) (16 bits), r (8 bits), and p (8 bits)</dt>
-     * <dd>SALT</dd><dt>base64-encoded salt</dt>
-     * <dd>KEY</dd><dt>base64-encoded derived key</dt>
-     * </dl>
-     * <p/>
-     * <code>s0</code> identifies version 0 of the scrypt format, using a 128-bit salt and 256-bit derived key.
-     * <p/>
-     * This method generates a 16 byte random salt internally.
-     *
-     * @param password password
-     * @param n        CPU cost parameter
-     * @param r        memory cost parameter
-     * @param p        parallelization parameter
-     * @param dkLen    the desired key length in bits
-     * @return the hashed password
-     */
-    public static String scrypt(String password, int n, int r, int p, int dkLen) {
-        byte[] salt = new byte[DEFAULT_SALT_LENGTH];
-        new SecureRandom().nextBytes(salt);
-
-        return scrypt(password, salt, n, r, p, dkLen);
-    }
-
-    /**
-     * Hash the supplied plaintext password and generate output in the format described
-     * in {@link Scrypt#scrypt(String, int, int, int, int)}.
-     *
-     * @param password password
-     * @param salt     the raw salt (16 bytes)
-     * @param n        CPU cost parameter
-     * @param r        memory cost parameter
-     * @param p        parallelization parameter
-     * @param dkLen    the desired key length in bits
-     * @return the hashed password
-     */
-    public static String scrypt(String password, byte[] salt, int n, int r, int p, int dkLen) {
-        try {
-            byte[] derived = deriveScryptKey(password.getBytes(StandardCharsets.UTF_8), salt, n, r, p, dkLen);
-
-            return formatHash(salt, n, r, p, derived);
-        } catch (GeneralSecurityException e) {
-            throw new IllegalStateException("JVM doesn't support SHA1PRNG or HMAC_SHA256?");
-        }
-    }
-
-    public static String formatSalt(byte[] salt, int n, int r, int p) {
-        String params = encodeParams(n, r, p);
-
-        StringBuilder sb = new StringBuilder((salt.length) * 2);
-        sb.append("$s0$").append(params).append('$');
-        sb.append(CipherUtility.encodeBase64NoPadding(salt));
-
-        return sb.toString();
-    }
-
-    private static String encodeParams(int n, int r, int p) {
-        return Long.toString(log2(n) << 16L | r << 8 | p, 16);
-    }
-
-    private static String formatHash(byte[] salt, int n, int r, int p, byte[] derived) {
-        StringBuilder sb = new StringBuilder((salt.length + derived.length) * 2);
-        sb.append(formatSalt(salt, n, r, p)).append('$');
-        sb.append(CipherUtility.encodeBase64NoPadding(derived));
-
-        return sb.toString();
-    }
-
-    /**
-     * Returns the expected memory cost of the provided parameters in bytes.
-     *
-     * @param n the N value, iterations >= 2
-     * @param r the r value, block size >= 1
-     * @param p the p value, parallelization factor >= 1
-     * @return the memory cost in bytes
-     */
-    public static int calculateExpectedMemory(int n, int r, int p) {
-        return 128 * r * n + 128 * r * p;
-    }
-
-    /**
-     * Compare the supplied plaintext password to a hashed password.
-     *
-     * @param password plaintext password
-     * @param hashed   scrypt hashed password
-     * @return true if password matches hashed value
-     */
-    public static boolean check(String password, String hashed) {
-        try {
-            if (StringUtils.isEmpty(password)) {
-                throw new IllegalArgumentException("Password cannot be empty");
-            }
-
-            if (StringUtils.isEmpty(hashed)) {
-                throw new IllegalArgumentException("Hash cannot be empty");
-            }
-
-            String[] parts = hashed.split("\\$");
-
-            if (parts.length != 5 || !parts[1].equals("s0")) {
-                throw new IllegalArgumentException("Hash is not properly formatted");
-            }
-
-            List<Integer> splitParams = parseParameters(parts[2]);
-            int n = splitParams.get(0);
-            int r = splitParams.get(1);
-            int p = splitParams.get(2);
-
-            byte[] salt = Base64.decodeBase64(parts[3]);
-            byte[] derived0 = Base64.decodeBase64(parts[4]);
-
-            // Previously this was hard-coded to 32 bits but the publicly-available scrypt methods accept arbitrary bit lengths
-            int hashLength = derived0.length * 8;
-            byte[] derived1 = deriveScryptKey(password.getBytes(StandardCharsets.UTF_8), salt, n, r, p, hashLength);
-
-            if (derived0.length != derived1.length) return false;
-
-            int result = 0;
-            for (int i = 0; i < derived0.length; i++) {
-                result |= derived0[i] ^ derived1[i];
-            }
-            return result == 0;
-        } catch (GeneralSecurityException e) {
-            throw new IllegalStateException("JVM doesn't support SHA1PRNG or HMAC_SHA256?");
-        }
-    }
-
-    /**
-     * Parses the individual values from the encoded params value in the modified-mcrypt format for the salt & hash.
-     * <p/>
-     * Example:
-     * <p/>
-     * Hash: $s0$e0801$epIxT/h6HbbwHaehFnh/bw$7H0vsXlY8UxxyW/BWx/9GuY7jEvGjT71GFd6O4SZND0
-     * Params:   e0801
-     * <p/>
-     * N = 16384
-     * r = 8
-     * p = 1
-     *
-     * @param encodedParams the String representation of the second section of the mcrypt format hash
-     * @return a list containing N, r, p
-     */
-    public static List<Integer> parseParameters(String encodedParams) {
-        long params = Long.parseLong(encodedParams, 16);
-
-        List<Integer> paramsList = new ArrayList<>(3);
-
-        // Parse N, r, p from encoded value and add to return list
-        paramsList.add((int) Math.pow(2, params >> 16 & 0xffff));
-        paramsList.add((int) params >> 8 & 0xff);
-        paramsList.add((int) params & 0xff);
-
-        return paramsList;
-    }
-
-    private static int log2(int n) {
-        int log = 0;
-        if ((n & 0xffff0000) != 0) {
-            n >>>= 16;
-            log = 16;
-        }
-        if (n >= 256) {
-            n >>>= 8;
-            log += 8;
-        }
-        if (n >= 16) {
-            n >>>= 4;
-            log += 4;
-        }
-        if (n >= 4) {
-            n >>>= 2;
-            log += 2;
-        }
-        return log + (n >>> 1);
-    }
-
-    /**
-     * Implementation of the <a href="http://www.tarsnap.com/scrypt/scrypt.pdf">scrypt KDF</a>.
-     *
-     * @param password password
-     * @param salt     salt
-     * @param n        CPU cost parameter
-     * @param r        memory cost parameter
-     * @param p        parallelization parameter
-     * @param dkLen    intended length of the derived key in bits
-     * @return the derived key
-     * @throws GeneralSecurityException when HMAC_SHA256 is not available
-     */
-    protected static byte[] deriveScryptKey(byte[] password, byte[] salt, int n, int r, int p, int dkLen) throws GeneralSecurityException {
-        if (n < 2 || (n & (n - 1)) != 0) {
-            throw new IllegalArgumentException("N must be a power of 2 greater than 1");
-        }
-
-        if (r < 1) {
-            throw new IllegalArgumentException("Parameter r must be 1 or greater");
-        }
-
-        if (p < 1) {
-            throw new IllegalArgumentException("Parameter p must be 1 or greater");
-        }
-
-        if (n > MAX_VALUE / 128 / r) {
-            throw new IllegalArgumentException("Parameter N is too large");
-        }
-
-        // Must be enforced before r check
-        if (p > MAX_VALUE / 128) {
-            throw new IllegalArgumentException("Parameter p is too large");
-        }
-
-        if (r > MAX_VALUE / 128 / p) {
-            throw new IllegalArgumentException("Parameter r is too large");
-        }
-
-        if (password == null || password.length == 0) {
-            throw new IllegalArgumentException("Password cannot be empty");
-        }
-
-        int saltLength = salt == null ? 0 : salt.length;
-        if (salt == null || saltLength == 0) {
-            // Do not enforce this check here. According to the scrypt spec, the salt can be empty. However, in the user-facing ScryptCipherProvider, enforce an arbitrary check to avoid empty salts
-            logger.warn("An empty salt was used for scrypt key derivation");
-//            throw new IllegalArgumentException("Salt cannot be empty");
-            // as the Exception is not being thrown, prevent NPE if salt is null by setting it to empty array
-            if( salt == null ) salt = new byte[]{};
-        }
-
-        if (saltLength < 8 || saltLength > 32) {
-            // Do not enforce this check here. According to the scrypt spec, the salt can be empty. However, in the user-facing ScryptCipherProvider, enforce an arbitrary check of [8..32] bytes
-            logger.warn("A salt of length {} was used for scrypt key derivation", saltLength);
-//            throw new IllegalArgumentException("Salt must be between 8 and 32 bytes");
-        }
-
-        Mac mac = Mac.getInstance("HmacSHA256");
-        mac.init(new SecretKeySpec(password, "HmacSHA256"));
-
-        byte[] b = new byte[128 * r * p];
-        byte[] xy = new byte[256 * r];
-        byte[] v = new byte[128 * r * n];
-        int i;
-
-        pbkdf2(mac, salt, 1, b, p * 128 * r);
-
-        for (i = 0; i < p; i++) {
-            smix(b, i * 128 * r, r, n, v, xy);
-        }
-
-        byte[] dk = new byte[dkLen / 8];
-        pbkdf2(mac, b, 1, dk, dkLen / 8);
-        return dk;
-    }
-
-    /**
-     * Implementation of PBKDF2 (RFC2898).
-     *
-     * @param alg   the HMAC algorithm to use
-     * @param p     the password
-     * @param s     the salt
-     * @param c     the iteration count
-     * @param dkLen the intended length, in octets, of the derived key
-     * @return The derived key
-     */
-    private static byte[] pbkdf2(String alg, byte[] p, byte[] s, int c, int dkLen) throws GeneralSecurityException {
-        Mac mac = Mac.getInstance(alg);
-        mac.init(new SecretKeySpec(p, alg));
-        byte[] dk = new byte[dkLen];
-        pbkdf2(mac, s, c, dk, dkLen);
-        return dk;
-    }
-
-    /**
-     * Implementation of PBKDF2 (RFC2898).
-     *
-     * @param mac   the pre-initialized {@link Mac} instance to use
-     * @param s     the salt
-     * @param c     the iteration count
-     * @param dk    the byte array that derived key will be placed in
-     * @param dkLen the intended length, in octets, of the derived key
-     * @throws GeneralSecurityException if the key length is too long
-     */
-    private static void pbkdf2(Mac mac, byte[] s, int c, byte[] dk, int dkLen) throws GeneralSecurityException {
-        int hLen = mac.getMacLength();
-
-        if (dkLen > (Math.pow(2, 32) - 1) * hLen) {
-            throw new GeneralSecurityException("Requested key length too long");
-        }
-
-        byte[] U = new byte[hLen];
-        byte[] T = new byte[hLen];
-        byte[] block1 = new byte[s.length + 4];
-
-        int l = (int) Math.ceil((double) dkLen / hLen);
-        int r = dkLen - (l - 1) * hLen;
-
-        arraycopy(s, 0, block1, 0, s.length);
-
-        for (int i = 1; i <= l; i++) {
-            block1[s.length + 0] = (byte) (i >> 24 & 0xff);
-            block1[s.length + 1] = (byte) (i >> 16 & 0xff);
-            block1[s.length + 2] = (byte) (i >> 8 & 0xff);
-            block1[s.length + 3] = (byte) (i >> 0 & 0xff);
-
-            mac.update(block1);
-            mac.doFinal(U, 0);
-            arraycopy(U, 0, T, 0, hLen);
-
-            for (int j = 1; j < c; j++) {
-                mac.update(U);
-                mac.doFinal(U, 0);
-
-                for (int k = 0; k < hLen; k++) {
-                    T[k] ^= U[k];
-                }
-            }
-
-            arraycopy(T, 0, dk, (i - 1) * hLen, (i == l ? r : hLen));
-        }
-    }
-
-    private static void smix(byte[] b, int bi, int r, int n, byte[] v, byte[] xy) {
-        int xi = 0;
-        int yi = 128 * r;
-        int i;
-
-        arraycopy(b, bi, xy, xi, 128 * r);
-
-        for (i = 0; i < n; i++) {
-            arraycopy(xy, xi, v, i * (128 * r), 128 * r);
-            blockmix_salsa8(xy, xi, yi, r);
-        }
-
-        for (i = 0; i < n; i++) {
-            int j = integerify(xy, xi, r) & (n - 1);
-            blockxor(v, j * (128 * r), xy, xi, 128 * r);
-            blockmix_salsa8(xy, xi, yi, r);
-        }
-
-        arraycopy(xy, xi, b, bi, 128 * r);
-    }
-
-    private static void blockmix_salsa8(byte[] by, int bi, int yi, int r) {
-        byte[] X = new byte[64];
-        int i;
-
-        arraycopy(by, bi + (2 * r - 1) * 64, X, 0, 64);
-
-        for (i = 0; i < 2 * r; i++) {
-            blockxor(by, i * 64, X, 0, 64);
-            salsa20_8(X);
-            arraycopy(X, 0, by, yi + (i * 64), 64);
-        }
-
-        for (i = 0; i < r; i++) {
-            arraycopy(by, yi + (i * 2) * 64, by, bi + (i * 64), 64);
-        }
-
-        for (i = 0; i < r; i++) {
-            arraycopy(by, yi + (i * 2 + 1) * 64, by, bi + (i + r) * 64, 64);
-        }
-    }
-
-    private static int r(int a, int b) {
-        return (a << b) | (a >>> (32 - b));
-    }
-
-    private static void salsa20_8(byte[] b) {
-        int[] b32 = new int[16];
-        int[] x = new int[16];
-        int i;
-
-        for (i = 0; i < 16; i++) {
-            b32[i] = (b[i * 4 + 0] & 0xff) << 0;
-            b32[i] |= (b[i * 4 + 1] & 0xff) << 8;
-            b32[i] |= (b[i * 4 + 2] & 0xff) << 16;
-            b32[i] |= (b[i * 4 + 3] & 0xff) << 24;
-        }
-
-        arraycopy(b32, 0, x, 0, 16);
-
-        for (i = 8; i > 0; i -= 2) {
-            x[4] ^= r(x[0] + x[12], 7);
-            x[8] ^= r(x[4] + x[0], 9);
-            x[12] ^= r(x[8] + x[4], 13);
-            x[0] ^= r(x[12] + x[8], 18);
-            x[9] ^= r(x[5] + x[1], 7);
-            x[13] ^= r(x[9] + x[5], 9);
-            x[1] ^= r(x[13] + x[9], 13);
-            x[5] ^= r(x[1] + x[13], 18);
-            x[14] ^= r(x[10] + x[6], 7);
-            x[2] ^= r(x[14] + x[10], 9);
-            x[6] ^= r(x[2] + x[14], 13);
-            x[10] ^= r(x[6] + x[2], 18);
-            x[3] ^= r(x[15] + x[11], 7);
-            x[7] ^= r(x[3] + x[15], 9);
-            x[11] ^= r(x[7] + x[3], 13);
-            x[15] ^= r(x[11] + x[7], 18);
-            x[1] ^= r(x[0] + x[3], 7);
-            x[2] ^= r(x[1] + x[0], 9);
-            x[3] ^= r(x[2] + x[1], 13);
-            x[0] ^= r(x[3] + x[2], 18);
-            x[6] ^= r(x[5] + x[4], 7);
-            x[7] ^= r(x[6] + x[5], 9);
-            x[4] ^= r(x[7] + x[6], 13);
-            x[5] ^= r(x[4] + x[7], 18);
-            x[11] ^= r(x[10] + x[9], 7);
-            x[8] ^= r(x[11] + x[10], 9);
-            x[9] ^= r(x[8] + x[11], 13);
-            x[10] ^= r(x[9] + x[8], 18);
-            x[12] ^= r(x[15] + x[14], 7);
-            x[13] ^= r(x[12] + x[15], 9);
-            x[14] ^= r(x[13] + x[12], 13);
-            x[15] ^= r(x[14] + x[13], 18);
-        }
-
-        for (i = 0; i < 16; ++i) b32[i] = x[i] + b32[i];
-
-        for (i = 0; i < 16; i++) {
-            b[i * 4 + 0] = (byte) (b32[i] >> 0 & 0xff);
-            b[i * 4 + 1] = (byte) (b32[i] >> 8 & 0xff);
-            b[i * 4 + 2] = (byte) (b32[i] >> 16 & 0xff);
-            b[i * 4 + 3] = (byte) (b32[i] >> 24 & 0xff);
-        }
-    }
-
-    private static void blockxor(byte[] s, int si, byte[] d, int di, int len) {
-        for (int i = 0; i < len; i++) {
-            d[di + i] ^= s[si + i];
-        }
-    }
-
-    private static int integerify(byte[] b, int bi, int r) {
-        int n;
-
-        bi += (2 * r - 1) * 64;
-
-        n = (b[bi + 0] & 0xff) << 0;
-        n |= (b[bi + 1] & 0xff) << 8;
-        n |= (b[bi + 2] & 0xff) << 16;
-        n |= (b[bi + 3] & 0xff) << 24;
-
-        return n;
-    }
-
-    public static int getDefaultSaltLength() {
-        return DEFAULT_SALT_LENGTH;
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/2c1f5b49/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/security/util/crypto/BcryptCipherProviderGroovyTest.groovy
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/security/util/crypto/BcryptCipherProviderGroovyTest.groovy b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/security/util/crypto/BcryptCipherProviderGroovyTest.groovy
deleted file mode 100644
index e5e001f..0000000
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/security/util/crypto/BcryptCipherProviderGroovyTest.groovy
+++ /dev/null
@@ -1,538 +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.security.util.crypto
-
-import org.apache.commons.codec.binary.Base64
-import org.apache.commons.codec.binary.Hex
-import org.apache.nifi.security.util.EncryptionMethod
-import org.apache.nifi.security.util.crypto.bcrypt.BCrypt
-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.spec.IvParameterSpec
-import javax.crypto.spec.SecretKeySpec
-import java.security.Security
-
-import static groovy.test.GroovyAssert.shouldFail
-import static org.junit.Assert.assertTrue
-
-@RunWith(JUnit4.class)
-public class BcryptCipherProviderGroovyTest {
-    private static final Logger logger = LoggerFactory.getLogger(BcryptCipherProviderGroovyTest.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
-
-    @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 BcryptCipherProvider(4)
-
-        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
-        RandomIVPBECipherProvider cipherProvider = new BcryptCipherProvider(4)
-
-        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());
-
-        RandomIVPBECipherProvider cipherProvider = new BcryptCipherProvider(4)
-
-        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 testHashPWShouldMatchTestVectors() {
-        // Arrange
-        final String PASSWORD = 'abcdefghijklmnopqrstuvwxyz'
-        final String SALT = '$2a$10$fVH8e28OQRj9tqiDXs1e1u'
-        final String EXPECTED_HASH = '$2a$10$fVH8e28OQRj9tqiDXs1e1uxpsjN0c7II7YPKXua2NAKYvM6iQk7dq'
-//        final int WORK_FACTOR = 10
-
-        // Act
-        String calculatedHash = BCrypt.hashpw(PASSWORD, SALT)
-        logger.info("Generated ${calculatedHash}")
-
-        // Assert
-        assert calculatedHash == EXPECTED_HASH
-    }
-
-    @Test
-    public void testGetCipherShouldSupportExternalCompatibility() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new BcryptCipherProvider(4)
-
-        final String PLAINTEXT = "This is a plaintext message.";
-        final String PASSWORD = "thisIsABadPassword";
-
-        // These values can be generated by running `$ ./openssl_bcrypt` in the terminal
-        final byte[] SALT = Hex.decodeHex("81455b915ce9efd1fc61a08eb0255936" as char[]);
-        final byte[] IV = Hex.decodeHex("41a51e0150df6a1f72826b36c6371f3f" as char[]);
-
-        // $v2$w2$base64_salt_22__base64_hash_31
-        final String FULL_HASH = "\$2a\$10\$gUVbkVzp79H8YaCOsCVZNuz/d759nrMKzjuviaS5/WdcKHzqngGKi"
-        logger.info("Full Hash: ${FULL_HASH}")
-        final String HASH = FULL_HASH[-31..-1]
-        logger.info("     Hash: ${HASH.padLeft(60, " ")}")
-        logger.info(" B64 Salt: ${CipherUtility.encodeBase64NoPadding(SALT).padLeft(29, " ")}")
-
-        String extractedSalt = FULL_HASH[7..<29]
-        logger.info("Extracted Salt:   ${extractedSalt}")
-        String extractedSaltHex = Hex.encodeHexString(Base64.decodeBase64(extractedSalt))
-        logger.info("Extracted Salt (hex): ${extractedSaltHex}")
-        logger.info(" Expected Salt (hex): ${Hex.encodeHexString(SALT)}")
-
-        final String CIPHER_TEXT = "3a226ba2b3c8fe559acb806620001246db289375ba8075a68573478b56a69f15"
-        byte[] cipherBytes = Hex.decodeHex(CIPHER_TEXT as char[])
-
-        EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-        logger.info("Using algorithm: ${encryptionMethod.getAlgorithm()}");
-        logger.info("External cipher text: ${Hex.encodeHexString(cipherBytes)} ${cipherBytes.length}");
-
-        // Sanity check
-        Cipher rubyCipher = Cipher.getInstance(encryptionMethod.algorithm, "BC")
-        def rubyKey = new SecretKeySpec(Hex.decodeHex("724cd9e1b0b9e87c7f7e7d7b270bca07" as char[]), "AES")
-        def ivSpec = new IvParameterSpec(IV)
-        rubyCipher.init(Cipher.ENCRYPT_MODE, rubyKey, ivSpec)
-        byte[] rubyCipherBytes = rubyCipher.doFinal(PLAINTEXT.bytes)
-        logger.info("Expected cipher text: ${Hex.encodeHexString(rubyCipherBytes)}")
-        rubyCipher.init(Cipher.DECRYPT_MODE, rubyKey, ivSpec)
-        assert rubyCipher.doFinal(rubyCipherBytes) == PLAINTEXT.bytes
-        assert rubyCipher.doFinal(cipherBytes) == PLAINTEXT.bytes
-        logger.sanity("Decrypted external cipher text and generated cipher text successfully")
-
-        // Sanity for hash generation
-        final String FULL_SALT = FULL_HASH[0..<29]
-        logger.sanity("Salt from external: ${FULL_SALT}")
-        String generatedHash = BCrypt.hashpw(PASSWORD, FULL_SALT)
-        logger.sanity("Generated hash: ${generatedHash}")
-        assert generatedHash == FULL_HASH
-
-        // Act
-        Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, FULL_SALT.bytes, 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 testGetCipherShouldHandleFullSalt() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new BcryptCipherProvider(4)
-
-        final String PLAINTEXT = "This is a plaintext message.";
-        final String PASSWORD = "thisIsABadPassword";
-
-        // These values can be generated by running `$ ./openssl_bcrypt.rb` in the terminal
-        final byte[] IV = Hex.decodeHex("41a51e0150df6a1f72826b36c6371f3f" as char[]);
-
-        // $v2$w2$base64_salt_22__base64_hash_31
-        final String FULL_HASH = "\$2a\$10\$gUVbkVzp79H8YaCOsCVZNuz/d759nrMKzjuviaS5/WdcKHzqngGKi"
-        logger.info("Full Hash: ${FULL_HASH}")
-        final String FULL_SALT = FULL_HASH[0..<29]
-        logger.info("     Salt: ${FULL_SALT}")
-        final String HASH = FULL_HASH[-31..-1]
-        logger.info("     Hash: ${HASH.padLeft(60, " ")}")
-
-        String extractedSalt = FULL_HASH[7..<29]
-        logger.info("Extracted Salt:   ${extractedSalt}")
-        String extractedSaltHex = Hex.encodeHexString(Base64.decodeBase64(extractedSalt))
-        logger.info("Extracted Salt (hex): ${extractedSaltHex}")
-
-        final String CIPHER_TEXT = "3a226ba2b3c8fe559acb806620001246db289375ba8075a68573478b56a69f15"
-        byte[] cipherBytes = Hex.decodeHex(CIPHER_TEXT as char[])
-
-        EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-        logger.info("Using algorithm: ${encryptionMethod.getAlgorithm()}");
-        logger.info("External cipher text: ${Hex.encodeHexString(cipherBytes)} ${cipherBytes.length}");
-
-        // Act
-        Cipher cipher = cipherProvider.getCipher(encryptionMethod, PASSWORD, FULL_SALT.bytes, 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 testGetCipherShouldHandleUnformedSalt() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new BcryptCipherProvider(4)
-
-        final String PASSWORD = "thisIsABadPassword";
-
-        final def INVALID_SALTS = ['$ab$00$acbdefghijklmnopqrstuv', 'bad_salt', '$3a$11$', 'x', '$2a$10$']
-
-        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 of the format \\\$2a\\\$10\\\$gUVbkVzp79H8YaCOsCVZNu\\. To generate a salt, use BcryptCipherProvider#generateSalt"
-        }
-    }
-
-    String bytesToBitString(byte[] bytes) {
-        bytes.collect {
-            String.format("%8s", Integer.toBinaryString(it & 0xFF)).replace(' ', '0')
-        }.join("")
-    }
-
-    String spaceString(String input, int blockSize = 4) {
-        input.collect { it.padLeft(blockSize, " ") }.join("")
-    }
-
-    @Test
-    public void testGetCipherShouldRejectEmptySalt() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new BcryptCipherProvider(4)
-
-        final String PASSWORD = "thisIsABadPassword";
-
-        EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC
-        logger.info("Using algorithm: ${encryptionMethod.getAlgorithm()}");
-
-        // Two different errors -- one explaining the no-salt method is not supported, and the other for an empty byte[] passed
-
-        // 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 BcryptCipherProvider#generateSalt"
-    }
-
-    @Test
-    public void testGetCipherForDecryptShouldRequireIV() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new BcryptCipherProvider(4)
-
-        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);
-            }
-
-            // Assert
-            assert msg =~ "Cannot decrypt without a valid IV"
-        }
-    }
-
-    @Test
-    public void testGetCipherShouldAcceptValidKeyLengths() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new BcryptCipherProvider(4);
-
-        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
-        RandomIVPBECipherProvider cipherProvider = new BcryptCipherProvider(4);
-
-        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.";
-
-        // Currently only AES ciphers are compatible with Bcrypt, so redundant to test all algorithms
-        final def INVALID_KEY_LENGTHS = [-1, 40, 64, 112, 512]
-        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);
-            }
-
-            // Assert
-            assert msg =~ "${keyLength} is not a valid key length for AES"
-        }
-    }
-
-    @Test
-    public void testGenerateSaltShouldUseProvidedWorkFactor() throws Exception {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new BcryptCipherProvider(11);
-        int workFactor = cipherProvider.getWorkFactor()
-
-        // Act
-        final byte[] saltBytes = cipherProvider.generateSalt()
-        String salt = new String(saltBytes)
-        logger.info("Salt: ${salt}")
-
-        // Assert
-        assert salt =~ /^\$2[axy]\$\d{2}\$/
-        assert salt.contains("\$${workFactor}\$")
-    }
-
-    @Ignore("This test can be run on a specific machine to evaluate if the default work factor is sufficient")
-    @Test
-    public void testDefaultConstructorShouldProvideStrongWorkFactor() {
-        // Arrange
-        RandomIVPBECipherProvider cipherProvider = new BcryptCipherProvider();
-
-        // 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 work factor to reach 500 ms
-        int minimumWorkFactor = calculateMinimumWorkFactor()
-        logger.info("Determined minimum safe work factor to be ${minimumWorkFactor}")
-
-        // Act
-        int workFactor = cipherProvider.getWorkFactor()
-        logger.info("Default work factor ${workFactor}")
-
-        // Assert
-        assertTrue("The default work factor for BcryptCipherProvider is too weak. Please update the default value to a stronger level.", workFactor >= minimumWorkFactor)
-    }
-
-    /**
-     * Returns the work factor 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
-     *
-     * @return the minimum bcrypt work factor
-     */
-    private static int calculateMinimumWorkFactor() {
-        // High start-up cost, so run multiple times for better benchmarking
-        final int RUNS = 10
-
-        // Benchmark using a work factor of 5 (the second-lowest allowed)
-        int workFactor = 5
-
-        String salt = BCrypt.gensalt(workFactor)
-
-        // Run once to prime the system
-        double duration = time {
-            BCrypt.hashpw(MICROBENCHMARK, salt)
-        }
-        logger.info("First run of work factor ${workFactor} took ${duration} ms (ignored)")
-
-        def durations = []
-
-        RUNS.times { int i ->
-            duration = time {
-                BCrypt.hashpw(MICROBENCHMARK, salt)
-            }
-            logger.info("Work factor ${workFactor} took ${duration} ms")
-            durations << duration
-        }
-
-        duration = durations.sum() / durations.size()
-        logger.info("Work factor ${workFactor} averaged ${duration} ms")
-
-        // Increasing the work factor by 1 would double the run time
-        // Keep increasing N until the estimated duration is over 500 ms
-        while (duration < 500) {
-            workFactor += 1
-            duration *= 2
-        }
-
-        logger.info("Returning work factor ${workFactor} for ${duration} ms")
-
-        return workFactor
-    }
-
-    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

http://git-wip-us.apache.org/repos/asf/nifi/blob/2c1f5b49/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/security/util/crypto/CipherProviderFactoryGroovyTest.groovy
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/security/util/crypto/CipherProviderFactoryGroovyTest.groovy b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/security/util/crypto/CipherProviderFactoryGroovyTest.groovy
deleted file mode 100644
index 28da9d1..0000000
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/security/util/crypto/CipherProviderFactoryGroovyTest.groovy
+++ /dev/null
@@ -1,97 +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.security.util.crypto
-
-import org.apache.nifi.security.util.KeyDerivationFunction
-import org.bouncycastle.jce.provider.BouncyCastleProvider
-import org.junit.After
-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 java.security.Security
-
-@RunWith(JUnit4.class)
-class CipherProviderFactoryGroovyTest extends GroovyTestCase {
-    private static final Logger logger = LoggerFactory.getLogger(CipherProviderFactoryGroovyTest.class)
-
-    private static final Map<KeyDerivationFunction, Class> EXPECTED_CIPHER_PROVIDERS = [
-            (KeyDerivationFunction.BCRYPT)                  : BcryptCipherProvider.class,
-            (KeyDerivationFunction.NIFI_LEGACY)             : NiFiLegacyCipherProvider.class,
-            (KeyDerivationFunction.NONE)                    : AESKeyedCipherProvider.class,
-            (KeyDerivationFunction.OPENSSL_EVP_BYTES_TO_KEY): OpenSSLPKCS5CipherProvider.class,
-            (KeyDerivationFunction.PBKDF2)                  : PBKDF2CipherProvider.class,
-            (KeyDerivationFunction.SCRYPT)                  : ScryptCipherProvider.class
-    ]
-
-    @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 testGetCipherProviderShouldResolveRegisteredKDFs() {
-        // Arrange
-
-        // Act
-        KeyDerivationFunction.values().each { KeyDerivationFunction kdf ->
-            logger.info("Expected: ${kdf.name} -> ${EXPECTED_CIPHER_PROVIDERS.get(kdf).simpleName}")
-            CipherProvider cp = CipherProviderFactory.getCipherProvider(kdf)
-            logger.info("Resolved: ${kdf.name} -> ${cp.class.simpleName}")
-
-            // Assert
-            assert cp.class == (EXPECTED_CIPHER_PROVIDERS.get(kdf))
-        }
-    }
-
-    @Ignore("Cannot mock enum using Groovy map coercion")
-    @Test
-    public void testGetCipherProviderShouldHandleUnregisteredKDFs() {
-        // Arrange
-
-        // Can't mock this; see http://stackoverflow.com/questions/5323505/mocking-java-enum-to-add-a-value-to-test-fail-case
-        KeyDerivationFunction invalidKDF = [name: "Unregistered", description: "Not a registered KDF"] as KeyDerivationFunction
-        logger.info("Expected: ${invalidKDF.name} -> error")
-
-        // Act
-        def msg = shouldFail(IllegalArgumentException) {
-            CipherProvider cp = CipherProviderFactory.getCipherProvider(invalidKDF)
-            logger.info("Resolved: ${invalidKDF.name} -> ${cp.class.simpleName}")
-        }
-        logger.expected(msg)
-
-        // Assert
-        assert msg =~ "No cipher provider registered for ${invalidKDF.name}"
-    }
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/2c1f5b49/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/security/util/crypto/NiFiLegacyCipherProviderGroovyTest.groovy
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/security/util/crypto/NiFiLegacyCipherProviderGroovyTest.groovy b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/security/util/crypto/NiFiLegacyCipherProviderGroovyTest.groovy
deleted file mode 100644
index 2a3d456..0000000
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/security/util/crypto/NiFiLegacyCipherProviderGroovyTest.groovy
+++ /dev/null
@@ -1,299 +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.security.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.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.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/2c1f5b49/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/security/util/crypto/OpenSSLPKCS5CipherProviderGroovyTest.groovy
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/security/util/crypto/OpenSSLPKCS5CipherProviderGroovyTest.groovy b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/security/util/crypto/OpenSSLPKCS5CipherProviderGroovyTest.groovy
deleted file mode 100644
index 62b7970..0000000
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/security/util/crypto/OpenSSLPKCS5CipherProviderGroovyTest.groovy
+++ /dev/null
@@ -1,323 +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.security.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.After
-import org.junit.Assume
-import org.junit.Before
-import org.junit.BeforeClass
-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.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