- updated and added tests
- replaced junit EnumSource with ArgumentsSource in CryptoUtilJ8ParameterizedTest
 (automatically converts to provided argument enum by JUnit Argument Conversion)
- check system ciphers in test and cli info (printInfo)
- dynamic clear code in CryptoParametersJ8
- fixes and cleanup of typed instances CryptoUtilJ8 and CryptoStreamFactoryJ8Template
- added documentation

git-svn-id: https://svn.apache.org/repos/asf/turbine/fulcrum/trunk/yaafi-crypto@1880199 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index bb8e321..7556de7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,8 +20,9 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <parent>
     <artifactId>turbine-parent</artifactId>
-       <groupId>org.apache.turbine</groupId>
-       <version>7</version>
+    <groupId>org.apache.turbine</groupId>
+    <version>7</version>
+    <relativePath />
   </parent>
 
   <modelVersion>4.0.0</modelVersion>
@@ -206,6 +207,15 @@
 
         </executions>
       </plugin>
+      
+      <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <configuration>
+            <forkCount>1</forkCount>
+            <reuseFork>true</reuseFork>
+           </configuration>
+        </plugin>
     </plugins>
   </build>
   
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 35ed3d8..edd24a1 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -25,6 +25,9 @@
 
   <body>
     <release version="1.0.8" date="as in SVN">
+    <action dev="gk" type="update">
+        Updated Tests using Junit extension. More flexible comman line utility, defining CLI2 as manifest main class. Fine tuning clear code prefix and added integration-test
+      </action>
       <action dev="gk" type="update">
         Added two Java 8 implementations based on PBE/AES (PBEWithHmacSHA256AndAES_256) or GCM (AES/GCM/NoPadding) encryption.
       </action>
diff --git a/src/filters/filter-integration-test.properties b/src/filters/filter-integration-test.properties
index f49b270..b08a2f5 100644
--- a/src/filters/filter-integration-test.properties
+++ b/src/filters/filter-integration-test.properties
@@ -1,2 +1,2 @@
-#Mon, 20 Jul 2020 13:46:30 +0200

-password_encrypted=1796bc2d3d02f478bb042ed24740e98a2654fa47bd331266e1a7b682c2d37a2d0254dc61dd71badfe1c22b745f039041

+#Thu, 23 Jul 2020 13:53:53 +0200

+password_encrypted=0e88b1ae1cc8bcee9df12575805fbb770d70123259929778998a8285730b1d53453632a50fd9cac77d8a8f1603b622f4

diff --git a/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactoryImpl.java b/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactoryImpl.java
index 3e27a33..609d0a6 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactoryImpl.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactoryImpl.java
@@ -122,6 +122,27 @@
         this.providerName = PROVIDERNAME;
         this.algorithm = CryptoParameters.ALGORITHM;
     }
+    
+
+    /**
+     * Factory method to get a default instance
+     * 
+     * @param salt the salt for the PBE algorithm
+     * @param count the iteration for PBEParameterSpec
+     * @return an instance of the CryptoStreamFactory
+     * 
+     */
+    public static CryptoStreamFactory getInstance( byte[] salt, int count)
+    {
+        synchronized(CryptoStreamFactoryImpl.class ) {
+            if( CryptoStreamFactoryImpl.instance == null )
+            {
+                CryptoStreamFactoryImpl.instance = new CryptoStreamFactoryImpl(salt, count);
+            }
+    
+            return CryptoStreamFactoryImpl.instance;
+        }
+    }
 
     /**
      * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getSmartInputStream(java.io.InputStream,char[])
diff --git a/src/java/org/apache/fulcrum/jce/crypto/CryptoUtil.java b/src/java/org/apache/fulcrum/jce/crypto/CryptoUtil.java
index 81f8d3a..7272f76 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/CryptoUtil.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/CryptoUtil.java
@@ -26,6 +26,8 @@
 import java.security.GeneralSecurityException;
 
 import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8;
+import org.apache.fulcrum.jce.crypto.extended.CryptoStreamFactoryJ8Template;
+import org.apache.fulcrum.jce.crypto.extended.CryptoUtilJ8;
 
 /**
  * Helper class to provde generic functions to work with CryptoStreams.
@@ -43,7 +45,7 @@
     private static CryptoUtil instance;
     
     
-    private CryptoStreamFactory cryptoStreamFactory;
+    protected CryptoStreamFactory cryptoStreamFactory;
     
     /**
      * Factory method to get a default instance
@@ -64,6 +66,29 @@
     protected CryptoUtil() {
         cryptoStreamFactory = CryptoStreamFactoryImpl.getInstance();
     }
+    
+    /**
+     * Factory method to get a default instance
+     * 
+     * @param salt the salt for the PBE algorithm
+     * @param count the iteration for PBEParameterSpec
+     * @return an instance of the CryptoUtil
+     */
+    public synchronized static CryptoUtil getInstance(byte[] salt, int count) {
+        if (CryptoUtil.instance == null) {
+            CryptoUtil.instance = new CryptoUtil(salt, count);
+        }
+
+        return CryptoUtil.instance;
+    }
+    
+    /**
+     *  @param salt the salt for the PBE algorithm
+     *  @param count the iteration for PBEParameterSpec
+     */
+    protected CryptoUtil(byte[] salt, int count) {
+        cryptoStreamFactory = CryptoStreamFactoryImpl.getInstance(salt, count);
+    }
 
     /**
      * Copies from a source to a target object using encryption
@@ -100,7 +125,7 @@
 
     
     /**
-     * Encrypts a string into a hex string using {@link CryptoParametersJ8#CLEAR_CODE_J8}
+     * Encrypts a string into a hex string using {@link CryptoParametersJ8#CLEAR_CODE_DEFAULT}
      *
      * @param plainText the plain text to be encrypted
      * @param password  the password for encryption
@@ -138,10 +163,12 @@
      */
     public String encryptString(CryptoStreamFactory factory, String plainText, char[] password, boolean withClearCode)
             throws GeneralSecurityException, IOException {
-        ByteArrayOutputStream bais = new ByteArrayOutputStream();
-        encrypt(factory, plainText, bais, password);
-        return (withClearCode)? CryptoParametersJ8.CLEAR_CODE_J8 + HexConverter.toString(bais.toByteArray()):
-            HexConverter.toString(bais.toByteArray());
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        encrypt(factory, plainText, baos, password);
+        String prefix =  (withClearCode)? (this instanceof CryptoUtilJ8)?
+        		((CryptoStreamFactoryJ8Template)((CryptoUtilJ8)this).getCryptoStreamFactory()).getType().getClearCode()
+            	: CryptoParametersJ8.CLEAR_CODE_DEFAULT: "";
+        return prefix + HexConverter.toString(baos.toByteArray());
     }
     
     /**
@@ -161,7 +188,9 @@
      * Decrypts an encrypted string into the plain text. The encrypted string must
      * be a hex string created by encryptString.
      * 
-     * Decrypts encrypted text after {@link CryptoParametersJ8#CLEAR_CODE_J8}.
+     * Decrypts encrypted text after {@link CryptoParametersJ8#CLEAR_CODE_DEFAULT}.
+     * 
+     * Removes ClearCode length of 10 bit, before decrpyting expected as prefix.
      *
      * @param cipherText the encrypted text to be decrypted
      * @param password   the password for decryption
@@ -170,7 +199,7 @@
      * @throws IOException              accessing the souce failed
      */
     public String decryptStringWithClearCode(String cipherText, char[] password) throws GeneralSecurityException, IOException {
-        return decryptString(getCryptoStreamFactory(), cipherText.substring(CryptoParametersJ8.CLEAR_CODE_J8.length()), password);
+        return decryptString(getCryptoStreamFactory(), cipherText.substring(10), password);
     }
 
     /**
@@ -200,7 +229,7 @@
      */
     public String decryptString(String cipherText, char[] password, boolean withClearCode) throws GeneralSecurityException, IOException {
         return decryptString(getCryptoStreamFactory(), withClearCode?
-                cipherText.substring(CryptoParametersJ8.CLEAR_CODE_J8.length()):
+                cipherText.substring(CryptoParametersJ8.CLEAR_CODE_DEFAULT.length()):
                 cipherText, password);
     }
 
diff --git a/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamGCMImpl.java b/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamGCMImpl.java
index f8bc29d..0fad268 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamGCMImpl.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamGCMImpl.java
@@ -69,24 +69,21 @@
      */
     public CryptoStreamGCMImpl() throws GeneralSecurityException
     {
-        this.salt =  generateSalt();
-        this.providerName = PROVIDERNAME;
-        this.algorithm = CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_GCM.getAlgorithm();
+        this(generateSalt());
     }
 
 
     /**
      * Constructor
      *
-     * @param salt the salt for the PBE algorithm
-     * @param count the iteration for PBEParameterSpec
+     * @param salt the salt for the GCM algorithm
 
      */
-    public CryptoStreamGCMImpl( byte[] salt, int count) 
+    public CryptoStreamGCMImpl( byte[] salt) 
     {
-        this.salt = salt.clone();
-        this.count = count;
+        setSalt(salt);
         this.providerName = PROVIDERNAME;
+        setType(TYPES.GCM);
         this.algorithm = CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_GCM.getAlgorithm();
     }
 
@@ -102,7 +99,6 @@
     protected Key createKey( char[] password, byte[] salt ) 
             throws GeneralSecurityException
     {
-
         SecretKey key = new SecretKeySpec(((salt == null)? this.getSalt(): salt.clone()), "AES");
         return key;
     }
diff --git a/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamPBEImpl.java b/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamPBEImpl.java
index 12d1f15..adc1603 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamPBEImpl.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamPBEImpl.java
@@ -31,7 +31,6 @@
 
 import javax.crypto.Cipher;
 import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.GCMParameterSpec;
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.PBEKeySpec;
 import javax.crypto.spec.PBEParameterSpec;
@@ -69,34 +68,48 @@
 
     protected static final int IV_SIZE = 16;
     
+    protected static final int KEY_SIZE = 256;
+    
 	/**
 	 * default count for pbe spec
 	 */
-	protected int COUNT_J8 = 10_000; // 200_000;
+	protected static final int COUNT_J8 = 10_000; // 200_000;
 
     /**
      * Constructor
+     * count is set to {@link #COUNT_J8}.
+     * 
      * @throws GeneralSecurityException  if no algo could be found.
      */
     public CryptoStreamPBEImpl() throws GeneralSecurityException
     {
-        this.salt =  generateSalt();
-        this.count = COUNT_J8;
-        this.providerName = PROVIDERNAME;
-        this.algorithm = CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_PBE.getAlgorithm();
+        this(generateSalt(), COUNT_J8);
     }
     
     /**
      * Constructor
      *
      * @param salt the salt for the PBE algorithm
+     */
+    public CryptoStreamPBEImpl( byte[] salt)
+    {
+        this(salt, COUNT_J8);
+        
+    }
+
+    
+    /**
+     * Constructor
+     *
+     * @param salt the salt for the PBE algorithm
      * @param count the iteration for PBEParameterSpec
      */
     public CryptoStreamPBEImpl( byte[] salt, int count)
     {
-        this.salt = salt.clone();
+        setSalt(salt);
         this.count = count;
         this.providerName = PROVIDERNAME;
+        setType(TYPES.PBE);
         this.algorithm = CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_PBE.getAlgorithm();
     }
 
diff --git a/src/java/org/apache/fulcrum/jce/crypto/cli/CLI2.java b/src/java/org/apache/fulcrum/jce/crypto/cli/CLI2.java
index 4c7989c..e6ba487 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/cli/CLI2.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/cli/CLI2.java
@@ -27,6 +27,7 @@
 import java.io.OutputStreamWriter;
 import java.nio.charset.Charset;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Optional;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -35,331 +36,336 @@
 import org.apache.fulcrum.jce.crypto.HexConverter;
 import org.apache.fulcrum.jce.crypto.StreamUtil;
 import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8;
+import org.apache.fulcrum.jce.crypto.extended.CryptoStreamFactoryJ8Template;
 import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8.TYPES;
 import org.apache.fulcrum.jce.crypto.extended.CryptoUtilJ8;
 
 /**
+ * <b>Manifest main class</b>.
+ * 
  * Command line tool for encrypting/decrypting a file or string
  *
- * file [enc|dec] passwd [file]*
- * string [enc|dec] passwd plaintext
+ * file [enc|dec] passwd [file]* string [enc|dec] passwd plaintext
  * 
  * Example :
  * 
- * <pre>java -classpath target/classes org.apache.fulcrum.jce.crypto.cli.CLI2 string enc changeit mysecretgeheim</pre>
+ * <pre>
+ * java -classpath target/classes org.apache.fulcrum.jce.crypto.cli.CLI2 string enc changeit mysecretgeheim
+ * </pre>
+ * 
+ * <pre>
+ * java -jar target/fulcrum-yaafi-crypto-1.0.8.jar string enc changeit mysecretgeheim
+ * </pre>
+ * 
  * ...
  * 
- * <pre>java -cp target/classes org.apache.fulcrum.jce.crypto.cli.Main string dec changeit J8_AES256 </pre>
+ * <pre>
+ * java java -jar target/fulcrum-yaafi-crypto-1.0.8.jar string dec changeit anothersecret
+ * </pre>
+ * 
+ *  @author gk@apache.org
  *
- * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
  */
+public class CLI2 {
+	
+	
+	static boolean debug = false;
+	/**
+	 * Allows usage on the command line.
+	 * 
+	 * @param args the command line parameters
+	 */
+	public static void main(String[] args) {
+		try {
+			if (args.length == 0) {
+				printHelp();
+				return;
+			}
+			String operationMode = args[0];
 
-public class CLI2
-{
-    /**
-     * Allows usage on the command line.
-     * 
-     * @param args the command line parameters
-     */
-    public static void main( String[] args )
-    {
-        try
-        {
-            if (args.length ==0 ){
-                printHelp();
-                return;
-            }
-            String operationMode = args[0];
-            
-            String msg = "No operationMode" ;
-            if (operationMode == null || operationMode.equals("")) 
-            {
-                throw new IllegalArgumentException(msg);
-            }
-            
-            if( operationMode.equals("info") )
-            {
-                printInfo();
-                return;
-            } 
-            else if (operationMode.equals("help") ) 
-            {
-                printHelp();
-                return;
-            }
-            
-            if( args.length < 3 )
-            {
-                printHelp();
-                throw new IllegalArgumentException("Invalid command line");
-            }
+			String msg = "No operationMode";
+			if (operationMode == null || operationMode.equals("")) {
+				throw new IllegalArgumentException(msg);
+			}
 
+			if (operationMode.equals("info")) {
+				printInfo();
+				return;
+			} else if (operationMode.equals("help")) {
+				printHelp();
+				return;
+			}
 
-            if( operationMode.equals("file") )
-            {
-                processFiles(args);
-            }
-            else if( operationMode.equals("string") )
-            {
-                processString(args);
-            }
-        }
-        catch (Exception e)
-        {
-            System.out.println("Error : " + e.getMessage());
-            e.printStackTrace();
-        }
-    }
+			if (args.length < 3) {
+				printHelp();
+				throw new IllegalArgumentException("Invalid command line");
+			}
 
-    private static void printInfo() 
-    {
-        CryptoUtilJ8 cryptoUtilJ8 = CryptoUtilJ8.getInstance();
-        System.out.println("\tCrypto factory class: " + cryptoUtilJ8.getCryptoStreamFactory().getClass());
-        System.out.println("\tDefault Algorithm used: " + cryptoUtilJ8.getCryptoStreamFactory().getAlgorithm());
-        String algoShortList= Arrays.stream(CryptoParametersJ8.TYPES.values()).map(t-> t.toString()).collect(Collectors.joining(","));
-        System.out.println("\tAlgorithms (shortcut) available: " + algoShortList);
-        String algoList= Arrays.stream(CryptoParametersJ8.TYPES_IMPL.values()).map(t-> t.toString()).collect(Collectors.joining(", "));
-        System.out.println("\tAlgorithms available: " + algoList);
-        System.out.println("\tMore Info: https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html");
-    }
+			if (operationMode.equals("file")) {
+				processFiles(args);
+			} else if (operationMode.equals("string")) {
+				processString(args);
+			}
+		} catch (Exception e) {
+			System.out.println("Error : " + e.getMessage());
+			e.printStackTrace();
+		}
+	}
 
-    /**
-     * Prints usage information.
-     */
-    public static void printHelp()
-    {
-        System.out.println("\r\n\t*** Command line tool for encrypting/decrypting strings/files ***\r\n\t*** algorithm based on "+ CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_PBE+ "***\r\n");
-        System.out.println("\tjava -cp target\\classes; "+ CLI2.class.getName()+ " <operation mode> <coding mode> <password> <path|string> [target]\r\n");
-        System.out.println("\t\toperation mode: file|string|info");
-        System.out.println("\t\tcoding mode: enc|dec|enc:GCM. Default algorithm is " + TYPES.PBE);
-        System.out.println("\t\t<password: string or empty:''");
-        System.out.println("\t\tcode|coderef: path|string");
-        System.out.println("\t\ttarget: optional\r\n");
-        System.out.println( "\t*** Usage: ***\r\n");
-        System.out.println("\t\t"+ CLI2.class.getSimpleName()+ " file [enc|dec] passwd source [target]");
-        System.out.println("\t\t"+ CLI2.class.getSimpleName() + " string [enc|dec] passwd source");
-        System.out.println("\t\t"+ CLI2.class.getSimpleName() + " info");
-    }
+	private static void printInfo() {
+		CryptoUtilJ8 cryptoUtilJ8 = CryptoUtilJ8.getInstance();
+		System.out.println("");
+		System.out.println("\t|Crypto factory class: \t" + cryptoUtilJ8.getCryptoStreamFactory().getClass());
+		System.out.println("\t|_Default Algorithm used: \t" + cryptoUtilJ8.getCryptoStreamFactory().getAlgorithm());
+		List<String> algoShortList = Arrays.stream(CryptoParametersJ8.TYPES.values()).map(t -> t.toString())
+				.collect(Collectors.toList());
+		System.out.println("\t|Algorithms (shortcut) available: \t" + algoShortList);
+		String type = "AlgorithmParameters";
+		List result = CryptoParametersJ8.getSupportedAlgos(algoShortList, type, true);
+		System.out.println(
+				String.format("\t|_Matched supported %2$s:\t%1$s", 
+						((result.size() > 0) ? 
+								result:
+									CryptoParametersJ8.getSupportedAlgos(algoShortList, type, false)), type));
+	
+		List<String> algoList = Arrays.stream(CryptoParametersJ8.TYPES_IMPL.values()).map(t -> t.toString())
+				.collect(Collectors.toList());
+		System.out.println("\t|Algorithms available: \t" + algoList);
+		type = "Cipher";
+		result = CryptoParametersJ8.getSupportedAlgos(algoList, type, true);
+		System.out.println(
+				String.format("\t|_Matched Supported %2$ss:\t%1$s", 
+						((result.size() > 0) ? 
+								result:
+									CryptoParametersJ8.getSupportedAlgos(algoList, type, false)), type));
+		System.out.println("");
+		System.out.println(
+				"\t|_ More Info: https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html\r\n");
+	}
+	
 
-    /**
-     * Decrypt/encrypt a list of files
-     * @param args the command line
-     * @throws Exception the operation failed
-     */
-    public static void processFiles(String[] args)
-        throws Exception
-    {
-        String cipherMode = args[1];
-        char[] password = args[2].toCharArray();
-        File sourceFile = new File(args[3]);
-        File targetFile = null;
+	/**
+	 * Prints usage information.
+	 */
+	public static void printHelp() {
+		System.out.println(
+				"\r\n\t*** Command line tool for encrypting/decrypting strings/files ***\r\n\t*** algorithm based on "
+						+ CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_PBE + "***\r\n");
+		System.out.println("\tjava -cp target\\classes; " + CLI2.class.getName()
+				+ " <operation mode> <coding mode> <password> <path|string> [target]\r\n");
+		System.out.println(
+				"\tjava -jar target/fulcrum-yaafi-crypto-1.0.8-SNAPSHOT.jar <operation mode> <coding mode> <password> <path|string> [target]\r\n");
+		System.out.println("\t\t-------------------");
+		System.out.println("\t\toperation mode: file|string|info");
+		System.out.println("\t\tcoding mode: enc|dec|enc:GCM. Default algorithm is " + TYPES.PBE);
+		System.out.println("\t\t<password: string or empty:''");
+		System.out.println("\t\tcode|coderef: path|string");
+		System.out.println("\t\ttarget: optional\r\n");
+		System.out.println("\t\t-------------------");
+		System.out.println("\t*** Usage: ***\r\n");
+		System.out.println("\t\t" + CLI2.class.getSimpleName() + " file [enc|dec] passwd source [target]");
+		System.out.println("\t\t" + CLI2.class.getSimpleName() + " string [enc|dec] passwd source");
+		System.out.println("\t\t" + CLI2.class.getSimpleName() + " info");
+	}
 
-        if (args.length == 4)
-        {
-            targetFile = sourceFile;
-        }
-        else
-        {
-            targetFile = new File(args[4]);
-            File parentFile = targetFile.getParentFile(); 
+	/**
+	 * Decrypt/encrypt a list of files
+	 * 
+	 * @param args the command line
+	 * @throws Exception the operation failed
+	 */
+	public static void processFiles(String[] args) throws Exception {
+		String cipherMode = args[1];
+		char[] password = args[2].toCharArray();
+		File sourceFile = new File(args[3]);
+		File targetFile = null;
 
-            if (parentFile != null && (!parentFile.exists() || !parentFile.isDirectory()))
-            {
-                boolean success = parentFile.mkdirs();
-                if ( !success )
-                {
-                	System.err.println("Error, could not create directory to write parent file");
-                }            	
-            }
-        }
+		if (args.length == 4) {
+			targetFile = sourceFile;
+		} else {
+			targetFile = new File(args[4]);
+			File parentFile = targetFile.getParentFile();
 
-        processFile(cipherMode,password,sourceFile,targetFile);
-    }
+			if (parentFile != null && (!parentFile.exists() || !parentFile.isDirectory())) {
+				boolean success = parentFile.mkdirs();
+				if (!success) {
+					System.err.println("Error, could not create directory to write parent file");
+				}
+			}
+		}
 
-    /**
-     * Decrypt/encrypt a single file
-     * @param cipherMode the mode
-     * @param password the password
-     * @param sourceFile the file to process
-     * @param targetFile the target file
-     * @throws Exception the operation failed
-     */
-    public static void processFile(String cipherMode, char[] password, File sourceFile, File targetFile)
-        throws Exception
-    {
-                
-        try (FileInputStream fis = new FileInputStream(sourceFile)) 
-        {
-            ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            CryptoUtilJ8 cryptoUtilJ8 = createCryptoUtil(cipherMode);
-    
-            if( cipherMode.startsWith("dec") )
-            {
-                System.out.println("Decrypting " + sourceFile.getAbsolutePath() );
-            
-                //String value = new String(Files.readAllBytes(Paths.get(sourceFile.toURI())));
-                StringBuffer stringBuffer = new StringBuffer();
-                int i; 
-                while ((i=fis.read()) != -1)  
-                {
-                    stringBuffer.append((char) i); 
-                } 
-                
-                String value = stringBuffer.toString();
-                if (isHexadecimal(value)) 
-                {
-                    byte[] buffer = HexConverter.toBytes(value);
-                    cryptoUtilJ8.decrypt( buffer, baos, password );
-                } 
-                else 
-                {
-                    try ( FileInputStream fis2 = new FileInputStream(sourceFile) ) 
-                    {
-                        cryptoUtilJ8.decrypt( fis2, baos, password );
-                    }
-                }
-    
-                ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-                FileOutputStream fos = new FileOutputStream(targetFile);
-                StreamUtil.copy(bais,fos);
-                bais.close();
-                fos.close();
-            }
-            else if( cipherMode.startsWith("enc") )
-            {
-                System.out.println("Encrypting " + sourceFile.getAbsolutePath() );
-                cryptoUtilJ8.encrypt( fis, baos, password );
-                fis.close();
-    
-                ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-                FileOutputStream fos = new FileOutputStream(targetFile);
-                StreamUtil.copy(bais,fos);
-                bais.close();
-                fos.close();
-            }
-            else
-            {
-                String msg = "Don't know what to do with : " + cipherMode;
-                throw new IllegalArgumentException(msg);
-            }
-        }
-    }
+		processFile(cipherMode, password, sourceFile, targetFile);
+	}
 
-    private static CryptoUtilJ8 createCryptoUtil(String cipherMode) throws Exception 
-    {
-        CryptoUtilJ8 cryptoUtilJ8 = null;
-        if (cipherMode.endsWith(TYPES.PBE.toString()) || cipherMode.substring("enc".length()).equals("") ) 
-        {
-            cryptoUtilJ8 = CryptoUtilJ8.getInstance();
-        } 
-        else 
-        {
-            Optional<TYPES> algoShortcut = Arrays.stream(CryptoParametersJ8.TYPES.values()).filter(a-> cipherMode.endsWith(a.toString())).findFirst(); //.collect(Collectors.toList());
-            if (algoShortcut.isPresent()) 
-            {
-                cryptoUtilJ8 = CryptoUtilJ8.getInstance(algoShortcut.get());
-            }
-        }
-        
-        if (cryptoUtilJ8 == null) 
-        {
-            throw new Exception("Could not find any algorithms. check provided alog shortcuts with CLI2 info!");
-        }
-        
-        return cryptoUtilJ8;
-    }
+	/**
+	 * Decrypt/encrypt a single file
+	 * 
+	 * @param cipherMode the mode
+	 * @param password   the password
+	 * @param sourceFile the file to process
+	 * @param targetFile the target file
+	 * @throws Exception the operation failed
+	 */
+	public static void processFile(String cipherMode, char[] password, File sourceFile, File targetFile)
+			throws Exception {
 
-    /**
-     * Decrypt and encrypt a string.
-     * 
-     * @param args the command line
-     * @throws Exception the operation failed
-     */
-    public static void processString(String[] args)
-        throws Exception
-    {
-        final String cipherMode;
-        final char[] password;
-        final String value;
-        File targetFile = null;
-        if (args.length > 3) {
-            cipherMode = args[1];
-            password = args[2].toCharArray();
-            value = args[3];
-        } else {
-            value = null;
-            cipherMode = null;
-            password = null;
-        }
-        if (args.length == 5) 
-        {
-            targetFile = new File(args[4]);
-            File parentFile = targetFile.getParentFile(); 
+		try (FileInputStream fis = new FileInputStream(sourceFile)) {
+			ByteArrayOutputStream baos = new ByteArrayOutputStream();
+			CryptoUtilJ8 cryptoUtilJ8 = createCryptoUtil(cipherMode);
 
-            if (parentFile != null && (!parentFile.exists() || !parentFile.isDirectory()))
-            {
-                boolean success = parentFile.mkdirs();
-                if ( !success )
-                {
-                  System.err.println("Error, could not create directory to write parent file");
-                }
-                
-            }
-        }
-        
-        if (value != null && !value.equals("")) 
-        {
+			if (cipherMode.startsWith("dec")) {
+				System.out.println("Decrypting " + sourceFile.getAbsolutePath());
 
-            String result = processString(cipherMode, password, value);
-            
-            if (targetFile != null) {
-       
-              try (OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(targetFile), Charset.forName("UTF-8").newEncoder() ) )
-              {
-                osw.write(result);
-              }
-            } else {
-               System.out.println( result );
-            }
-        }
-    }
-    
-    /**
-     * Decrypt and encrypt a string.
-     * 
-     * @param cipherMode \"dec|enc\" + @link{TYPES}
-     * @param password as char array
-     * @param value String to be en/decrypted
-     * @throws Exception the operation failed
-     * 
-     * @return the result - either the encrypted or decrypted string depending on cipherMode
-     */
-    public static String processString(String cipherMode, char[] password, String value)
-        throws Exception
-    {  
-        if (value != null && !value.equals("")) 
-        {
-            CryptoUtilJ8 cryptoUtilJ8 = createCryptoUtil(cipherMode);
-    
-            String result = null;
-            if ( cipherMode.startsWith("dec") )
-            {
-                result = cryptoUtilJ8.decryptString(value,password);
-            }
-            else if ( cipherMode.startsWith("enc"))
-            {
-                result = cryptoUtilJ8.encryptString(value,password);
-            }
-            return result;
-        } else {
-          return null;
-        }
-    }
-    
-    private static final Pattern HEXADECIMAL_PATTERN = Pattern.compile("\\p{XDigit}+");
+				// String value = new String(Files.readAllBytes(Paths.get(sourceFile.toURI())));
+				StringBuffer stringBuffer = new StringBuffer();
+				int i;
+				while ((i = fis.read()) != -1) {
+					stringBuffer.append((char) i);
+				}
 
-    public static boolean isHexadecimal(String input) {
-        final Matcher matcher = HEXADECIMAL_PATTERN.matcher(input);
-        return matcher.matches();
-    }
+				String value = stringBuffer.toString();
+				if (isHexadecimal(value)) {
+					byte[] buffer = HexConverter.toBytes(value);
+					cryptoUtilJ8.decrypt(buffer, baos, password);
+				} else {
+					try (FileInputStream fis2 = new FileInputStream(sourceFile)) {
+						cryptoUtilJ8.decrypt(fis2, baos, password);
+					}
+				}
+
+				ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+				FileOutputStream fos = new FileOutputStream(targetFile);
+				StreamUtil.copy(bais, fos);
+				bais.close();
+				fos.close();
+			} else if (cipherMode.startsWith("enc")) {
+				System.out.println("Encrypting " + sourceFile.getAbsolutePath());
+				cryptoUtilJ8.encrypt(fis, baos, password);
+				fis.close();
+
+				ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+				FileOutputStream fos = new FileOutputStream(targetFile);
+				StreamUtil.copy(bais, fos);
+				bais.close();
+				fos.close();
+			} else {
+				String msg = "Don't know what to do with : " + cipherMode;
+				throw new IllegalArgumentException(msg);
+			}
+		}
+	}
+
+	private static CryptoUtilJ8 createCryptoUtil(String cipherMode) throws Exception {
+		CryptoUtilJ8 cryptoUtilJ8 = null;
+		// now extension like enc:GCM
+		if (cipherMode.endsWith(TYPES.PBE.toString()) || cipherMode.substring("enc".length()).equals("")) {
+			cryptoUtilJ8 = CryptoUtilJ8.getInstance();
+		} else {
+			List<String> supportedTypes = CryptoParametersJ8.init();
+			System.err.println("checking supported types:"+ supportedTypes);
+			List<String> matchedType = supportedTypes.stream().filter(x-> cipherMode.endsWith(x) ).collect(Collectors.toList());
+			System.err.println("matched type:"+ matchedType);
+			Optional<TYPES> algoShortcut = Arrays.stream(CryptoParametersJ8.TYPES.values())
+					.filter(a -> matchedType.get(0).equals(a.toString())).findFirst();
+			if (algoShortcut.isPresent()) {
+				System.err.println("initializing type:"+ algoShortcut);
+				cryptoUtilJ8 = CryptoUtilJ8.getInstance(algoShortcut.get());
+			}
+		}
+
+		if (cryptoUtilJ8 == null) {
+			throw new Exception("Could not find any algorithms. check provided algo shortcuts with CLI2 info!");
+		}
+		
+		if (debug) {
+			CryptoStreamFactoryJ8Template crt = ((CryptoStreamFactoryJ8Template)cryptoUtilJ8.getCryptoStreamFactory());
+			System.err.println(String.format("using crypto factory instance %s for algo %s and type %s with salt length: %s and count %s", 
+	           		crt.getClass().getSimpleName(), crt.getType(),
+	           		crt.getAlgorithm(), crt.getSalt().length, crt.getCount()));
+		}
+		return cryptoUtilJ8;
+	}
+
+	/**
+	 * Decrypt and encrypt a string.
+	 * 
+	 * @param args the command line
+	 * @throws Exception the operation failed
+	 */
+	public static void processString(String[] args) throws Exception {
+		final String cipherMode;
+		final char[] password;
+		final String value;
+		File targetFile = null;
+		if (args.length > 3) {
+			cipherMode = args[1];
+			password = args[2].toCharArray();
+			value = args[3];
+		} else {
+			value = null;
+			cipherMode = null;
+			password = null;
+		}
+		if (args.length == 5) {
+			targetFile = new File(args[4]);
+			File parentFile = targetFile.getParentFile();
+
+			if (parentFile != null && (!parentFile.exists() || !parentFile.isDirectory())) {
+				boolean success = parentFile.mkdirs();
+				if (!success) {
+					System.err.println("Error, could not create directory to write parent file");
+				}
+
+			}
+		}
+
+		if (value != null && !value.equals("")) {
+
+			String result = processString(cipherMode, password, value);
+
+			if (targetFile != null) {
+
+				try (OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(targetFile),
+						Charset.forName("UTF-8").newEncoder())) {
+					osw.write(result);
+				}
+			} else {
+				System.out.println(result);
+			}
+		}
+	}
+
+	/**
+	 * Decrypt and encrypt a string.
+	 * 
+	 * @param cipherMode \"dec|enc\" + @link{TYPES}
+	 * @param password   as char array
+	 * @param value      String to be en/decrypted
+	 * @throws Exception the operation failed
+	 * 
+	 * @return the result - either the encrypted or decrypted string depending on
+	 *         cipherMode
+	 */
+	public static String processString(String cipherMode, char[] password, String value) throws Exception {
+		if (value != null && !value.equals("")) {
+			CryptoUtilJ8 cryptoUtilJ8 = createCryptoUtil(cipherMode);
+
+			String result = null;
+			if (cipherMode.startsWith("dec")) {
+				result = cryptoUtilJ8.decryptString(value, password);
+			} else if (cipherMode.startsWith("enc")) {
+				result = cryptoUtilJ8.encryptString(value, password);
+			}
+			return result;
+		} else {
+			return null;
+		}
+	}
+
+	private static final Pattern HEXADECIMAL_PATTERN = Pattern.compile("\\p{XDigit}+");
+
+	public static boolean isHexadecimal(String input) {
+		final Matcher matcher = HEXADECIMAL_PATTERN.matcher(input);
+		return matcher.matches();
+	}
 }
\ No newline at end of file
diff --git a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoParametersJ8.java b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoParametersJ8.java
index a02eb6a..152219a 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoParametersJ8.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoParametersJ8.java
@@ -1,5 +1,13 @@
 package org.apache.fulcrum.jce.crypto.extended;
 
+import java.security.Provider;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -26,7 +34,7 @@
  */
 
 public interface CryptoParametersJ8 {
-
+	
 	/**
 	 * 
 	 * Implementing classes are either using
@@ -42,14 +50,13 @@
 	 * </ul>
 	 * 
 	 * 
-	 * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html#SunJCEProvider">The Oracle Security SunJCE Provider</a>
+	 * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html#SunJCEProvider">The Oracle Security SunJCE Provider</a>
 	 * 
 	 * Algo/mode/padding for cipher transformation:
 	 * 
-	 * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">Java 8: The Oracle Security Standard Names Cipher Algorithms</a>
+	 * Java 8: <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">The Oracle Security Standard Names Cipher Algorithms</a>
 	 * 
-	 * @see <a href="https://docs.oracle.com/en/java/javase/14/docs/specs/security/standard-names.html#security-algorithm-implementation-requirements">Java 14: Security Algorithm Implementation Requirements</a>
-	 * 
+	 * Java 14: <a href="https://docs.oracle.com/en/java/javase/14/docs/specs/security/standard-names.html#security-algorithm-implementation-requirements">Security Algorithm Implementation Requirements</a>
 	 * 
 	 */
 	public enum TYPES_IMPL {
@@ -57,7 +64,7 @@
 		// key size 256
 		ALGORITHM_J8_PBE("PBEWithHmacSHA256AndAES_256"), 
 		// key size 128
-		ALGORITHM_J8_GCM("AES/GCM/NoPadding");
+		ALGORITHM_J8_GCM("AES_128/GCM/NoPadding");
 
 		private final String algorithm;
 
@@ -73,16 +80,113 @@
 		public String getAlgorithm() {
 			return algorithm;
 		}
-	}
-
-	public enum TYPES {
-		PBE, GCM
+		
+		/**
+		 * clear code depending on algorithm AES size return <pre>J8AESAES_&lt;size&gt;;</pre>.
+		 * {@link CryptoParametersJ8#CLEAR_CODE_DEFAULT}
+		 *  
+		 * @return clear code J8AES_&lt;size&gt;; with three digit size.
+		 */
+		public String getClearCode() {
+			
+			return String.format("J8%1$s;", 
+					algorithm.subSequence(algorithm.indexOf("AES_"),algorithm.indexOf("AES_")+7));
+		}
 	}
 
 	/**
-	 * Prefix to decrypted hex hash to get a clue, what to use and what it is.
 	 * 
-	 * This should be always 10 bytes
+	 * short names, exact names @see {@link TYPES_IMPL}.
+	 *
 	 */
-	String CLEAR_CODE_J8 = "J8_AES256;";
+	public enum TYPES {
+		
+		/**
+		 *  PBE algorithm is kind of meta algorithm, uses AES, see above. 
+		 */
+		PBE, 
+		/**
+		 *  AES algorithm, but GCM is is actually the algorithm mode, but nevertheless used as a short name.
+		 */
+		GCM;
+
+		/**
+		 * Clear code should be always 10 bytes.
+		 * 
+		 * {@link CryptoParametersJ8#CLEAR_CODE_DEFAULT}
+		 * 
+		 * @return clear code
+		 * 
+		 */
+		public String getClearCode() {
+			return this.equals(TYPES.PBE)? 
+					TYPES_IMPL.ALGORITHM_J8_PBE.getClearCode():
+				TYPES_IMPL.ALGORITHM_J8_GCM.getClearCode();
+		}
+	}
+
+	/**
+	 * Prefix to decrypted hex hash to get a clue, what to use and what it is; should be always 10 bytes.
+	 */
+	public String CLEAR_CODE_DEFAULT = "J8_AES064;";
+	
+	public TYPES DEFAULT_TYPE = TYPES.PBE;
+
+	
+	/**
+	 * Checks Java provider with <b>type</b> has exact type or contains any of the strings in algoList.
+	 * <pre>Types</pre> may be Cipher, AlgorithmParameters, KeyGenerator, Alg, Mac, SecretKeyFactory.
+	 * 
+	 * @param algoList the types to be checked
+	 * @param type the type is ignored if not exact, instead uses the two types: "AlgorithmParameters", "Cipher".
+	 * @param exact if exact does a exact match 
+	 * @return the matched results as a list
+	 */
+	public static List<String> getSupportedAlgos(List<String> algoList, String type, boolean exact) {
+		List<String> result = new ArrayList<String>();
+		Provider p[] = Security.getProviders();
+		List<Provider> providerList = Arrays.asList(p);
+
+		String[] PROVIDER_TYPES = { "AlgorithmParameters", "Cipher" };
+		for (Provider provider : providerList) {
+			// System.out.println(provider);
+			result.addAll(Collections.list(provider.keys()).stream().map(t -> t.toString())
+					.filter(x->
+							(exact)? 
+							(x.startsWith(type) && algoList.contains(x.replaceAll(type + ".", ""))):
+							(x.matches("(" +String.join("|", PROVIDER_TYPES) + ").*$") && 
+									algoList.stream().anyMatch(y -> y.contains(x.replaceAll(type + ".", "")))
+							)
+					)
+					.map( x ->
+					(exact)? 
+					   x.replaceAll(type + ".", ""):
+						   x.replaceAll("(" +String.join("|", PROVIDER_TYPES) + ")" + ".", "")
+					)
+					.collect(Collectors.toList()));
+		}
+		return result;
+	}
+
+	/**
+	 * initializes supported parameters by filtering {@link TYPES} against <i>AlgorithmParameters</i> in system supported cipher suites:
+	 * first by an exact match with type <i>AlgorithmParameters</i>, then by inexact matching.
+	 * 
+	 * {@link #getSupportedAlgos(List, String, boolean)}
+	 * @return list of supported algo short codes, if nothing is found the {@link #DEFAULT_TYPE} is set.
+	 */
+	static List<String> init() {
+		List<String> result = new ArrayList<String>();
+		List<String> defaultSupportedTypes = Arrays.asList( TYPES.values() ).stream().map(x-> x.toString()).collect(Collectors.toList());
+		String providerType = "AlgorithmParameters";
+		result = getSupportedAlgos(defaultSupportedTypes, providerType, true);
+		if (result.isEmpty()) {
+			// minimal default, try it 
+			result = getSupportedAlgos(defaultSupportedTypes, providerType, false);
+			result = !result.isEmpty()? 
+					result: Arrays.asList( DEFAULT_TYPE).stream().map(x-> x.toString()).collect(Collectors.toList());
+		} 
+		return result;
+	}
+
 }
diff --git a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8Template.java b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8Template.java
index dbd5fb3..7de7f52 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8Template.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8Template.java
@@ -23,7 +23,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.security.AlgorithmParameters;
 import java.security.GeneralSecurityException;
 import java.security.Key;
 import java.security.NoSuchAlgorithmException;
@@ -50,7 +49,7 @@
 	/** the salt for the algorithm */
     protected byte[] salt;
 
-    /** the count paramter for the algorithm */
+    /** the count parameter for the algorithm, not used for GCM */
     protected int count;
 
     /** the name of the JCE provider */
@@ -59,6 +58,16 @@
     /** the algorithm to use */
     protected String algorithm;
     
+    private TYPES type;
+    
+    public TYPES getType() {
+      return type;
+    }
+    
+    public void setType(TYPES type) {
+    	this.type = type;
+    }
+    
     /**
      * The JCE provider name known to work. If the value
      * is set to null an appropriate provider will be
@@ -67,16 +76,42 @@
     protected static final String PROVIDERNAME = null;
 
     protected static final int SALT_SIZE = 16; //might increase cipher length
-    protected static final int KEY_SIZE = 256;
 
     /** the default instances */
-    protected static Map<TYPES,CryptoStreamFactoryJ8Template> instances = new ConcurrentHashMap<>();
+    protected static final Map<TYPES,CryptoStreamFactoryJ8Template> instances = new ConcurrentHashMap<>();
     
     //protected AlgorithmParameters algorithmParameters;// used only for debugging
    
     public CryptoStreamFactoryJ8Template() {
        
     }
+    
+    /**
+     * Factory method to get a default instance
+     * 
+     * creating instance of type {@link CryptoParametersJ8#DEFAULT_TYPE}.
+     * 
+     * @return an instance of the CryptoStreamFactory
+     */
+    public static CryptoStreamFactoryJ8 getInstance() 
+    {
+        synchronized (CryptoStreamFactoryJ8Template.class) {
+            if( !instances.containsKey(CryptoParametersJ8.DEFAULT_TYPE) )
+            {
+                try {
+                    instances.put(CryptoParametersJ8.DEFAULT_TYPE, 
+                            (CryptoParametersJ8.DEFAULT_TYPE.equals(TYPES.PBE))? new CryptoStreamPBEImpl():
+                                new CryptoStreamGCMImpl()
+                            );
+                } catch (GeneralSecurityException e) {
+                    e.printStackTrace();
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+    
+            return instances.get(CryptoParametersJ8.DEFAULT_TYPE);
+        }
+    }
 
     /**
      * Factory method to get a default instance
@@ -103,22 +138,33 @@
             return instances.get(type);
         }
     }
-
-
+    
     /**
-     * Constructor
-     *
-     * @param salt the salt for the PBE algorithm
-     * @param count the iteration for PBEParameterSpec
-     * @param type {@link TYPES} what type the algorithm will be
+     * Factory method to get a default instance
+     * 
+     * @param type the @see {@link TYPES} of the instance.
+     * @param salt provided salt
+     * @param count provided count, used only for {@link TYPES#PBE}.
+     * @return an instance of the CryptoStreamFactory
      */
-    public CryptoStreamFactoryJ8Template( byte[] salt, int count, TYPES type)
+    public static CryptoStreamFactoryJ8 getInstance(TYPES type, byte[] salt, int count) 
     {
-        this.salt = salt.clone();
-        this.count = count;
-        this.providerName = PROVIDERNAME;
-        this.algorithm = type.equals(TYPES.PBE)? CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_PBE.getAlgorithm():
-            CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_GCM.getAlgorithm();;
+        synchronized (CryptoStreamFactoryJ8Template.class) {
+            if( !instances.containsKey(type) )
+            {
+                try {
+                    instances.put(type, 
+                            (type.equals(TYPES.PBE))? new CryptoStreamPBEImpl(salt, count):
+                                new CryptoStreamGCMImpl(salt)
+                            );
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+    
+            return instances.get(type);
+        }
     }
 
 
@@ -146,6 +192,9 @@
         return eis;
     }
 
+    /**
+     * @see org.apache.fulcrum.jce.crypto.extended.CryptoStreamFactoryJ8#getOutputStream(InputStream, OutputStream, char[])
+     */
     public OutputStream getOutputStream(InputStream is, OutputStream os, char[] password)
             throws GeneralSecurityException, IOException {
         byte[] encrypted =  this.createCipher( is, Cipher.ENCRYPT_MODE, password.clone() );
@@ -162,16 +211,16 @@
         CryptoStreamFactoryJ8Template.instances.clear();
     }
     
-    /**
-     * Set the default instances from an external application.
-     * @param instances the new default instances map
-     * @throws Exception if instances are null
-     */
-    public static void setInstances(Map<TYPES,CryptoStreamFactoryJ8Template> instances ) throws Exception
-    {
-    	if (instances == null) throw new Exception("setting instances to null not allowed!");
-        CryptoStreamFactoryJ8Template.instances = instances;
-    }
+//    /**
+//     * Set the default instances from an external application.
+//     * @param instances the new default instances map
+//     * @throws Exception if instances are null
+//     */
+//    public static void setInstances(Map<TYPES,CryptoStreamFactoryJ8Template> instances ) throws Exception
+//    {
+//    	if (instances == null) throw new Exception("setting instances to null not allowed!");
+//        CryptoStreamFactoryJ8Template.instances = instances;
+//    }
     
     /** not used / implemented methods **/
     
@@ -239,12 +288,12 @@
      * 
      * changed to {@link SecureRandom#getInstanceStrong()} and let the system decide, what PRNG to use for salt random.
      * 
-     * salt size by default @link {@value #SALT_SIZE}.
+     * salt size is by default @link {@value #SALT_SIZE}.
      * 
      * @return the generated salt as byte array
      * @throws GeneralSecurityException if no algo could be found.
      */
-    protected byte[] generateSalt() throws GeneralSecurityException {
+    protected static byte[] generateSalt() throws GeneralSecurityException {
         SecureRandom random;
         try {
             random = SecureRandom.getInstanceStrong();
@@ -260,7 +309,7 @@
 		return salt.clone();
 	}
 
-	public void setSalt(byte[] salt) {
+	protected void setSalt(byte[] salt) {
 		this.salt = salt.clone();
 	}
 
diff --git a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8.java b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8.java
index a4bbc2e..51d1805 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8.java
@@ -32,42 +32,19 @@
 import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8.TYPES;
 
 /**
- * Helper class to provide generic functions to work with CryptoStreams.
- *
- * The code uses parts from Markus Hahn's Blowfish library found at
- * http://blowfishj.sourceforge.net/
+ * Helper class to provide typed functions to work with CryptoStreams.
  *
  * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl </a>
- * @author <a href="mailto:maakus@earthlink.net">Markus Hahn</a>
  * @author <a href="mailto:gk@apache.org">Georg Kallidis</a>
  */
 public final class CryptoUtilJ8 extends CryptoUtil {
 
-	/** the typed default instances */
-	private static Map<TYPES, CryptoUtilJ8> cryptoUtilJ8s = new ConcurrentHashMap<>();
-
-	// default see instance
-	public TYPES type;
-
-	public TYPES getType() {
-		return type;
-	}
-
-	/**
-	 * Factory method to get a default instance
-	 * 
-	 * @param type one of the enum {@link TYPES}.
-	 * @return an instance of the CryptoStreamFactory
-	 */
-	public static CryptoUtilJ8 getInstance(TYPES type) {
-		synchronized (CryptoUtilJ8.class) {
-			if (!cryptoUtilJ8s.containsKey(type)) {
-				cryptoUtilJ8s.put(type, new CryptoUtilJ8(type));
-			}
-			return cryptoUtilJ8s.get(type);
-		}
-	}
-
+	/** the typed default instances */   
+    private static final Map<TYPES, CryptoUtilJ8> instances = new ConcurrentHashMap<>();
+    
+    /** the default instances with custom settings **/
+    private static final Map<TYPES, CryptoUtilJ8> instancesWithExplicitParams = new ConcurrentHashMap<>();    
+	
 	/**
 	 * Factory method to get a default instance
 	 * 
@@ -77,26 +54,69 @@
 	 */
 	public static CryptoUtilJ8 getInstance() {
 		synchronized (CryptoUtilJ8.class) {
-			TYPES defaultType = TYPES.PBE;
-			if (cryptoUtilJ8s.isEmpty() && !cryptoUtilJ8s.containsKey(defaultType)) {
-				cryptoUtilJ8s.put(defaultType, new CryptoUtilJ8(defaultType));
+			TYPES defaultType = CryptoParametersJ8.DEFAULT_TYPE;
+			if (instances.isEmpty() && !instances.containsKey(defaultType)) {
+				instances.put(defaultType, new CryptoUtilJ8());
 			}
-			return cryptoUtilJ8s.get(defaultType);
+			return instances.get(defaultType);
 		}
 	}
-
-	private CryptoUtilJ8(TYPES type) {
-		super();
-		this.type = type;
+	
+	/**
+	 * Factory method to get a default instance
+	 * 
+	 * @param type one of the enum {@link TYPES}.
+	 * @return an instance of the CryptoStreamFactory
+	 */
+	public static CryptoUtilJ8 getInstance(TYPES type) {
+		synchronized (CryptoUtilJ8.class) {
+			if (!instances.containsKey(type)) {
+				instances.put(type, new CryptoUtilJ8(type));
+			}
+			return instances.get(type);
+		}
 	}
-
+	
+	/**
+	 * Factory method to get a default instance
+	 * 
+	 * @param type one of the enum {@link TYPES}.
+	 * @param salt the salt
+	 * @param count the iteration count
+	 * @return an instance of the CryptoStreamFactory
+	 */
+	public static CryptoUtilJ8 getInstance(TYPES type, byte[] salt, int count) {
+		synchronized (CryptoUtilJ8.class) {
+			if (!instancesWithExplicitParams.containsKey(type)) {
+				instancesWithExplicitParams.put(type, new CryptoUtilJ8(type, salt, count));
+			}
+			return instancesWithExplicitParams.get(type);
+		}
+	}
+	
 	private CryptoUtilJ8() {
-		super();
+		cryptoStreamFactory = CryptoStreamFactoryJ8Template.getInstance();
 	}
+	
+	private CryptoUtilJ8(TYPES type) {
+		cryptoStreamFactory = CryptoStreamFactoryJ8Template.getInstance(type);
+	}
+	
+    /**
+     * 
+     * @param type one of the enum {@link TYPES}.
+     * @param salt v
+     * @param count the iteration count
+     */
+    protected CryptoUtilJ8(TYPES type, byte[] salt, int count) {
+    	cryptoStreamFactory = CryptoStreamFactoryJ8Template.getInstance(type, salt, count);
+    }
 
 	/**
 	 * Copies from a source to a target object using encryption and a caller
 	 * supplied CryptoStreamFactory.
+	 * 
+	 * {@link CryptoStreamFactoryJ8Template#getOutputStream(InputStream, OutputStream, char[])} 
 	 *
 	 * @param factory  the factory to create the crypto streams
 	 * @param source   the source object
@@ -110,8 +130,7 @@
 			throws GeneralSecurityException, IOException {
 		InputStream is = StreamUtil.createInputStream(source);
 		OutputStream os = StreamUtil.createOutputStream(target);
-		OutputStream eos = ((CryptoStreamFactoryJ8) factory).getOutputStream(is, os, password);
-		// StreamUtil.copy( is, eos );
+		((CryptoStreamFactoryJ8) factory).getOutputStream(is, os, password);
 	}
 
 	/**
@@ -134,11 +153,12 @@
 		StreamUtil.copy(dis, os);
 	}
 
-	/**
-	 * 
-	 * @return the CryptoStreamFactory to be used
-	 */
-	public CryptoStreamFactory getCryptoStreamFactory() {
-		return CryptoStreamFactoryJ8Template.getInstance(type);
+	public static Map<TYPES, CryptoUtilJ8> getInstances() {
+		return instances;
 	}
+
+	public static Map<TYPES, CryptoUtilJ8> getInstancesWithExplicitParams() {
+		return instancesWithExplicitParams;
+	}
+
 }
diff --git a/src/test/log4j2.xml b/src/test/log4j2.xml
index 1846038..3533c0e 100644
--- a/src/test/log4j2.xml
+++ b/src/test/log4j2.xml
@@ -1,58 +1,55 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!--
- 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.
--->
+<!-- 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. -->
 <Configuration status="info" verbose="false">
-    <Appenders>
-      <Console name="console" target="SYSTEM_OUT">
-          <PatternLayout pattern="%d [%t] %-5p %c - %m%n"/>
-	    </Console>
-	    <File name="logfile" fileName="target/fulcrum-test.log">
-          <PatternLayout pattern="%d [%t] %-5p %c - %m%n"/>
-	    </File>
-	    <File name="avalon" fileName="target/avalon-test.log">
-          <PatternLayout pattern="%d [%t] %-5p %c - %m%n"/>
-	    </File>
-    </Appenders>
-    <Loggers>
-      <Logger name="org.apache.fulcrum.jce.crypto" level="debug" additivity="false">
-            <AppenderRef ref="console"/>
-            <AppenderRef ref="logfile"/>
-       </Logger>
-       <Logger name="org.apache.fulcrum.jce" level="debug" additivity="false">
-            <AppenderRef ref="console"/>
-            <AppenderRef ref="logfile"/>
-       </Logger>
-      <Logger name="org.apache.fulcrum" level="info" additivity="false">
-          <AppenderRef ref="console"/>
-          <AppenderRef ref="logfile"/>
-      </Logger>
-       <Logger name="org.apache.fulcrum.yaafi" level="info" additivity="false">
-          <AppenderRef ref="avalon"/>
-      </Logger>
-      <Logger name="avalon" level="warn" additivity="false">
-          <AppenderRef ref="avalon"/>
-      </Logger>
-      <Logger name="org.apache.logging.log4j" level="warn" additivity="false">
-          <AppenderRef ref="logfile"/>
-      </Logger>
-      <Root level="error">
-          <AppenderRef ref="console"/>
-      </Root>
-    </Loggers>
+  <Appenders>
+    <Console name="console" target="SYSTEM_OUT">
+      <PatternLayout pattern="%d [%t] %-5p %c - %m%n" />
+    </Console>
+    <File name="logfile" fileName="target/fulcrum-test.log">
+      <PatternLayout pattern="%d [%t] %-5p %c - %m%n" />
+    </File>
+    <File name="avalon" fileName="target/avalon-test.log">
+      <PatternLayout pattern="%d [%t] %-5p %c - %m%n" />
+    </File>
+  </Appenders>
+  <Loggers>
+    <Logger name="org.apache.fulcrum.jce.crypto" level="debug"
+      additivity="false">
+      <AppenderRef ref="console" />
+      <AppenderRef ref="logfile" />
+    </Logger>
+    <Logger name="org.apache.fulcrum.jce" level="debug"
+      additivity="false">
+      <AppenderRef ref="console" />
+      <AppenderRef ref="logfile" />
+    </Logger>
+    <Logger name="org.apache.fulcrum" level="info"
+      additivity="false">
+      <AppenderRef ref="console" />
+      <AppenderRef ref="logfile" />
+    </Logger>
+    <Logger name="org.apache.fulcrum.yaafi" level="info"
+      additivity="false">
+      <AppenderRef ref="avalon" />
+    </Logger>
+    <Logger name="avalon" level="warn" additivity="false">
+      <AppenderRef ref="avalon" />
+    </Logger>
+    <Logger name="org.apache.logging.log4j" level="warn"
+      additivity="false">
+      <AppenderRef ref="logfile" />
+    </Logger>
+    <Root level="error">
+      <AppenderRef ref="console" />
+    </Root>
+  </Loggers>
 </Configuration>
\ No newline at end of file
diff --git a/src/test/org/apache/fulcrum/jce/crypto/CryptoUtilExplicitParamsTest.java b/src/test/org/apache/fulcrum/jce/crypto/CryptoUtilExplicitParamsTest.java
new file mode 100644
index 0000000..12001c1
--- /dev/null
+++ b/src/test/org/apache/fulcrum/jce/crypto/CryptoUtilExplicitParamsTest.java
@@ -0,0 +1,447 @@
+package org.apache.fulcrum.jce.crypto;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/*
+ * 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.
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test suite for crypto functionality
+ *
+ * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
+ */
+
+public class CryptoUtilExplicitParamsTest {
+	/** the password to be used */
+	private String password;
+
+	/** the test data directory */
+	private File testDataDirectory;
+
+	/** the temp data director */
+	private File tempDataDirectory;
+	
+	private static Logger log = LogManager.getLogger(CryptoUtilExplicitParamsTest.class);
+	
+	private static byte[] SALT = Salt();
+	
+	private static int COUNT = 25;
+	
+	 public static byte[] Salt()
+	 {
+		SecureRandom random;
+		try {
+			random = SecureRandom.getInstanceStrong();
+	        byte[] salt = new byte[ 8 ];
+	        random.nextBytes(salt);
+	        return salt;
+		} catch (NoSuchAlgorithmException e) {
+			e.printStackTrace();
+		}
+		return null;
+	 }
+
+	/**
+	 * Constructor
+	 */
+	public CryptoUtilExplicitParamsTest() {
+		this.password = "mysecret";
+		this.testDataDirectory = new File("./src/test/data");
+		this.tempDataDirectory = new File("./target/temp");
+		this.tempDataDirectory.mkdirs();
+	}
+
+	/**
+	 * 
+	 * @throws Exception Generic exception
+	 */
+	@BeforeAll
+	protected static void setUp() throws Exception {
+	}
+
+	/**
+	 * @return Returns the password.
+	 */
+	protected char[] getPassword() {
+		return password.toCharArray();
+	}
+
+	/**
+	 * @return Returns the tempDataDirectory.
+	 */
+	protected File getTempDataDirectory() {
+		return tempDataDirectory;
+	}
+
+	/**
+	 * @return Returns the testDataDirectory.
+	 */
+	protected File getTestDataDirectory() {
+		return testDataDirectory;
+	}
+
+	/** Encrypt a text file 
+	 */
+	@Test
+	public void testTextEncryption()  {
+		File sourceFile = new File(this.getTestDataDirectory(), "plain.txt");
+		File targetFile = new File(this.getTempDataDirectory(), "plain.enc.txt");
+		try {
+			CryptoUtil.getInstance(SALT,COUNT).encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException e) {
+			fail(e);
+		} catch (IOException e) {
+			fail(e);
+		}
+	}
+
+	/** Decrypt a text file 
+	 */
+	@Test
+	public void testTextDecryption()  {
+		testTextEncryption();
+		File sourceFile = new File(this.getTempDataDirectory(), "plain.enc.txt");
+		File targetFile = new File(this.getTempDataDirectory(), "plain.dec.txt");
+		try {
+			CryptoUtil.getInstance(SALT,COUNT).decrypt(sourceFile, targetFile.getAbsolutePath(), this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
+
+	/** Encrypt an empty text file 
+	 */
+	@Test
+	public void testEmptyTextEncryption() {
+		File sourceFile = new File(this.getTestDataDirectory(), "empty.txt");
+		File targetFile = new File(this.getTempDataDirectory(), "empty.enc.txt");
+		try {
+			CryptoUtil.getInstance(SALT,COUNT).encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
+
+	/** Decrypt a text file
+	 */
+	@Test
+	public void testEmptyTextDecryption() {
+		testEmptyTextEncryption();
+		File sourceFile = new File(this.getTempDataDirectory(), "empty.enc.txt");
+		File targetFile = new File(this.getTempDataDirectory(), "empty.dec.txt");
+		try {
+			CryptoUtil.getInstance(SALT,COUNT).decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
+
+	/** Encrypt a PDF file 
+	 */
+	@Test
+	public void testPdfEncryption()  {
+		File sourceFile = new File(this.getTestDataDirectory(), "plain.pdf");
+		File targetFile = new File(this.getTempDataDirectory(), "plain.enc.pdf");
+		try {
+			CryptoUtil.getInstance(SALT,COUNT).encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
+
+	/** Decrypt a PDF file 
+	 */
+	@Test
+	public void testPdfDecryption() {
+		testPdfEncryption();
+		File sourceFile = new File(this.getTempDataDirectory(), "plain.enc.pdf");
+		File targetFile = new File(this.getTempDataDirectory(), "plain.dec.pdf");
+		try {
+			CryptoUtil.getInstance(SALT,COUNT).decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
+
+	/** Encrypt a ZIP file 
+	 */
+	@Test
+	public void testZipEncryption()  {
+		File sourceFile = new File(this.getTestDataDirectory(), "plain.zip");
+		File targetFile = new File(this.getTempDataDirectory(), "plain.enc.zip");
+		try {
+			CryptoUtil.getInstance(SALT,COUNT).encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
+
+	/** Decrypt a ZIP file 
+	 */
+	@Test
+	public void testZipDecryption()  {
+		testZipEncryption();
+		File sourceFile = new File(this.getTempDataDirectory(), "plain.enc.zip");
+		File targetFile = new File(this.getTempDataDirectory(), "plain.dec.zip");
+		try {
+			CryptoUtil.getInstance(SALT,COUNT).decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
+
+	/** Encrypt a UTF-16 XML file 
+	 */
+	@Test
+	public void testXmlUTF16Encryption()  {
+		File sourceFile = new File(this.getTestDataDirectory(), "plain-utf16.xml");
+		File targetFile = new File(this.getTempDataDirectory(), "plain-utf16.enc.xml");
+		try {
+			CryptoUtil.getInstance(SALT,COUNT).encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
+
+	/**
+	 * Decrypt a UTF-16 XML file
+	 */
+	 @Test
+	public void testXMLUTF16Decryption() {
+		testXmlUTF16Encryption();
+		File sourceFile = new File(this.getTempDataDirectory(), "plain-utf16.enc.xml");
+		File targetFile = new File(this.getTempDataDirectory(), "plain-utf16.dec.xml");
+		try {
+			CryptoUtil.getInstance(SALT,COUNT).decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
+
+	/**
+	 * Encrypt a UTF-8 XML file
+	 */
+	 @Test
+	public void testXmlUTF8Encryption() {
+		File sourceFile = new File(this.getTestDataDirectory(), "plain-utf8.xml");
+		File targetFile = new File(this.getTempDataDirectory(), "plain-utf8.enc.xml");
+		try {
+			CryptoUtil.getInstance(SALT,COUNT).encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
+
+	/**
+	 * Decrypt a UTF-8 XML file
+	 */
+	 @Test
+	public void testXMLUTF8Decryption() {
+		testXmlUTF8Encryption();
+		File sourceFile = new File(this.getTempDataDirectory(), "plain-utf8.enc.xml");
+		File targetFile = new File(this.getTempDataDirectory(), "plain-utf8.dec.xml");
+		try {
+			CryptoUtil.getInstance(SALT,COUNT).decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
+
+	/**
+	 * Encrypt a ISO-8859-1 XML file
+	 */
+	@Test
+	public void testXmlISO88591Encryption()  {
+		File sourceFile = new File(this.getTestDataDirectory(), "plain-iso-8859-1.xml");
+		File targetFile = new File(this.getTempDataDirectory(), "plain-iso-8859-1.enc.xml");
+		try {
+			CryptoUtil.getInstance(SALT,COUNT).encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
+
+	/**
+	 * Decrypt a ISO-8859-1 XML file
+	 */
+	@Test
+	public void testXmlISO88591Decryption()  {
+		testXmlISO88591Encryption();
+		File sourceFile = new File(this.getTempDataDirectory(), "plain-iso-8859-1.enc.xml");
+		File targetFile = new File(this.getTempDataDirectory(), "plain-iso-8859-1.dec.xml");
+		try {
+			CryptoUtil.getInstance(SALT,COUNT).decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
+
+	/** Test encryption and decryption of Strings
+	 */
+	@Test
+	public void testStringEncryption()  {
+		char[] testVector = new char[513];
+
+		for (int i = 0; i < testVector.length; i++) {
+			testVector[i] = (char) i;
+		}
+
+		String source = new String(testVector);
+		try {
+			String cipherText = CryptoUtil.getInstance(SALT,COUNT).encryptString(source, this.getPassword());
+			String plainText = CryptoUtil.getInstance(SALT,COUNT).decryptString(cipherText, this.getPassword());
+			assertEquals(source, plainText);
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+		
+	}
+	
+	@Test
+	public void testStringEncryptionWithType() {
+		CryptoUtil cu = CryptoUtil.getInstance(SALT,COUNT);
+		char[] testVector = new char[513];
+
+		for (int i = 0; i < testVector.length; i++) {
+			testVector[i] = (char) i;
+		}
+
+		String source = new String(testVector);
+		String cipherText = null;
+		String plainText = null;
+		try {
+			log.info("Test without clearTextHeader");
+			cipherText = cu.encryptString(source, this.getPassword());
+			log.trace(cipherText);
+			plainText = cu.decryptString(cipherText, this.getPassword());
+			assertEquals(source, plainText, source + " is not equal with " + plainText);
+
+			log.info(String.format("Test with clearTextHeader %s in encrypted string.",
+					CryptoParametersJ8.CLEAR_CODE_DEFAULT));
+			String cipherText2 = cu.encryptStringWithClearCode(source, this.getPassword());
+			log.trace(cipherText2);
+			// old style
+			assertTrue(cipherText2.startsWith(CryptoParametersJ8.CLEAR_CODE_DEFAULT),
+					String.format("%s does not start with '%s'", cipherText2, CryptoParametersJ8.CLEAR_CODE_DEFAULT));
+			String plainText2 = cu.decryptStringWithClearCode(cipherText2, this.getPassword());
+			assertEquals(source, plainText2, String.format("%s is not equal with %s", source, plainText));
+
+		} catch (GeneralSecurityException | IOException e) {
+			e.printStackTrace();
+			fail();
+		}
+	}
+
+	/** Test encryption and decryption of Strings
+	 */
+	@Test
+	public void testStringHandling() {
+		String source = "Nobody knows the toubles I have seen ...";
+		try {
+			String cipherText = CryptoUtil.getInstance(SALT,COUNT).encryptString(source, this.getPassword());
+			String plainText = CryptoUtil.getInstance(SALT,COUNT).decryptString(cipherText, this.getPassword());
+		assertEquals(source, plainText);
+		} catch (GeneralSecurityException | IOException e) {
+			e.printStackTrace();
+			fail();
+		}
+	}
+
+	/** Test encryption and decryption of binary data
+	 * @throws Exception Generic exception
+	 */
+	 @Test
+	public void testBinaryHandling() throws Exception {
+		byte[] source = new byte[256];
+		byte[] result = null;
+
+		for (int i = 0; i < source.length; i++) {
+			source[i] = (byte) i;
+		}
+
+		ByteArrayOutputStream cipherText = new ByteArrayOutputStream();
+		ByteArrayOutputStream plainText = new ByteArrayOutputStream();
+
+		CryptoUtil.getInstance(SALT,COUNT).encrypt(source, cipherText, this.getPassword());
+		CryptoUtil.getInstance(SALT,COUNT).decrypt(cipherText, plainText, this.getPassword());
+
+		result = plainText.toByteArray();
+
+		for (int i = 0; i < source.length; i++) {
+			if (source[i] != result[i]) {
+				fail("Binary data are different at position " + i);
+			}
+		}
+	}
+
+	/** Test creating a password
+	 * @throws Exception Generic exception
+	 */
+	@Test
+	public void testPasswordFactory() throws Exception {
+		char[] result = null;
+		result = PasswordFactory.getInstance().create();
+		System.out.println(new String(result));
+		result = PasswordFactory.getInstance().create(this.getPassword());
+		log.info(new String(result));
+		assertNotNull(result);
+	}
+
+	/** Test the hex converter
+	 * @throws Exception Generic exception
+	 */
+	 @Test
+	public void testHexConverter() throws Exception {
+		String source = "DceuATAABWSaVTSIK";
+		String hexString = HexConverter.toString(source.getBytes());
+		String result = new String(HexConverter.toBytes(hexString));
+		assertEquals(source, result);
+	}
+
+	/** Test encryption and decryption of Strings 
+	 * @throws Exception Generic exception
+	 */
+	 @Test
+	public void testPasswordEncryption() throws Exception {
+		char[] password = "57cb-4a23-d838-45222".toCharArray();
+		String source = "e02c-3b76-ff1e-5d9a1";
+		String cipherText = CryptoUtil.getInstance(SALT,COUNT).encryptString(source, password);
+		log.info(cipherText);// len 48
+		assertEquals(48, cipherText.length());
+		String plainText = CryptoUtil.getInstance(SALT,COUNT).decryptString(cipherText, password);
+		assertEquals(source, plainText);
+	}
+
+}
diff --git a/src/test/org/apache/fulcrum/jce/crypto/CryptoUtilTest.java b/src/test/org/apache/fulcrum/jce/crypto/CryptoUtilTest.java
index caf0283..8b10615 100644
--- a/src/test/org/apache/fulcrum/jce/crypto/CryptoUtilTest.java
+++ b/src/test/org/apache/fulcrum/jce/crypto/CryptoUtilTest.java
@@ -1,5 +1,10 @@
 package org.apache.fulcrum.jce.crypto;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -21,12 +26,14 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
 
-import org.apache.fulcrum.jce.crypto.extended.CryptoUtilJ8ParameterizedTest;
+import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-
-import junit.framework.TestCase;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
 
 /**
  * Test suite for crypto functionality
@@ -34,7 +41,7 @@
  * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
  */
 
-public class CryptoUtilTest extends TestCase {
+public class CryptoUtilTest {
 	/** the password to be used */
 	private String password;
 
@@ -48,12 +55,8 @@
 
 	/**
 	 * Constructor
-	 * 
-	 * @param name the name of the test case
 	 */
-	public CryptoUtilTest(String name) {
-		super(name);
-
+	public CryptoUtilTest() {
 		this.password = "mysecret";
 		this.testDataDirectory = new File("./src/test/data");
 		this.tempDataDirectory = new File("./target/temp");
@@ -61,15 +64,16 @@
 	}
 
 	/**
-	 * @see junit.framework.TestCase#setUp() byte[] salt, int count, String
-	 *      algorithm, String providerName )
 	 * 
 	 * @throws Exception Generic exception
 	 */
-	protected void setUp() throws Exception {
+	@BeforeAll
+	protected static void setUp() throws Exception {
 	    CryptoStreamFactoryImpl factory = new CryptoStreamFactoryImpl(CryptoParameters.Salt(), CryptoParameters.COUNT);
 
 	    CryptoStreamFactoryImpl.setInstance(factory);
+	    
+	    
 	}
 
 	/**
@@ -94,159 +98,205 @@
 	}
 
 	/** Encrypt a text file 
-	 * @throws Exception Generic exception
 	 */
-	public void testTextEncryption() throws Exception {
+	@Test
+	public void testTextEncryption()  {
 		File sourceFile = new File(this.getTestDataDirectory(), "plain.txt");
 		File targetFile = new File(this.getTempDataDirectory(), "plain.enc.txt");
-		CryptoUtil.getInstance().encrypt(sourceFile, targetFile, this.getPassword());
+		try {
+			CryptoUtil.getInstance().encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException e) {
+			fail(e);
+		} catch (IOException e) {
+			fail(e);
+		}
 	}
 
 	/** Decrypt a text file 
-	 * @throws Exception Generic exception
 	 */
-	public void testTextDecryption() throws Exception {
+	@Test
+	public void testTextDecryption()  {
 		testTextEncryption();
 		File sourceFile = new File(this.getTempDataDirectory(), "plain.enc.txt");
 		File targetFile = new File(this.getTempDataDirectory(), "plain.dec.txt");
-		CryptoUtil.getInstance().decrypt(sourceFile, targetFile.getAbsolutePath(), this.getPassword());
+		try {
+			CryptoUtil.getInstance().decrypt(sourceFile, targetFile.getAbsolutePath(), this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
 	}
 
 	/** Encrypt an empty text file 
-	 * 
-	 * @throws Exception Generic exception
 	 */
-	public void testEmptyTextEncryption() throws Exception {
+	@Test
+	public void testEmptyTextEncryption() {
 		File sourceFile = new File(this.getTestDataDirectory(), "empty.txt");
 		File targetFile = new File(this.getTempDataDirectory(), "empty.enc.txt");
-		CryptoUtil.getInstance().encrypt(sourceFile, targetFile, this.getPassword());
+		try {
+			CryptoUtil.getInstance().encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
 	}
 
 	/** Decrypt a text file
-	 * @throws Exception Generic exception
 	 */
-	public void testEmptyTextDecryption() throws Exception {
+	@Test
+	public void testEmptyTextDecryption() {
 		testEmptyTextEncryption();
 		File sourceFile = new File(this.getTempDataDirectory(), "empty.enc.txt");
 		File targetFile = new File(this.getTempDataDirectory(), "empty.dec.txt");
-		CryptoUtil.getInstance().decrypt(sourceFile, targetFile, this.getPassword());
+		try {
+			CryptoUtil.getInstance().decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
 	}
 
 	/** Encrypt a PDF file 
-	 * 
-	 * @throws Exception Generic exception
 	 */
-	public void testPdfEncryption() throws Exception {
+	@Test
+	public void testPdfEncryption()  {
 		File sourceFile = new File(this.getTestDataDirectory(), "plain.pdf");
 		File targetFile = new File(this.getTempDataDirectory(), "plain.enc.pdf");
-		CryptoUtil.getInstance().encrypt(sourceFile, targetFile, this.getPassword());
+		try {
+			CryptoUtil.getInstance().encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
 	}
 
 	/** Decrypt a PDF file 
-	 * 
-	 * @throws Exception Generic exception
 	 */
-	public void testPdfDecryption() throws Exception {
+	@Test
+	public void testPdfDecryption() {
 		testPdfEncryption();
 		File sourceFile = new File(this.getTempDataDirectory(), "plain.enc.pdf");
 		File targetFile = new File(this.getTempDataDirectory(), "plain.dec.pdf");
-		CryptoUtil.getInstance().decrypt(sourceFile, targetFile, this.getPassword());
+		try {
+			CryptoUtil.getInstance().decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
 	}
 
 	/** Encrypt a ZIP file 
-	 * 
-	 * @throws Exception Generic exception
 	 */
-	public void testZipEncryption() throws Exception {
+	@Test
+	public void testZipEncryption()  {
 		File sourceFile = new File(this.getTestDataDirectory(), "plain.zip");
 		File targetFile = new File(this.getTempDataDirectory(), "plain.enc.zip");
-		CryptoUtil.getInstance().encrypt(sourceFile, targetFile, this.getPassword());
+		try {
+			CryptoUtil.getInstance().encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
 	}
 
 	/** Decrypt a ZIP file 
-	 * 
-	 * @throws Exception Generic exception
 	 */
-	public void testZipDecryption() throws Exception {
+	@Test
+	public void testZipDecryption()  {
 		testZipEncryption();
 		File sourceFile = new File(this.getTempDataDirectory(), "plain.enc.zip");
 		File targetFile = new File(this.getTempDataDirectory(), "plain.dec.zip");
-		CryptoUtil.getInstance().decrypt(sourceFile, targetFile, this.getPassword());
+		try {
+			CryptoUtil.getInstance().decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
 	}
 
 	/** Encrypt a UTF-16 XML file 
-	 * 
-	 * @throws Exception Generic exception
 	 */
-	public void testXmlUTF16Encryption() throws Exception {
+	@Test
+	public void testXmlUTF16Encryption()  {
 		File sourceFile = new File(this.getTestDataDirectory(), "plain-utf16.xml");
 		File targetFile = new File(this.getTempDataDirectory(), "plain-utf16.enc.xml");
-		CryptoUtil.getInstance().encrypt(sourceFile, targetFile, this.getPassword());
+		try {
+			CryptoUtil.getInstance().encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
 	}
 
 	/**
 	 * Decrypt a UTF-16 XML file
-	 * 
-	 * @throws Exception Generic exception
 	 */
-	public void testXMLUTF16Decryption() throws Exception {
+	 @Test
+	public void testXMLUTF16Decryption() {
 		testXmlUTF16Encryption();
 		File sourceFile = new File(this.getTempDataDirectory(), "plain-utf16.enc.xml");
 		File targetFile = new File(this.getTempDataDirectory(), "plain-utf16.dec.xml");
-		CryptoUtil.getInstance().decrypt(sourceFile, targetFile, this.getPassword());
+		try {
+			CryptoUtil.getInstance().decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
 	}
 
 	/**
 	 * Encrypt a UTF-8 XML file
-	 * 
-	 * @throws Exception Generic exception
 	 */
-	public void testXmlUTF8Encryption() throws Exception {
+	 @Test
+	public void testXmlUTF8Encryption() {
 		File sourceFile = new File(this.getTestDataDirectory(), "plain-utf8.xml");
 		File targetFile = new File(this.getTempDataDirectory(), "plain-utf8.enc.xml");
-		CryptoUtil.getInstance().encrypt(sourceFile, targetFile, this.getPassword());
+		try {
+			CryptoUtil.getInstance().encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
 	}
 
 	/**
 	 * Decrypt a UTF-8 XML file
-	 * 
-	 * @throws Exception Generic exception
 	 */
-	public void testXMLUTF8Decryption() throws Exception {
+	 @Test
+	public void testXMLUTF8Decryption() {
 		testXmlUTF8Encryption();
 		File sourceFile = new File(this.getTempDataDirectory(), "plain-utf8.enc.xml");
 		File targetFile = new File(this.getTempDataDirectory(), "plain-utf8.dec.xml");
-		CryptoUtil.getInstance().decrypt(sourceFile, targetFile, this.getPassword());
+		try {
+			CryptoUtil.getInstance().decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
 	}
 
 	/**
 	 * Encrypt a ISO-8859-1 XML file
-	 * 
-	 * @throws Exception Generic exception
 	 */
-	public void testXmlISO88591Encryption() throws Exception {
+	@Test
+	public void testXmlISO88591Encryption()  {
 		File sourceFile = new File(this.getTestDataDirectory(), "plain-iso-8859-1.xml");
 		File targetFile = new File(this.getTempDataDirectory(), "plain-iso-8859-1.enc.xml");
-		CryptoUtil.getInstance().encrypt(sourceFile, targetFile, this.getPassword());
+		try {
+			CryptoUtil.getInstance().encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
 	}
 
 	/**
 	 * Decrypt a ISO-8859-1 XML file
-	 * 
-	 * @throws Exception Generic exception
 	 */
-	public void testXmlISO88591Decryption() throws Exception {
+	@Test
+	public void testXmlISO88591Decryption()  {
 		testXmlISO88591Encryption();
 		File sourceFile = new File(this.getTempDataDirectory(), "plain-iso-8859-1.enc.xml");
 		File targetFile = new File(this.getTempDataDirectory(), "plain-iso-8859-1.dec.xml");
-		CryptoUtil.getInstance().decrypt(sourceFile, targetFile, this.getPassword());
+		try {
+			CryptoUtil.getInstance().decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
 	}
 
 	/** Test encryption and decryption of Strings
-	 * 
-	 *  @throws Exception Generic exception
 	 */
-	public void testStringEncryption() throws Exception {
+	@Test
+	public void testStringEncryption()  {
 		char[] testVector = new char[513];
 
 		for (int i = 0; i < testVector.length; i++) {
@@ -254,24 +304,70 @@
 		}
 
 		String source = new String(testVector);
-		String cipherText = CryptoUtil.getInstance().encryptString(source, this.getPassword());
-		String plainText = CryptoUtil.getInstance().decryptString(cipherText, this.getPassword());
-		assertEquals(source, plainText);
+		try {
+			String cipherText = CryptoUtil.getInstance().encryptString(source, this.getPassword());
+			String plainText = CryptoUtil.getInstance().decryptString(cipherText, this.getPassword());
+			assertEquals(source, plainText);
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+		
+	}
+	
+	@Test
+	public void testStringEncryptionWithType() {
+		CryptoUtil cu = CryptoUtil.getInstance();
+		char[] testVector = new char[513];
+
+		for (int i = 0; i < testVector.length; i++) {
+			testVector[i] = (char) i;
+		}
+
+		String source = new String(testVector);
+		String cipherText = null;
+		String plainText = null;
+		try {
+			log.info("Test without clearTextHeader");
+			cipherText = cu.encryptString(source, this.getPassword());
+			log.trace(cipherText);
+			plainText = cu.decryptString(cipherText, this.getPassword());
+			assertEquals(source, plainText, source + " is not equal with " + plainText);
+
+			log.info(String.format("Test with clearTextHeader %s in encrypted string.",
+					CryptoParametersJ8.CLEAR_CODE_DEFAULT));
+			String cipherText2 = cu.encryptStringWithClearCode(source, this.getPassword());
+			log.trace(cipherText2);
+			// old style
+			assertTrue(cipherText2.startsWith(CryptoParametersJ8.CLEAR_CODE_DEFAULT),
+					String.format("%s does not start with '%s'", cipherText2, CryptoParametersJ8.CLEAR_CODE_DEFAULT));
+			String plainText2 = cu.decryptStringWithClearCode(cipherText2, this.getPassword());
+			assertEquals(source, plainText2, String.format("%s is not equal with %s", source, plainText));
+
+		} catch (GeneralSecurityException | IOException e) {
+			e.printStackTrace();
+			fail();
+		}
 	}
 
 	/** Test encryption and decryption of Strings
-	 * @throws Exception Generic exception
 	 */
-	public void testStringHandling() throws Exception {
+	@Test
+	public void testStringHandling() {
 		String source = "Nobody knows the toubles I have seen ...";
-		String cipherText = CryptoUtil.getInstance().encryptString(source, this.getPassword());
-		String plainText = CryptoUtil.getInstance().decryptString(cipherText, this.getPassword());
+		try {
+			String cipherText = CryptoUtil.getInstance().encryptString(source, this.getPassword());
+			String plainText = CryptoUtil.getInstance().decryptString(cipherText, this.getPassword());
 		assertEquals(source, plainText);
+		} catch (GeneralSecurityException | IOException e) {
+			e.printStackTrace();
+			fail();
+		}
 	}
 
 	/** Test encryption and decryption of binary data
 	 * @throws Exception Generic exception
 	 */
+	 @Test
 	public void testBinaryHandling() throws Exception {
 		byte[] source = new byte[256];
 		byte[] result = null;
@@ -298,6 +394,7 @@
 	/** Test creating a password
 	 * @throws Exception Generic exception
 	 */
+	@Test
 	public void testPasswordFactory() throws Exception {
 		char[] result = null;
 		result = PasswordFactory.getInstance().create();
@@ -305,12 +402,12 @@
 		result = PasswordFactory.getInstance().create(this.getPassword());
 		log.info(new String(result));
 		assertNotNull(result);
-		return;
 	}
 
 	/** Test the hex converter
 	 * @throws Exception Generic exception
 	 */
+	 @Test
 	public void testHexConverter() throws Exception {
 		String source = "DceuATAABWSaVTSIK";
 		String hexString = HexConverter.toString(source.getBytes());
@@ -321,6 +418,7 @@
 	/** Test encryption and decryption of Strings 
 	 * @throws Exception Generic exception
 	 */
+	 @Test
 	public void testPasswordEncryption() throws Exception {
 		char[] password = "57cb-4a23-d838-45222".toCharArray();
 		String source = "e02c-3b76-ff1e-5d9a1";
diff --git a/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8ExplicitParamsTest.java b/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8ExplicitParamsTest.java
new file mode 100644
index 0000000..6a0b84a
--- /dev/null
+++ b/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8ExplicitParamsTest.java
@@ -0,0 +1,371 @@
+package org.apache.fulcrum.jce.crypto.extended;

+

+

+import static org.junit.jupiter.api.Assertions.assertEquals;

+import static org.junit.jupiter.api.Assertions.assertNotNull;

+import static org.junit.jupiter.api.Assertions.fail;

+

+import java.io.ByteArrayOutputStream;

+import java.io.File;

+import java.io.IOException;

+import java.nio.file.Files;

+import java.nio.file.Paths;

+import java.security.GeneralSecurityException;

+import java.security.NoSuchAlgorithmException;

+import java.security.SecureRandom;

+import java.util.ArrayList;

+import java.util.List;

+

+import org.apache.fulcrum.jce.crypto.PasswordFactory;

+import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8.TYPES;

+import org.apache.fulcrum.jce.junit5.extension.SupportedTypeArguments;

+import org.apache.logging.log4j.LogManager;

+import org.apache.logging.log4j.Logger;

+import org.junit.jupiter.api.AfterAll;

+import org.junit.jupiter.api.BeforeAll;

+import org.junit.jupiter.api.Test;

+

+/*

+ * 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.

+ */

+

+

+/**

+ * Test suite for crypto functionality

+ *

+ * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>

+ */

+public class CryptoUtilJ8ExplicitParamsTest {

+    /** the password to be used */

+    private String password;

+

+    /** the test data directory */

+    private File testDataDirectory;

+

+    /** the temp data director */

+    private File tempDataDirectory;

+    

+	

+	private static byte[] SALT = generateSalt();

+	

+	private static int COUNT = 12345;

+    

+    private static List<CryptoUtilJ8> cryptoUtilJ8s = new ArrayList<>();

+

+    private static Logger log = LogManager.getLogger(CryptoUtilJ8ExplicitParamsTest.class);

+    

+    

+    protected static byte[] generateSalt() {

+        SecureRandom random;

+        try {

+            random = SecureRandom.getInstanceStrong();

+            byte[] salt = new byte[ 16 ];

+            random.nextBytes(salt);

+            return salt;

+        } catch (NoSuchAlgorithmException e) {

+            e.printStackTrace();

+        }

+        return null;

+    }

+

+    /**

+     * Constructor

+     */

+    public CryptoUtilJ8ExplicitParamsTest() {

+

+        this.password = "mysecret";

+        this.testDataDirectory = new File("./src/test/data");

+        this.tempDataDirectory = new File("./target/temp");

+        this.tempDataDirectory.mkdirs();

+    }

+

+

+    @BeforeAll

+    public static void setUp() throws Exception {

+        cryptoUtilJ8s.clear();

+        SupportedTypeArguments.init();

+        for (TYPES type : CryptoParametersJ8.TYPES.values()) {

+            if (SupportedTypeArguments.SUPPORTED_TYPES.contains(type.toString())) {

+            	cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type, SALT, COUNT));

+            }

+        }

+        for (CryptoUtilJ8 cryptoUtilJ8 : cryptoUtilJ8s) {

+            log.debug("registered {}", cryptoUtilJ8.getClass().getSimpleName() );

+            CryptoStreamFactoryJ8Template crt = ((CryptoStreamFactoryJ8Template)cryptoUtilJ8.getCryptoStreamFactory());

+            log.debug(String.format("created default crypto factory instance %s for algo %s with salt length: %s", 

+               		crt.getClass().getSimpleName(),

+               		crt.getAlgorithm(), crt.getSalt().length));

+        }

+    }

+    

+    @AfterAll

+    public static void destroy() {

+        cryptoUtilJ8s.clear();

+    }

+    

+

+    /**

+     * @return Returns the password.

+     */

+    protected char[] getPassword() {

+        return password.toCharArray();

+    }

+

+    /**

+     * @return Returns the tempDataDirectory.

+     */

+    protected File getTempDataDirectory() {

+        return tempDataDirectory;

+    }

+

+    /**

+     * @return Returns the testDataDirectory.

+     */

+    protected File getTestDataDirectory() {

+        return testDataDirectory;

+    }

+    

+    /** Encrypt a text file 

+     * 

+     */

+    @Test

+    public void testTextEncryption()  {

+        

+        File sourceFile = new File(this.getTestDataDirectory(), "plain.txt");

+        File targetFile = new File(this.getTempDataDirectory(), "plain.j8.enc.txt");

+        

+        cryptoUtilJ8s.forEach(cuj8 -> {

+            try {

+                cuj8.encrypt(sourceFile, targetFile, this.getPassword());

+            } catch (GeneralSecurityException e) {

+                e.printStackTrace();

+                fail();

+            } catch (IOException e) {

+                e.printStackTrace();

+                fail();

+            }

+        } );

+    }

+

+    /** Decrypt a text file 

+     */

+    @Test

+    public void testTextDecryption() {           

+    	cryptoUtilJ8s.forEach(cuj8 -> { 

+            log.info("start en-/decrypting with {}",cuj8);    

+    		try {

+                    File sourceFile = new File(this.getTestDataDirectory(), "plain.txt");

+                    File targetFile = new File(this.getTempDataDirectory(), "plain.j8.enc.txt");

+                    cuj8.encrypt(sourceFile, targetFile, this.getPassword());

+                    

+                    File sourceFile2 = new File(this.getTempDataDirectory(), "plain.j8.enc.txt");;

+                    File targetFile2 = new File(this.getTempDataDirectory(), "plain.j8.dec.txt");

+                    cuj8.decrypt(sourceFile2, targetFile2.getAbsolutePath(), this.getPassword());

+                    assertEquals(

+                            new String(Files.readAllBytes( Paths.get(sourceFile.toURI())) ), 

+                            new String(Files.readAllBytes( Paths.get(targetFile2.toURI())) )

+                            );

+                } catch (GeneralSecurityException | IOException e) {

+                    e.printStackTrace();

+                    fail();

+                }

+            });

+    }

+    

+    /** Encrypt a PDF file 

+     * 

+     */

+    @Test

+    public void testPdfEncryption() {

+        File sourceFile = new File(this.getTestDataDirectory(), "plain.pdf");

+        File targetFile = new File(this.getTempDataDirectory(), "plain.j8.enc.pdf");

+        cryptoUtilJ8s.forEach(cuj8 -> { 

+            try {

+                cuj8.encrypt(sourceFile, targetFile, this.getPassword());

+            } catch (GeneralSecurityException | IOException e) {

+                e.printStackTrace();

+                fail();

+            }    

+        });        

+    }

+

+    /** Decrypt a PDF file 

+     * 

+     */

+    @Test

+    public void testPdfDecryption()  {

+        //testPdfEncryption();

+        cryptoUtilJ8s.forEach(cuj8 -> { 

+            try {

+                File sourceFile = new File(this.getTestDataDirectory(), "plain.pdf");

+                File targetFile = new File(this.getTempDataDirectory(), "plain.j8.enc.pdf");

+                cuj8.encrypt(sourceFile, targetFile, this.getPassword());

+                

+                File sourceFile2 = new File(this.getTempDataDirectory(), "plain.j8.enc.pdf");

+                File targetFile2 = new File(this.getTempDataDirectory(), "plain.j8.dec.pdf");

+                cuj8.decrypt(sourceFile2, targetFile2, this.getPassword());

+                

+                assertEquals(

+                        new String(Files.readAllBytes( Paths.get(sourceFile.toURI())) ), 

+                        new String(Files.readAllBytes( Paths.get(targetFile2.toURI())) )

+                        );

+            } catch (GeneralSecurityException | IOException e) {

+                e.printStackTrace();

+                fail();

+            }    

+        }); 

+

+    }

+

+    /** Test encryption and decryption of Strings

+     * 

+     */

+    @Test

+    public void testStringEncryption() {

+        char[] testVector = new char[513];

+

+        for (int i = 0; i < testVector.length; i++) {

+            testVector[i] = (char) i;

+        }

+

+        String source = new String(testVector);

+        cryptoUtilJ8s.forEach(cuj8 -> { 

+            String cipherText;

+            String plainText;

+            try {

+                cipherText = cuj8.encryptString(source, this.getPassword());

+                plainText = cuj8.decryptString(cipherText, this.getPassword());

+                assertEquals(source, plainText, source +" is not equal with " + plainText); 

+            } catch (GeneralSecurityException | IOException e) {

+                e.printStackTrace();

+                fail();

+            }

+           

+        });

+        

+

+    }

+

+    /** Test encryption and decryption of Strings

+     */

+    @Test

+    public void testStringHandling()  {

+        String source = "Nobody knows the toubles I have seen ...";

+        cryptoUtilJ8s.forEach(cuj8 -> { 

+            String cipherText;

+            try {

+                cipherText = cuj8.encryptString(source, this.getPassword());

+                String plainText = cuj8.decryptString(cipherText, this.getPassword());

+                assertEquals(source, plainText);   

+            } catch (GeneralSecurityException | IOException e) {

+                e.printStackTrace();

+                fail();

+            }

+         

+        });

+

+    }

+

+    /** 

+     * Test creating a password

+     * @throws Exception Generic exception

+     */

+    @Test

+    public void testPasswordFactory() throws Exception {

+        char[] result = null;

+        result = PasswordFactory.getInstance("SHA-256").create();

+        log.debug("random pw: {}", new String(result));

+        result = PasswordFactory.getInstance("SHA-256",10_000).create(this.getPassword());

+        log.debug("password pw with seed: {}", new String(result));

+        assertNotNull(result);

+        return;

+    }

+    

+    /** Test encryption and decryption of binary data

+     * @throws Exception Generic exception

+     */

+    @Test

+    public void testBinaryHandling() throws Exception {

+        

+        cryptoUtilJ8s.forEach(cuj8 -> { 

+            byte[] source = new byte[256];

+            byte[] result = null;

+

+            for (int i = 0; i < source.length; i++) {

+                source[i] = (byte) i;

+            }

+

+            ByteArrayOutputStream cipherText = new ByteArrayOutputStream();

+            ByteArrayOutputStream plainText = new ByteArrayOutputStream();

+            try {

+                cuj8.encrypt(source, cipherText, this.getPassword());

+                cuj8.decrypt(cipherText, plainText, this.getPassword());

+            } catch (GeneralSecurityException | IOException e) {

+                e.printStackTrace();

+                fail();

+            }

+            result = plainText.toByteArray();

+

+            for (int i = 0; i < source.length; i++) {

+                if (source[i] != result[i]) {

+                    fail("Binary data are different at position " + i);

+                }

+            }

+        });

+

+       

+

+    }

+    

+    /** 

+     * Test encryption and decryption of Strings 

+     */

+    @Test

+    public void testStringWithPasswordEncryption() {

+        char[] password = "57cb-4a23-d838-45222".toCharArray();

+        String source = "e02c-3b76-ff1e-5d9a1";

+        

+        cryptoUtilJ8s.forEach(cuj8 -> { 

+            String cipherText = null;

+            try {

+                cipherText = cuj8.encryptString(source, password);

+                log.debug(cipherText);// about 128

+                

+                log.debug("registered {}: {}", cuj8.getClass().getSimpleName());

+                CryptoStreamFactoryJ8Template crt = ((CryptoStreamFactoryJ8Template)cuj8.getCryptoStreamFactory());

+                log.debug(String.format("created default crypto factory instance %s for algo %s with salt (optional): %s", 

+               		crt.getClass().getSimpleName(),

+               		crt.getAlgorithm(), crt.getSalt()));

+                

+                log.debug("length for {} is: {}", crt.getType(), cipherText.length());// about 128

+                if (crt.getType() == TYPES.PBE) {

+                    assertEquals(128, cipherText.length()); // 128bytes + 10 bytes for cleartext

+                } 

+                CryptoStreamFactoryJ8Template.resetInstances();

+                String plainText = cuj8.decryptString(cipherText, password);

+                assertEquals(source, plainText);

+            } catch (GeneralSecurityException | IOException e) {

+                e.printStackTrace();

+                fail();

+            }

+            

+        });      

+

+    }

+

+}

diff --git a/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8ParameterizedTest.java b/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8ParameterizedTest.java
index ed3f275..0f278e7 100644
--- a/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8ParameterizedTest.java
+++ b/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8ParameterizedTest.java
@@ -16,18 +16,25 @@
 
 import org.apache.fulcrum.jce.crypto.PasswordFactory;
 import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8.TYPES;
+import org.apache.fulcrum.jce.junit5.extension.SupportedTypeArguments;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.EnumSource;
+import org.junit.jupiter.params.provider.ArgumentsSource;
 
 /**
  * Test suite for crypto functionality
+ * 
+ * Could still not access arguments of parameterized tests in lifecycle callback methods
+ * 
+ * - https://github.com/junit-team/junit5/issues/944
+ * - https://github.com/junit-team/junit5/issues/1139#issuecomment-341683075
  *
- * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
- */
+ * e.g. with ExtendWith(SupportedTypeArguments.class)
+ * */
 public class CryptoUtilJ8ParameterizedTest {
 	/** the password to be used */
 	private String password;
@@ -46,19 +53,12 @@
 	 * Constructor
 	 */
 	public CryptoUtilJ8ParameterizedTest() {
-
 		this.password = "mysecret";
 		this.testDataDirectory = new File("./src/test/data");
 		this.tempDataDirectory = new File("./target/temp");
 		this.tempDataDirectory.mkdirs();
 	}
 
-//    @ParameterizedTest
-//    @EnumSource( TYPES.class )
-//    public void setUp(TYPES type) throws Exception {
-//        cryptoUtilJ8 = CryptoUtilJ8.getInstance(type); // (TYPES.PBE);
-//    }
-
 	/**
 	 * @return Returns the password.
 	 */
@@ -80,9 +80,16 @@
 		return testDataDirectory;
 	}
 
-	@AfterEach
+	@BeforeEach
 	public void setup() {
 		cryptoUtilJ8s.clear();
+        SupportedTypeArguments.init();
+	}
+	
+
+	@AfterEach
+	public void clean() {
+		cryptoUtilJ8s.clear();
 	}
 
 	/**
@@ -94,7 +101,7 @@
 	 * 
 	 */
 	@ParameterizedTest
-	@EnumSource(TYPES.class)
+	@ArgumentsSource(SupportedTypeArguments.class)
 	public void testTextEncryption(TYPES type) {
 
 		cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
@@ -103,7 +110,11 @@
 
 		cryptoUtilJ8s.forEach(cuj8 -> {
 			try {
-				log.info("checking " + cuj8.getType());
+				log.debug("registered {}: {}", cuj8.getClass().getSimpleName());
+	            CryptoStreamFactoryJ8Template crt = ((CryptoStreamFactoryJ8Template)cuj8.getCryptoStreamFactory());
+	            log.debug(String.format("created default crypto factory instance %s for algo %s with salt (optional): %s", 
+	            		crt.getClass().getSimpleName(),
+           		crt.getAlgorithm(), crt.getSalt()));
 				cuj8.encrypt(sourceFile, targetFile, this.getPassword());
 			} catch (GeneralSecurityException e) {
 				e.printStackTrace();
@@ -122,11 +133,15 @@
 	 * 
 	 */
 	@ParameterizedTest
-	@EnumSource(TYPES.class)
+	@ArgumentsSource(SupportedTypeArguments.class)
 	public void testTextDecryption(TYPES type) {
 		cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
 		cryptoUtilJ8s.forEach(cuj8 -> {
-			log.info("checking " + cuj8.getType());
+			log.debug("registered {}: {}", cuj8.getClass().getSimpleName());
+            CryptoStreamFactoryJ8Template crt = ((CryptoStreamFactoryJ8Template)cuj8.getCryptoStreamFactory());
+            log.debug(String.format("created default crypto factory instance %s for algo %s with salt length: %s", 
+               		crt.getClass().getSimpleName(),
+               		crt.getAlgorithm(), crt.getSalt().length));
 			try {
 				File sourceFile = new File(this.getTestDataDirectory(), "plain.txt");
 				File targetFile = new File(this.getTempDataDirectory(), "plain.j8.enc.txt");
@@ -153,7 +168,7 @@
 	 * 
 	 */
 	@ParameterizedTest
-	@EnumSource(TYPES.class)
+	@ArgumentsSource(SupportedTypeArguments.class)
 	public void testPdfEncryption(TYPES type) {
 		cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
 		File sourceFile = new File(this.getTestDataDirectory(), "plain.pdf");
@@ -175,7 +190,7 @@
 	 * 
 	 */
 	@ParameterizedTest
-	@EnumSource(TYPES.class)
+	@ArgumentsSource(SupportedTypeArguments.class)
 	public void testPdfDecryption(TYPES type) {
 		cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
 		// testPdfEncryption();
@@ -206,9 +221,15 @@
 	 * 
 	 */
 	@ParameterizedTest
-	@EnumSource(TYPES.class)
+	@ArgumentsSource(SupportedTypeArguments.class)
 	public void testStringEncryption(TYPES type) {
 		CryptoUtilJ8 cuj8 = CryptoUtilJ8.getInstance(type);
+		
+		log.debug("registered {} and called for {}", cuj8.getClass().getSimpleName(), type);
+        CryptoStreamFactoryJ8Template crt = ((CryptoStreamFactoryJ8Template)cuj8.getCryptoStreamFactory());
+        log.debug(String.format("created default crypto factory instance %s for algo %s with salt length: %s", 
+           		crt.getClass().getSimpleName(),
+           		crt.getAlgorithm(), crt.getSalt().length));
 		char[] testVector = new char[513];
 
 		for (int i = 0; i < testVector.length; i++) {
@@ -219,18 +240,20 @@
 		String cipherText = null;
 		String plainText = null;
 		try {
-			log.info("Test without clearTextHeader");
+			log.info("Test without clearTextHeader in type {}", type);
 			cipherText = cuj8.encryptString(source, this.getPassword());
-			// log.debug(cipherText);
+			log.trace(cipherText);
 			plainText = cuj8.decryptString(cipherText, this.getPassword());
 			assertEquals(source, plainText, source + " is not equal with " + plainText);
+			
+			String clearCode = type.equals(TYPES.PBE)? CryptoParametersJ8.TYPES.PBE.getClearCode():
+				CryptoParametersJ8.TYPES.GCM.getClearCode() ;
 
-			log.info(String.format("Test with clearTextHeader %s in encrypted string.",
-					CryptoParametersJ8.CLEAR_CODE_J8));
+			log.info(String.format("Test with clearTextHeader %s in encrypted string.",clearCode) );
 			String cipherText2 = cuj8.encryptStringWithClearCode(source, this.getPassword());
-			// log.debug(cipherText2);
-			assertTrue(cipherText2.startsWith(CryptoParametersJ8.CLEAR_CODE_J8),
-					String.format("%s does not start with '%s'", cipherText2, CryptoParametersJ8.CLEAR_CODE_J8));
+			log.trace(cipherText2);
+			assertTrue(cipherText2.startsWith(clearCode),
+					String.format("%s does not start with '%s'", cipherText2, clearCode));
 			String plainText2 = cuj8.decryptStringWithClearCode(cipherText2, this.getPassword());
 			assertEquals(source, plainText2, String.format("%s is not equal with %s", source, plainText));
 
@@ -247,7 +270,7 @@
 	 * 
 	 */
 	@ParameterizedTest
-	@EnumSource(TYPES.class)
+	@ArgumentsSource(SupportedTypeArguments.class)
 	public void testStringHandling(TYPES type) {
 		cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
 		String source = "Nobody knows the toubles I have seen ...";
@@ -292,7 +315,7 @@
 	 * @param type the type to be tested based on {@link TYPES}
 	 */
 	@ParameterizedTest
-	@EnumSource(TYPES.class)
+	@ArgumentsSource(SupportedTypeArguments.class)
 	public void testBinaryHandling(TYPES type) throws Exception {
 		cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
 		cryptoUtilJ8s.forEach(cuj8 -> {
@@ -332,23 +355,28 @@
 	 * 
 	 */
 	@ParameterizedTest
-	@EnumSource(TYPES.class)
+	@ArgumentsSource(SupportedTypeArguments.class)
 	public void testStringWithPasswordEncryption(TYPES type) {
 		char[] password = "57cb-4a23-d838-45222".toCharArray();
 		String source = "e02c-3b76-ff1e-5d9a1";
 		CryptoUtilJ8 cuj8 = CryptoUtilJ8.getInstance(type);
-		log.debug("checking type " + cuj8.getType());
+		log.debug("registered {}: {}", cuj8.getClass().getSimpleName());
+        CryptoStreamFactoryJ8Template crt = ((CryptoStreamFactoryJ8Template)cuj8.getCryptoStreamFactory());
+        log.debug(String.format("created default crypto factory instance %s for algo %s with salt (optional): %s", 
+       		crt.getClass().getSimpleName(),
+       		crt.getAlgorithm(), crt.getSalt()));
 		String cipherText = null;
 		try {
 			cipherText = cuj8.encryptString(source, password);
 			log.info(cipherText);// about 128
-			log.info(String.format("length for %s is %d", cuj8.getType(), cipherText.length()));// about 128
-			if (cuj8.type == TYPES.PBE) {
-				assertEquals(128, cipherText.length()); // 128bytes + 10 bytes for cleartext
-			}
-			if (cuj8.type == TYPES.GCM) {
-				assertEquals(128, cipherText.length());
-			}
+			log.info(String.format("length for %s is %d", cuj8, cipherText.length()));// about 128
+			assertEquals(128, cipherText.length());
+//			if (cuj8.type == TYPES.PBE) {
+//				assertEquals(128, cipherText.length()); // 128bytes + 10 bytes for cleartext
+//			}
+//			if (cuj8.type == TYPES.GCM) {
+//				assertEquals(128, cipherText.length());
+//			}
 			String plainText = cuj8.decryptString(cipherText, password);
 			assertEquals(source, plainText);
 		} catch (GeneralSecurityException | IOException e) {
diff --git a/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8Test.java b/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8Test.java
index 3c7570b..2b7ef55 100644
--- a/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8Test.java
+++ b/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8Test.java
@@ -11,6 +11,8 @@
 import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -18,6 +20,7 @@
 import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8;
 import org.apache.fulcrum.jce.crypto.extended.CryptoStreamFactoryJ8Template;
 import org.apache.fulcrum.jce.crypto.extended.CryptoUtilJ8;
+import org.apache.fulcrum.jce.junit5.extension.SupportedTypeArguments;
 import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8.TYPES;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -25,6 +28,24 @@
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 
+/*
+ * 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.
+ */
 
 /**
  * Test suite for crypto functionality
@@ -60,17 +81,21 @@
     @BeforeAll
     public static void setUp() throws Exception {
         cryptoUtilJ8s.clear();
+        SupportedTypeArguments.init();
         for (TYPES type : CryptoParametersJ8.TYPES.values()) {
-            cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
+            if (SupportedTypeArguments.SUPPORTED_TYPES.contains(type.toString())) {
+            	cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
+            }
         }
         for (CryptoUtilJ8 cryptoUtilJ8 : cryptoUtilJ8s) {
-            log.debug("registered {}: {}", cryptoUtilJ8.getClass().getSimpleName(), cryptoUtilJ8.getType() );
+            log.debug("registered {}: {}", cryptoUtilJ8.getClass().getSimpleName());
             CryptoStreamFactoryJ8Template crt = ((CryptoStreamFactoryJ8Template)cryptoUtilJ8.getCryptoStreamFactory());
-            log.debug(String.format("created default crypto factory instance %s for algo %s", crt.getClass().getSimpleName(),
-            		crt.getAlgorithm()));
+            log.debug(String.format("created default crypto factory instance %s for algo %s with salt length: %s", 
+               		crt.getClass().getSimpleName(),
+               		crt.getAlgorithm(), crt.getSalt().length));
         }
-
     }
+    
     @AfterAll
     public static void destroy() {
         cryptoUtilJ8s.clear();
@@ -124,8 +149,13 @@
      */
     @Test
     public void testTextDecryption() {           
-            cryptoUtilJ8s.forEach(cuj8 -> { 
-                try {
+    	cryptoUtilJ8s.forEach(cuj8 -> { 
+    		log.debug("registered {}: {}", cuj8.getClass().getSimpleName());
+            CryptoStreamFactoryJ8Template crt = ((CryptoStreamFactoryJ8Template)cuj8.getCryptoStreamFactory());
+            log.debug(String.format("created default crypto factory instance %s for algo %s with salt length: %s", 
+               		crt.getClass().getSimpleName(),
+               		crt.getAlgorithm(), crt.getSalt().length));
+    		try {
                     File sourceFile = new File(this.getTestDataDirectory(), "plain.txt");
                     File targetFile = new File(this.getTempDataDirectory(), "plain.j8.enc.txt");
                     cuj8.encrypt(sourceFile, targetFile, this.getPassword());
@@ -302,9 +332,14 @@
             try {
                 cipherText = cuj8.encryptString(source, password);
                 log.debug(cipherText);// about 128
+                
+                CryptoStreamFactoryJ8Template crt = ((CryptoStreamFactoryJ8Template)cuj8.getCryptoStreamFactory());
+                log.debug(String.format("created default crypto factory instance %s for algo %s and type %s with salt (optional): %s", 
+                		crt.getClass().getSimpleName(), crt.getType(),
+                		crt.getAlgorithm(), crt.getSalt()));
 
-                log.debug("length for {} is: {}", cuj8.getType(), cipherText.length());// about 128
-                if (cuj8.type == TYPES.PBE) {
+                log.debug("length for {} is: {}", crt.getType(), cipherText.length());// about 128
+                if (crt.getType() == TYPES.PBE) {
                     assertEquals(128, cipherText.length()); // 128bytes + 10 bytes for cleartext
                 } 
                 CryptoStreamFactoryJ8Template.resetInstances();
diff --git a/src/test/org/apache/fulcrum/jce/crypto/extended/Main8Test.java b/src/test/org/apache/fulcrum/jce/crypto/extended/Main8Test.java
index 6453529..ecd6228 100644
--- a/src/test/org/apache/fulcrum/jce/crypto/extended/Main8Test.java
+++ b/src/test/org/apache/fulcrum/jce/crypto/extended/Main8Test.java
@@ -1,23 +1,25 @@
 package org.apache.fulcrum.jce.crypto.extended;
 
 import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.commons.io.Charsets;
 import org.apache.commons.io.FileUtils;
 import org.apache.fulcrum.jce.crypto.cli.CLI2;
 import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8.TYPES;
+import org.apache.fulcrum.jce.junit5.extension.SupportedTypeArguments;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
 import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
-
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 
 /*
@@ -39,177 +41,198 @@
  * under the License.
  */
 
-
 /**
  * Test suite for crypto functionality
  *
  * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
  */
 
-public class Main8Test
-{
-    /** the password to be used */
-    private String password;
-    
-    /**
-     * Constructor
-     */
-    public Main8Test() {
+public class Main8Test {
+	/** the password to be used */
+	private String password;
 
-        this.password = "foobar";
-        ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
-        builder.setStatusLevel(Level.DEBUG);
-    }
-   
+	/**
+	 * Constructor
+	 */
+	public Main8Test() {
 
-    /**
-     * @return Returns the password.
-     */
-    protected char[] getPassword()
-    {
-        return password.toCharArray();
-    }
-    
-    
-    /** Encrypt a string on the command line */
-    @Test
-    public void testStringEncryption()
-    {
-        String[] encryptionArgs = { "string", "enc", this.password, "mysecretpassword"};
-        CLI2.main(encryptionArgs);
-        String[] decryptionArgs = { "string", "dec", this.password, "ce3bf02da8a57c94b4f42c084230d1bedcd856c49a3fd23ec59835ca46a3d37ee02d470394691353478c905e7b342316d1fcc3e1b98837bf0595ef50853922df"};
-        CLI2.main(decryptionArgs);
-    }
-    @Test
-    public void testAnotherStringEncryption()
-    {
-        String[] encryptionArgs = { "string", "enc", this.password, "secret"};
-        CLI2.main(encryptionArgs);
-        String[] decryptionArgs = { "string", "dec", this.password, "8626904c9e64fddfa64add56472c4796429b0adb7c8039424adef7434be6bc255ce092011e8c560965814e806dd68117"};
-        CLI2.main(decryptionArgs);
-    }
-    @Test
-    /** Encrypt a text file on the command line */
-    public void testFileEncryption1()
-    {
-        String[] encryptionArgs = { "file", "enc", this.password, "./src/test/data/plain.txt", "./target/main8/plain.enc.txt" };
-        String[] decryptionArgs = { "file", "dec", this.password, "./target/main8/plain.enc.txt", "./target/main8/plain.dec.txt" };
-        CLI2.main(encryptionArgs);
-        CLI2.main(decryptionArgs);
-        try {
-            assertTrue(
-                    FileUtils.contentEquals(new File("./src/test/data/plain.txt"), new File("./target/main8/plain.dec.txt"))
-                    );
-        } catch (IOException e) {
-            fail();
+		this.password = "foobar";
+		ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
+		builder.setStatusLevel(Level.DEBUG);
+	}
+
+	@BeforeAll
+	public static void setup() {
+		SupportedTypeArguments.init();
+	}
+
+	/**
+	 * @return Returns the password.
+	 */
+	protected char[] getPassword() {
+		return password.toCharArray();
+	}
+
+	/** Encrypt a string on the command line */
+	@Test
+	public void testStringEncryption() {
+		String[] encryptionArgs = { "string", "enc", this.password, "mysecretpassword" };
+		CLI2.main(encryptionArgs);
+		String[] decryptionArgs = { "string", "dec", this.password,
+				"ce3bf02da8a57c94b4f42c084230d1bedcd856c49a3fd23ec59835ca46a3d37ee02d470394691353478c905e7b342316d1fcc3e1b98837bf0595ef50853922df" };
+		CLI2.main(decryptionArgs);
+	}
+
+	@Test
+	public void testAnotherStringEncryption() {
+		String[] encryptionArgs = { "string", "enc", this.password, "secret" };
+		CLI2.main(encryptionArgs);
+		String[] decryptionArgs = { "string", "dec", this.password,
+				"8626904c9e64fddfa64add56472c4796429b0adb7c8039424adef7434be6bc255ce092011e8c560965814e806dd68117" };
+		CLI2.main(decryptionArgs);
+	}
+
+	@Test
+	/** Encrypt a text file on the command line */
+	public void testFileEncryption1() {
+		String[] encryptionArgs = { "file", "enc", this.password, "./src/test/data/plain.txt",
+				"./target/main8/plain.enc.txt" };
+		String[] decryptionArgs = { "file", "dec", this.password, "./target/main8/plain.enc.txt",
+				"./target/main8/plain.dec.txt" };
+		CLI2.main(encryptionArgs);
+		CLI2.main(decryptionArgs);
+		try {
+			assertTrue(FileUtils.contentEquals(new File("./src/test/data/plain.txt"),
+					new File("./target/main8/plain.dec.txt")));
+		} catch (IOException e) {
+			fail();
+		}
+	}
+
+	@Test
+	/** Encrypt a text file in-place on the command line */
+	public void testFileEncryption2() {
+		String[] encryptionArgs = { "file", "enc", this.password, "./src/test/data/plain.txt",
+				"./target/main8/plain.txt" };
+		// caution decrypting into source file!
+		String[] decryptionArgs = { "file", "dec", this.password, "./target/main8/plain.txt" };
+		CLI2.main(encryptionArgs);
+		CLI2.main(decryptionArgs);
+	}
+
+	@Test
+	public void testYetAnotherStringEncryption() {
+		try {
+			// assumptions
+			String topSecret = "mysecretpassword";
+			assertTrue(FileUtils.readFileToString(new File("./src/test/data/plain-simple.txt"), StandardCharsets.UTF_8)
+					.equals(topSecret));
+
+			if (SupportedTypeArguments.SUPPORTED_TYPES.contains(TYPES.GCM.toString())) {
+
+				// test
+				// encode from string = hexdecimal file
+				String[] encryptionArgs = { "string", "enc" + TYPES.GCM, this.password, topSecret,
+						"./target/main8/another-plain16chars.enc.txt" };
+				CLI2.main(encryptionArgs);
+				// shows hex dec in stderr + file
+
+				String[] decryptionArgs = { "string", "dec" + TYPES.GCM, this.password,
+						"c9fa3e7d3c49d379ee8ff2dff6e6effbafee264794a03d0ffd895caac2b3c9b4558087f5b12e72a92475f1ed638b7911389234b443d4ebcf351c86cb",
+						"./target/main8/another-plain16chars.dec.txt" };
+				CLI2.main(decryptionArgs);
+				// shows clear password in stdout + file
+
+				assertTrue(FileUtils.readFileToString(new File("./target/main8/another-plain16chars.dec.txt"),
+						StandardCharsets.UTF_8).equals(topSecret));
+
+				String[] decryptionArgs2 = { "string", "dec" + TYPES.GCM, this.password,
+						"605efd3009a7242a9c9cab23aa712d6d116e8686732194d3306416cda2a416df1e63aeffcdc1910af1e1100b382b24fc628d9c413ebf7e1b2885c0ec" };
+				CLI2.main(decryptionArgs2);
+				// shows clear password in stdout (offline decoded)
+
+				// file mode commands do show nothing on stdout, except Decrypting / Encrypting
+
+				// should not fail, if converted from hex
+				String[] decryptionArgs3 = { "file", "dec" + TYPES.GCM, this.password,
+						"./target/main8/another-plain16chars.enc.txt", "./target/main8/another-plain16chars2.dec.txt" };
+				CLI2.main(decryptionArgs3);
+				assertTrue(FileUtils.readFileToString(new File("./target/main8/another-plain16chars2.dec.txt"),
+						StandardCharsets.UTF_8).equals(topSecret));
+
+				String[] encryptionArgs4 = { "file", "enc" + TYPES.GCM, this.password,
+						"./src/test/data/plain-simple.txt", "./target/main8/plain-simple.enc.txt" };
+				CLI2.main(encryptionArgs4);
+
+				String[] decryptionArgs4 = { "file", "dec" + TYPES.GCM, this.password,
+						"./target/main8/plain-simple.enc.txt", "./target/main8/plain-simple.dec.txt" };
+				CLI2.main(decryptionArgs4);
+
+				try {
+					assertTrue(FileUtils.contentEquals(new File("./src/test/data/plain-simple.txt"),
+							new File("./target/main8/plain-simple.dec.txt")));
+				} catch (IOException e) {
+					fail();
+				}
+
+			}
+
+		} catch (Exception e) {
+			e.printStackTrace();
+			fail();
+		}
+	}
+
+	@Test
+	public void testIntegratedStringEncryption() {
+		try {
+			// assumptions
+			String topSecret = "myX!_secretp@ssword?~,2";
+
+			Map<String, Object> conf = new HashMap<>();
+			conf.put("enc", TYPES.GCM);
+
+			// encode as string to stderr and file in hexdecimal format
+			String[] encryptionArgs = { "string", "enc" + conf.get("enc"), this.password, topSecret,
+					"./target/main8/integrated-plain16chars.enc.txt" };
+			CLI2.main(encryptionArgs);
+			// shows encoded hexdec in stdout + file
+
+			String encodedEncrypted = FileUtils.readFileToString(
+					new File("./target/main8/integrated-plain16chars.enc.txt"), StandardCharsets.UTF_8);
+
+			conf.put("pw", encodedEncrypted);
+
+			// this should be done without output to console
+			String result = CLI2.processString("dec" + conf.get("enc"), this.password.toCharArray(),
+					(String) conf.get("pw"));
+
+			assertTrue(result.equals(topSecret));
+
+		} catch (Exception e) {
+			e.printStackTrace();
+			fail();
+		}
+	}
+	
+	@Test
+    public void testDefaultStringEncryption() {
+        char[] testVector = new char[513];
+
+        for (int i = 0; i < testVector.length; i++) {
+            testVector[i] = (char) i;
         }
-    }
-    @Test
-    /** Encrypt a text file in-place on the command line */
-    public void testFileEncryption2()
-    {
-        String[] encryptionArgs = { "file", "enc", this.password, "./src/test/data/plain.txt", "./target/main8/plain.txt" };
-        // caution decrypting into source file!
-        String[] decryptionArgs = { "file", "dec", this.password, "./target/main8/plain.txt" };
-        CLI2.main(encryptionArgs);
-        CLI2.main(decryptionArgs);
-    }
-    
-    @Test
-    public void testYetAnotherStringEncryption()
-    {
+        String source = new String(testVector);
+       
+        CryptoUtilJ8.getInstances().clear();
+        CryptoUtilJ8 cuj8 = CryptoUtilJ8.getInstance();
+        String cipherText;
+        String plainText;
         try {
-            // assumptions
-            String topSecret= "mysecretpassword";
-            assertTrue(FileUtils.readFileToString(
-                    new File("./src/test/data/plain-simple.txt"), StandardCharsets.UTF_8).
-                    equals(topSecret));
-            // test
-            // encode from string = hexdecimal file
-            String[] encryptionArgs = { "string", "enc"+TYPES.GCM, this.password, topSecret, 
-                    "./target/main8/another-plain16chars.enc.txt"};
-            CLI2.main(encryptionArgs);
-            // shows hex dec in stderr + file 
-   
-            String[] decryptionArgs = { "string", "dec"+TYPES.GCM, this.password, 
-                    "c9fa3e7d3c49d379ee8ff2dff6e6effbafee264794a03d0ffd895caac2b3c9b4558087f5b12e72a92475f1ed638b7911389234b443d4ebcf351c86cb", 
-                    "./target/main8/another-plain16chars.dec.txt"};
-            CLI2.main(decryptionArgs);
-            //  shows clear password in stdout + file
-            
-            assertTrue(
-                    FileUtils.readFileToString(
-                            new File("./target/main8/another-plain16chars.dec.txt"), StandardCharsets.UTF_8).
-                    equals(topSecret));
-            
-            String[] decryptionArgs2 = { "string", "dec"+TYPES.GCM, this.password, 
-                    "605efd3009a7242a9c9cab23aa712d6d116e8686732194d3306416cda2a416df1e63aeffcdc1910af1e1100b382b24fc628d9c413ebf7e1b2885c0ec"};
-            CLI2.main(decryptionArgs2);
-            //  shows clear password in stdout (offline decoded)
-            
-            // file mode commands do show nothing on stdout, except Decrypting / Encrypting
-            
-            // should not fail, if converted from hex
-            String[] decryptionArgs3 = { "file", "dec"+TYPES.GCM, this.password, "./target/main8/another-plain16chars.enc.txt", "./target/main8/another-plain16chars2.dec.txt"};
-            CLI2.main(decryptionArgs3);
-            assertTrue(
-                    FileUtils.readFileToString(
-                            new File("./target/main8/another-plain16chars2.dec.txt"), StandardCharsets.UTF_8).
-                    equals(topSecret));
-            
-            String[] encryptionArgs4 = { "file", "enc"+TYPES.GCM, this.password, 
-                    "./src/test/data/plain-simple.txt", "./target/main8/plain-simple.enc.txt" };
-            CLI2.main(encryptionArgs4);
-            
-            String[] decryptionArgs4 = { "file", "dec"+TYPES.GCM, this.password, 
-                    "./target/main8/plain-simple.enc.txt", "./target/main8/plain-simple.dec.txt"};
-            CLI2.main(decryptionArgs4);
-            
-            try {
-                assertTrue(
-                        FileUtils.contentEquals(
-                                new File("./src/test/data/plain-simple.txt"), 
-                                new File("./target/main8/plain-simple.dec.txt"))
-                        );
-            } catch (IOException e) {
-                fail();
-            }
-  
-        } catch (Exception e) {
-            e.printStackTrace();
-            fail();
-        }
-    }
-    
-    @Test
-    public void testIntegratedStringEncryption()
-    {
-        try {
-            // assumptions
-            String topSecret= "myX!_secretp@ssword?~,2";
-            
-            Map<String,Object> conf = new HashMap<>();
-            conf.put("enc",TYPES.GCM);
-
-            // encode as string to stderr and  file in hexdecimal format
-            String[] encryptionArgs = {
-                    "string", "enc"+ conf.get("enc"), this.password,
-                    topSecret, 
-                    "./target/main8/integrated-plain16chars.enc.txt"};
-            CLI2.main(encryptionArgs);
-            // shows encoded hexdec in stdout + file
-            
-            String encodedEncrypted = FileUtils.readFileToString(new File("./target/main8/integrated-plain16chars.enc.txt"), StandardCharsets.UTF_8);
-            
-            conf.put("pw", encodedEncrypted);
-
-            // this should be done without output to console
-            String result = CLI2.processString( "dec"+ conf.get("enc"), this.password.toCharArray(), (String) conf.get("pw"));
-            
-            assertTrue(
-                    result.equals(topSecret));
-
-        } catch (Exception e) {
+            cipherText = cuj8.encryptString(source, this.getPassword());
+            plainText = cuj8.decryptString(cipherText, this.getPassword());
+            assertEquals(source, plainText, source +" is not equal with " + plainText); 
+        } catch (GeneralSecurityException | IOException e) {
             e.printStackTrace();
             fail();
         }
diff --git a/src/test/org/apache/fulcrum/jce/junit5/extension/SupportedTypeArguments.java b/src/test/org/apache/fulcrum/jce/junit5/extension/SupportedTypeArguments.java
new file mode 100644
index 0000000..c475523
--- /dev/null
+++ b/src/test/org/apache/fulcrum/jce/junit5/extension/SupportedTypeArguments.java
@@ -0,0 +1,71 @@
+package org.apache.fulcrum.jce.junit5.extension;

+

+import java.util.Arrays;

+import java.util.List;

+import java.util.stream.Collectors;

+import java.util.stream.Stream;

+

+import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8;

+import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8.TYPES;

+import org.apache.logging.log4j.LogManager;

+import org.apache.logging.log4j.Logger;

+import org.junit.jupiter.api.extension.ExtensionContext;

+import org.junit.jupiter.params.provider.Arguments;

+import org.junit.jupiter.params.provider.ArgumentsProvider;

+

+/*

+ * 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.

+ */

+ 

+/**

+ * Using {@link CryptoParametersJ8#init()} and ArgumentsProvider to filter parameters.

+ * 

+ * Could still not access arguments of parameterized tests in lifecycle callback methods

+ * 

+ * - https://github.com/junit-team/junit5/issues/944

+ * - https://github.com/junit-team/junit5/issues/1139#issuecomment-341683075

+ * 

+ * @author gkallidis

+ *

+ */

+public class SupportedTypeArguments implements ArgumentsProvider {

+	

+	public static Logger log = LogManager.getLogger();

+	

+	public static List<String> SUPPORTED_TYPES = null;

+	

+	public static void init() {

+		if (SUPPORTED_TYPES == null) {

+			SUPPORTED_TYPES = CryptoParametersJ8.init();

+		}

+		log.warn("SUPPORTED_TYPES: {}",SupportedTypeArguments.SUPPORTED_TYPES);

+	}

+ 

+	@Override

+	public Stream<? extends Arguments> provideArguments(ExtensionContext arg0) throws Exception {

+		if (SUPPORTED_TYPES == null) {

+			init();

+		}

+		return SUPPORTED_TYPES.stream().map(Arguments::of);

+	}

+

+	public static List<String> getSUPPORTED_TYPES() {

+		return SUPPORTED_TYPES;

+	}

+

+}

diff --git a/xdocs/index.xml b/xdocs/index.xml
index 66a9b0d..8e21359 100644
--- a/xdocs/index.xml
+++ b/xdocs/index.xml
@@ -120,7 +120,7 @@
           </tr>
         </table>
       </subsection>
-      <subsection name="Availabe Algorithms">
+      <subsection name="Availabe Cipher Algorithms (Algorithm Modes)">
         <table>
           <tr>
             <th>Provider Version</th>
@@ -134,10 +134,14 @@
             <td>SunJCE 1.42</td>
             <td>PBEWithMD5AndDES</td>
           </tr>
-           <tr>
+          <tr>
             <td>SunJCE (Java 8)</td>
             <td>PBEWithHmacSHA256AndAES_256</td>
           </tr>
+           <tr>
+            <td>SunJCE (Java 8)</td>
+            <td>AES_128/GCM/NoPadding</td>
+          </tr>
         </table>
       </subsection>
      </section>