[maven-release-plugin] copy for tag fulcrum-yaafi-crypto-2.0.1

git-svn-id: https://svn.apache.org/repos/asf/turbine/fulcrum/tags/fulcrum-yaafi-crypto-2.0.1@1881901 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/NOTICE.txt b/NOTICE.txt
index ef3d1c2..de693dd 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -1,5 +1,5 @@
 Turbine Fulcrum YAAFI-Cypto Component
-Copyright 2002-2007 The Apache Software Foundation.
+Copyright 2002-2020 The Apache Software Foundation.
 
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
diff --git a/pom.xml b/pom.xml
index 279265f..e7932bd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,84 +1,220 @@
-<?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.
-
--->
-<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>5</version>
-  </parent>
-
-  <modelVersion>4.0.0</modelVersion>
-  <artifactId>fulcrum-yaafi-crypto</artifactId>
-  <groupId>org.apache.fulcrum</groupId>
-  <version>1.0.7</version>
-  <name>Fulcrum YAAFI Crypto</name>
-  <inceptionYear>2008</inceptionYear>
-  <description>Fulcrum YAAFI Crypto Library</description>
-  <url>http://turbine.apache.org/fulcrum/fulcrum-yaafi-crytpo</url>
-
-  <!-- Required for staging to work -->
-  <distributionManagement>
-    <site>
-      <id>turbine.apache.org</id>
-      <url>https://turbine.apache.org/fulcrum/fulcrum-yaafi-crypto</url>
-    </site>
-  </distributionManagement>
-		
-  <scm>
-    <connection>scm:svn:http://svn.apache.org/repos/asf/turbine/fulcrum/tags/fulcrum-yaafi-crypto-1.0.7/</connection>
-    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/turbine/fulcrum/tags/fulcrum-yaafi-crypto-1.0.7</developerConnection>
-    <url>http://svn.apache.org/viewvc/turbine/fulcrum/tags/fulcrum-yaafi-crypto-1.0.7</url>
-  </scm>
-	
-  <developers>
-    <developer>
-      <name>Siegfried Goeschl</name>
-      <id>sgoeschl</id>
-      <email>sgoeschl@apache.org</email>
-      <organization />
-      <roles>
-        <role>Java Developer</role>
-      </roles>
-    </developer>
-  </developers>
-
-  <dependencies>
-    <!-- testing dependencies -->
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>4.12</version>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
-
-  <build>
-    <sourceDirectory>${basedir}/src/java</sourceDirectory>
-    <testSourceDirectory>${basedir}/src/test</testSourceDirectory>
-  </build>
-
-  <properties>
-    <turbine.site.path>fulcrum/fulcrum-yaafi-crypto</turbine.site.path>
-    <turbine.scmPubCheckoutDirectory>${turbine.site.cache}/fulcrum/fulcrum-yaafi-crypto</turbine.scmPubCheckoutDirectory>
-    <turbine.site.cache>${project.build.directory}/turbine-sites</turbine.site.cache>
-    <siteContent.path>${project.build.directory}/staging</siteContent.path><!-- default stagingSiteURL -->
-  </properties>  
-	
-</project>
+<?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.

+

+-->

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

+    <relativePath />

+  </parent>

+

+  <modelVersion>4.0.0</modelVersion>

+  <artifactId>fulcrum-yaafi-crypto</artifactId>

+  <groupId>org.apache.fulcrum</groupId>

+  <version>2.0.1</version>

+  <name>Fulcrum YAAFI Crypto</name>

+  <inceptionYear>2008</inceptionYear>

+  <description>Fulcrum YAAFI Crypto Library</description>

+  <url>http://turbine.apache.org/fulcrum/fulcrum-yaafi-crytpo</url>

+

+  <!-- Required for staging to work -->

+  <distributionManagement>

+    <site>

+      <id>turbine.apache.org</id>

+      <url>https://turbine.apache.org/fulcrum/fulcrum-yaafi-crypto/</url>

+    </site>

+  </distributionManagement>

+

+  <scm>

+    <connection>scm:svn:http://svn.apache.org/repos/asf/turbine/fulcrum/tags/fulcrum-yaafi-crypto-2.0.1</connection>

+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/turbine/fulcrum/tags/fulcrum-yaafi-crypto-2.0.1</developerConnection>

+    <url>http://svn.apache.org/viewvc/turbine/fulcrum/tags/fulcrum-yaafi-crypto-2.0.1</url>

+  </scm>

+	

+  <developers>

+    <developer>

+      <name>Siegfried Goeschl</name>

+      <id>sgoeschl</id>

+      <email>sgoeschl@apache.org</email>

+      <organization />

+      <roles>

+        <role>Java Developer</role>

+      </roles>

+    </developer>

+     <developer>

+      <name>Georg Kallidis </name>

+      <id>gk</id>

+      <email>gk@apache.org</email>

+      <organization />

+      <roles>

+        <role>Java Developer</role>

+      </roles>

+    </developer>

+  </developers>

+

+  <dependencies>

+    <!-- testing dependencies -->

+       <dependency>

+            <groupId>org.junit.jupiter</groupId>

+            <artifactId>junit-jupiter</artifactId>

+            <version>5.6.2</version>

+            <scope>test</scope>

+        </dependency>

+        <dependency>

+			<groupId>junit</groupId>

+			<artifactId>junit</artifactId>

+			<version>4.13</version>

+              <scope>test</scope>

+		</dependency>

+        <dependency>

+            <groupId>org.apache.fulcrum</groupId>

+            <artifactId>fulcrum-testcontainer</artifactId>

+            <version>1.0.8</version>

+            <exclusions>

+                <exclusion>

+                    <groupId>*</groupId>

+                    <artifactId>*</artifactId>

+                </exclusion>

+            </exclusions>

+            <scope>test</scope>

+      </dependency>

+    <dependency>

+      <groupId>org.apache.logging.log4j</groupId>

+      <artifactId>log4j-core</artifactId>

+      <version>${turbine.log4j2.version}</version>

+      <scope>test</scope><!-- change to provided ? -->

+    </dependency>

+    <dependency>

+        <groupId>commons-io</groupId>

+        <artifactId>commons-io</artifactId>

+        <version>2.6</version>

+        <scope>test</scope>

+    </dependency>    

+  </dependencies>

+

+  <build>

+    <sourceDirectory>${basedir}/src/java</sourceDirectory>

+    <testSourceDirectory>${basedir}/src/test</testSourceDirectory>

+    <testResources>

+      <testResource>

+        <directory>src/test</directory>

+        <includes> <include>**/*.xml</include><include>**/*.properties</include>

+        </includes>

+      </testResource>

+    </testResources>

+    

+    <plugins>

+     <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-jar-plugin</artifactId>

+        <version>2.3</version>

+        <configuration>

+          <archive>

+            <manifest>

+              <addClasspath>true</addClasspath>

+              <mainClass>org.apache.fulcrum.jce.crypto.cli.CLI2</mainClass>

+            </manifest>

+          </archive>

+        </configuration>

+      </plugin>    

+      <plugin>

+        <artifactId>maven-antrun-plugin</artifactId>

+        <!-- 

+            Integration Test encrypts and decrypts in one step

+            mvn clean install integration-test 

+            -->

+        <executions>

+          <execution>

+            <id>init</id>

+            <phase>integration-test</phase>

+            <configuration>

+              <skip>${skip.pw.encrypt}</skip>

+              <target>

+                 <touch file="${basedir}/target/integration-test/filter-integration-test.properties" mkdirs="true" />

+                <ant antfile="${basedir}/src/ant/integration-test-build-pw.xml" target="init">

+                  <property name="build.path" value="${basedir}/build" />

+                   <property name="password" value="${test.password}" />

+                  <property name="meta.pw" value="${meta.pw}" />

+                  <property name="jarname" value="${project.build.finalName}" />

+                  <!-- generates encrypted password, saved in vcs: -->

+                  <property name="target.property.path" value="${basedir}/target/integration-test/filter-integration-test.properties" />

+                </ant>

+              </target>

+            </configuration>

+            <goals>

+              <goal>run</goal>

+            </goals>

+          </execution>

+          <execution>

+            <id>build</id>

+            <!-- 

+            1) run mvn package to generate executable jar 

+            2) mvn generate-sources -Dskip.pw.gen=false 

+            to generate encrypted password 

+            -->

+            <phase>integration-test</phase>

+            <configuration>

+              <skip>${skip.pw.gen}</skip>

+              <target>

+                <touch file="${basedir}/target/integration-test/filtered-pw.properties" mkdirs="true" />

+                <ant antfile="${basedir}/src/ant/integration-test-build-pw.xml" target="build">

+                  <property name="build.path" value="${basedir}/build" />

+                  <property name="meta.pw" value="${meta.pw}" /><!-- 

+                    provided by env variable -->

+                  <property name="jarname" value="${project.build.finalName}" />

+                  <!-- contains encrypted password, saved in vcs: -->

+                  <property name="source.property.path" value="${basedir}/target/integration-test/filter-integration-test.properties" />

+                  <!-- should not be saved in vcs: -->

+                  <property name="target.property.path" value="${basedir}/target/integration-test/filtered-pw.properties" />

+                </ant>

+              </target>

+            </configuration>

+            <goals>

+              <goal>run</goal>

+            </goals>

+          </execution>

+

+        </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>

+  

+  <properties>

+    <turbine.site.path>fulcrum/fulcrum-yaafi-crypto</turbine.site.path>

+    <turbine.scmPubCheckoutDirectory>${turbine.site.cache}/fulcrum/yaafi-crypto</turbine.scmPubCheckoutDirectory>

+    <turbine.site.cache>${project.build.directory}/turbine-sites</turbine.site.cache>

+    <siteContent.path>${project.build.directory}/staging</siteContent.path><!-- default stagingSiteURL -->

+

+    <skip.pw.encrypt>false</skip.pw.encrypt>

+    <skip.pw.gen>false</skip.pw.gen>

+    <meta.pw>changeit</meta.pw>

+    <test.password>mypassword</test.password>

+  </properties>  

+	

+</project>

diff --git a/src/ant/integration-test-build-pw.xml b/src/ant/integration-test-build-pw.xml
new file mode 100644
index 0000000..d1c2b21
--- /dev/null
+++ b/src/ant/integration-test-build-pw.xml
@@ -0,0 +1,69 @@
+<project basedir="."  default="build" name="build">

+  <property environment="env"/>

+   <property file=".build"/>  

+   <!-- reading from the file properties: password_encrypted or password -->

+   <property file="${source.property.path}"/>

+   <property name="meta.pw" value="${env.meta.pw}"/>

+

+   <target name="testjava">

+      <echo>Ant Java/JVM  version: ${java.version}</echo> 

+    </target>

+   

+   <target name="decrypt">

+      <echo message="executing java -jar target/${jarname}.jar string dec &quot;${meta.pw}&quot; &quot;${password_encrypted}&quot;."/>

+      <java jar="target/${jarname}.jar" fork="true" failonerror="true" maxmemory="128m" dir="${build.path}/../" outputproperty="decoded.pw" inputstring="">

+         <arg value="string"/>

+         <arg value="dec"/>

+         <arg value="${meta.pw}"/>

+         <arg value="${password_encrypted}"/>

+         <classpath>

+            <pathelement location="target/${jarname}.jar"/>

+            <pathelement path="${java.class.path}"/>

+        </classpath>

+      </java>

+    </target>

+    

+     <target name="encrypt">

+      <echo message="executing java -jar target/${jarname}.jar string enc &quot;${meta.pw}&quot; &quot;${password}&quot;"/>

+      <java jar="target/${jarname}.jar" fork="true" failonerror="true" maxmemory="128m" dir="${build.path}/../" outputproperty="encoded.pw" inputstring="">

+         <arg value="string"/>

+         <arg value="enc"/>

+         <arg value="${meta.pw}"/>

+         <arg value="${password}"/>

+         <classpath>

+            <pathelement location="target/${jarname}.jar"/>

+            <pathelement path="${java.class.path}"/>

+        </classpath>

+      </java>

+    </target>

+  

+   <target name="update">

+       <echo message="updating password in property file: ${target.property.path}."/>

+       <propertyfile file="${target.property.path}" >

+          <entry  key="password" value="${decoded.pw}"/>

+        </propertyfile>

+    </target>

+    

+    <target name="init-update">

+       <echo message="updating password_encrypted in property file: ${target.property.path}."/>

+       <propertyfile file="${target.property.path}" >

+          <entry  key="password_encrypted" value="${encoded.pw}"/>

+        </propertyfile>

+    </target>

+  

+  <target name="clean">

+   <echo message="cleaning up key password in property file: ${target.property.path}."/>

+       <propertyfile file="${target.property.path}" >

+          <entry  key="password" value=""/>

+        </propertyfile>

+  </target>

+  

+    <!-- decrypt to --> 

+   <target name="build" depends="testjava, decrypt, update">

+  </target>

+  

+    <!-- encrypt to password_encrypted -->

+    <target name="init" depends="testjava, encrypt, init-update">

+   </target>

+  

+ </project>  
\ No newline at end of file
diff --git a/xdocs/changes.xml b/src/changes/changes.xml
similarity index 67%
rename from xdocs/changes.xml
rename to src/changes/changes.xml
index 56db47f..0ea4516 100644
--- a/xdocs/changes.xml
+++ b/src/changes/changes.xml
@@ -24,7 +24,20 @@
   </properties>
 
   <body>
-    <release version="1.0.7" date="as in SVN">
+    <release version="2.0.2" date="as in SVN">
+    </release>
+    <release version="2.0.1" 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>
+      <action dev="painter" type="update">
+        Clean up PMD and FindBug reports.  Fixed some typos and updated to conform with Turbine coding style guidelines
+      </action>
+    </release>
+    <release version="1.0.7" date="2018-11-08">
       <action dev="painter" type="update">
         Simplify the HexConverter code, more Java 8 friendly
       </action>
@@ -38,7 +51,7 @@
         Fix missing license from rat report
       </action>
     </release>
-    <release version="1.0.6" date="as in SVN">
+    <release version="1.0.6" date="2009-03-25">
       <action dev="sgoeschl" type="update">
         Using the official fulcrum-parent-1 pom.	
       </action>
diff --git a/src/java/org/apache/fulcrum/jce/crypto/CryptoParameters.java b/src/java/org/apache/fulcrum/jce/crypto/CryptoParameters.java
index 9ee3eb3..914f020 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/CryptoParameters.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/CryptoParameters.java
@@ -31,12 +31,22 @@
     /** Parameter for PBEParameterSpec */
     int COUNT = 20;
 
-    /** The password salt */
-    byte[] SALT = {
-        (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
-        (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
-        };
-
-    /** The crypto algorithm being used */
-    String ALGORITHM = "PBEWithMD5AndDES";
-}
+    /** 
+     * The password salt: update to a method to prevent malicious code bug.
+     * 
+     * @return the salt 
+     * 
+     * */
+    public static byte[] Salt() 
+    {
+    	return new byte[] 
+    			{
+    					(byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
+    					(byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
+    			};
+    }
+    
+    
+    /** 
+     * The default crypto algorithm being used */
+    String ALGORITHM = "PBEWithMD5AndDES";}
diff --git a/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactory.java b/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactory.java
index 34e55a3..5a4e5be 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactory.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactory.java
@@ -115,9 +115,9 @@
      * Creates an encrypting output stream using the default password.
      *
      * @param os the output stream to be wrapped
-     * @return an decrypting input stream
-     * @throws GeneralSecurityException creating the ouptut stream failed
-     * @throws IOException creating the ouptut stream failed
+     * @return an encrypting output stream
+     * @throws GeneralSecurityException creating the output stream failed
+     * @throws IOException creating the output stream failed
      */
     OutputStream getOutputStream(OutputStream os)
         throws GeneralSecurityException, IOException;
@@ -127,10 +127,17 @@
      *
      * @param os the output stream to be wrapped
      * @param password the password to be used
-     * @return an decrypting input stream
-     * @throws GeneralSecurityException creating the ouptut stream failed
-     * @throws IOException creating the ouptut stream failed
+     * @return an encrypting output stream
+     * @throws GeneralSecurityException creating the output stream failed
+     * @throws IOException creating the output stream failed
      */
     OutputStream getOutputStream(OutputStream os, char[] password)
         throws GeneralSecurityException, IOException;
+
+    /**
+     * Info about used algorithm.
+     * @return algorithm string 
+     */
+    String getAlgorithm();
+    
 }
diff --git a/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactoryImpl.java b/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactoryImpl.java
index 2449cf4..609d0a6 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactoryImpl.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactoryImpl.java
@@ -21,13 +21,10 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 import java.security.GeneralSecurityException;
 import java.security.Key;
 
 import javax.crypto.Cipher;
-import javax.crypto.CipherInputStream;
-import javax.crypto.CipherOutputStream;
 import javax.crypto.SecretKeyFactory;
 import javax.crypto.spec.PBEKeySpec;
 import javax.crypto.spec.PBEParameterSpec;
@@ -52,19 +49,19 @@
  * @author <a href="mailto:maakus@earthlink.net">Markus Hahn</a>
  */
 
-public final class CryptoStreamFactoryImpl implements CryptoStreamFactory
+public class CryptoStreamFactoryImpl extends CryptoStreamFactoryTemplate implements CryptoStreamFactory
 {
     /** the salt for the PBE algorithm */
-    private byte[] salt;
+    protected final byte[] salt;
 
     /** the count paramter for the PBE algorithm */
-    private int count;
+    protected int count;
 
     /** the name of the JCE provider */
-    private String providerName;
+    protected String providerName;
 
     /** the algorithm to use */
-    private String algorithm;
+    protected String algorithm;
 
     /** the default instance */
     private static CryptoStreamFactory instance;
@@ -74,20 +71,22 @@
      * is set to null an appropriate provider will be
      * used.
      */
-    private static final String PROVIDERNAME = null;
+    protected static final String PROVIDERNAME = null;
 
     /**
      * Factory method to get a default instance
      * @return an instance of the CryptoStreamFactory
      */
-    public synchronized static CryptoStreamFactory getInstance()
+    public static CryptoStreamFactory getInstance()
     {
-        if( CryptoStreamFactoryImpl.instance == null )
-        {
-            CryptoStreamFactoryImpl.instance = new CryptoStreamFactoryImpl();
+        synchronized(CryptoStreamFactoryImpl.class ) {
+            if( CryptoStreamFactoryImpl.instance == null )
+            {
+                CryptoStreamFactoryImpl.instance = new CryptoStreamFactoryImpl();
+            }
+    
+            return CryptoStreamFactoryImpl.instance;
         }
-
-        return CryptoStreamFactoryImpl.instance;
     }
 
     /**
@@ -104,7 +103,7 @@
      */
     public CryptoStreamFactoryImpl()
     {
-        this.salt = CryptoParameters.SALT;
+        this.salt = CryptoParameters.Salt();
         this.count = CryptoParameters.COUNT;
         this.providerName = PROVIDERNAME;
         this.algorithm = CryptoParameters.ALGORITHM;
@@ -118,91 +117,37 @@
      */
     public CryptoStreamFactoryImpl( byte[] salt, int count)
     {
-        this.salt = salt;
+        this.salt = salt.clone();
         this.count = count;
         this.providerName = PROVIDERNAME;
         this.algorithm = CryptoParameters.ALGORITHM;
     }
-
+    
 
     /**
-     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getInputStream(java.io.InputStream, String)
+     * 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 InputStream getInputStream(InputStream is, String decryptionMode) throws GeneralSecurityException, IOException {
-
-        InputStream result = null;
-
-        if( "auto".equalsIgnoreCase(decryptionMode) )
-        {
-            result = CryptoStreamFactoryImpl.getInstance().getSmartInputStream(is);
-        }
-        else if( "true".equalsIgnoreCase(decryptionMode) )
-        {
-            result = CryptoStreamFactoryImpl.getInstance().getInputStream(is);
-        }
-        else
-        {
-            result = is;
-        }
-        return result;
-    }
-
-    /**
-     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getInputStream(java.io.InputStream, String, char[])
-     */
-    public InputStream getInputStream(InputStream is, String decryptionMode, char[] password) throws GeneralSecurityException, IOException {
-
-        InputStream result = null;
-
-        if( "auto".equalsIgnoreCase(decryptionMode) )
-        {
-            result = CryptoStreamFactoryImpl.getInstance().getSmartInputStream(is, password);
-        }
-        else if( "true".equalsIgnoreCase(decryptionMode) )
-        {
-            result = CryptoStreamFactoryImpl.getInstance().getInputStream(is, password);
-        }
-        else
-        {
-            result = is;
-        }
-        return result;
-    }
-
-    /**
-     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getInputStream(java.io.InputStream)
-     */
-    public InputStream getInputStream( InputStream is )
-        throws GeneralSecurityException, IOException
+    public static CryptoStreamFactory getInstance( byte[] salt, int count)
     {
-        Cipher cipher = this.createCipher( Cipher.DECRYPT_MODE, PasswordFactory.create() );
-        return new CipherInputStream( is, cipher );
-    }
-
-    /**
-     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getInputStream(java.io.InputStream,char[])
-     */
-    public InputStream getInputStream( InputStream is, char[] password )
-        throws GeneralSecurityException, IOException
-    {
-        Cipher cipher = this.createCipher( Cipher.DECRYPT_MODE, password );
-        return new CipherInputStream( is, cipher );
-    }
-
-    /**
-     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getSmartInputStream(java.io.InputStream)
-     */
-    public InputStream getSmartInputStream(InputStream is)
-        throws GeneralSecurityException, IOException
-    {
-        return this.getSmartInputStream(
-            is,
-            PasswordFactory.create()
-            );
+        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[])
+     * 
+     * 
      */
     public InputStream getSmartInputStream(InputStream is, char[] password )
         throws GeneralSecurityException, IOException
@@ -219,28 +164,10 @@
     }
 
     /**
-     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getOutputStream(java.io.OutputStream)
-     */
-    public OutputStream getOutputStream( OutputStream os )
-        throws GeneralSecurityException, IOException
-    {
-        Cipher cipher = this.createCipher( Cipher.ENCRYPT_MODE, PasswordFactory.create() );
-        return new CipherOutputStream( os, cipher );    }
-
-    /**
-     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getOutputStream(java.io.OutputStream, char[])
-     */
-    public OutputStream getOutputStream( OutputStream os, char[] password )
-        throws GeneralSecurityException, IOException
-    {
-        Cipher cipher = this.createCipher( Cipher.ENCRYPT_MODE, password );
-        return new CipherOutputStream( os, cipher );
-    }
-
-    /**
      * @return Returns the algorithm.
      */
-    private String getAlgorithm()
+    @Override
+    public String getAlgorithm()
     {
         return algorithm;
     }
@@ -248,7 +175,7 @@
     /**
      * @return Returns the count.
      */
-    private int getCount()
+    protected int getCount()
     {
         return count;
     }
@@ -256,7 +183,7 @@
     /**
      * @return Returns the providerName.
      */
-    private String getProviderName()
+    protected String getProviderName()
     {
         return providerName;
     }
@@ -264,7 +191,7 @@
     /**
      * @return Returns the salt.
      */
-    private byte [] getSalt()
+    protected byte [] getSalt()
     {
         return salt;
     }
@@ -276,7 +203,7 @@
      * @return the key
      * @throws GeneralSecurityException creating the key failed
      */
-    private Key createKey( char[] password )
+    protected Key createKey( char[] password )
         throws GeneralSecurityException
     {
         SecretKeyFactory keyFactory;
@@ -304,7 +231,7 @@
      * @throws GeneralSecurityException creating a cipher failed
      * @throws IOException creating a cipher failed
      */
-    private Cipher createCipher( int mode, char[] password )
+    protected Cipher createCipher( int mode, char[] password )
         throws GeneralSecurityException, IOException
     {
         Cipher cipher;
diff --git a/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactoryTemplate.java b/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactoryTemplate.java
new file mode 100644
index 0000000..17e6f89
--- /dev/null
+++ b/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactoryTemplate.java
@@ -0,0 +1,171 @@
+package org.apache.fulcrum.jce.crypto;
+
+/*
+ * 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.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+
+/**
+ * Concrete factory for creating encrypting/decrypting streams. The
+ * implementation uses the JCA (Java Crypto Extension) supplied
+ * by SUN (using SunJCE 1.42).
+ *
+ * The implementation uses as PBEWithMD5AndDES for encryption which
+ * should be sufficent for most applications.
+ *
+ * The implementation also supplies a default password in the case that
+ * the programmer don't want to have additional hassles. It is easy to
+ * reengineer the password being used but much better than a hard-coded
+ * password in the application.
+ *
+ * The code uses parts from Markus Hahn's Blowfish library found at
+ * http://blowfishj.sourceforge.net/
+ *
+ * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl </a>
+ * @author <a href="mailto:maakus@earthlink.net">Markus Hahn</a>
+ */
+
+public abstract class CryptoStreamFactoryTemplate implements CryptoStreamFactory
+{
+
+    /** the default instance */
+    protected static CryptoStreamFactory instance;
+    
+    public static CryptoStreamFactory getInstance() 
+    {
+        return instance;
+    }
+
+    public static void setInstance(CryptoStreamFactory instance) 
+    {
+        CryptoStreamFactoryTemplate.instance = instance;
+    }
+
+    /**
+     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getInputStream(java.io.InputStream, String)
+     */
+    public InputStream getInputStream(InputStream is, String decryptionMode) throws GeneralSecurityException, IOException 
+    {
+
+        InputStream result = null;
+
+        if( "auto".equalsIgnoreCase(decryptionMode) )
+        {
+            result = getSmartInputStream(is);
+        }
+        else if( "true".equalsIgnoreCase(decryptionMode) )
+        {
+            result = getInputStream(is);
+        }
+        else
+        {
+            result = is;
+        }
+        return result;
+    }
+
+    /**
+     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getInputStream(java.io.InputStream, String, char[])
+     */
+    public InputStream getInputStream(InputStream is, String decryptionMode, char[] password) throws GeneralSecurityException, IOException 
+    {
+
+        InputStream result = null;
+
+        if( "auto".equalsIgnoreCase(decryptionMode) )
+        {
+            result = getSmartInputStream(is, password);
+        }
+        else if( "true".equalsIgnoreCase(decryptionMode) )
+        {
+            result = getInputStream(is, password);
+        }
+        else
+        {
+            result = is;
+        }
+        return result;
+    }
+
+    /**
+     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getInputStream(java.io.InputStream)
+     */
+    public InputStream getInputStream( InputStream is )
+        throws GeneralSecurityException, IOException
+    {
+        Cipher cipher = this.createCipher( Cipher.DECRYPT_MODE, PasswordFactory.getInstance().create() );
+        return new CipherInputStream( is, cipher );
+    }
+
+    /**
+     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getInputStream(java.io.InputStream,char[])
+     */
+    public InputStream getInputStream( InputStream is, char[] password )
+        throws GeneralSecurityException, IOException
+    {
+        Cipher cipher = this.createCipher( Cipher.DECRYPT_MODE, password );
+        return new CipherInputStream( is, cipher );
+    }
+
+    /**
+     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getSmartInputStream(java.io.InputStream)
+     */
+    public InputStream getSmartInputStream(InputStream is)
+        throws GeneralSecurityException, IOException
+    {
+        return this.getSmartInputStream(
+            is,
+            PasswordFactory.getInstance().create()
+            );
+    }
+
+    /**
+     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getSmartInputStream(java.io.InputStream,char[])
+     */
+    public abstract InputStream getSmartInputStream(InputStream is, char[] password )
+        throws GeneralSecurityException, IOException;
+
+    /**
+     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getOutputStream(java.io.OutputStream)
+     */
+    public OutputStream getOutputStream( OutputStream os )
+        throws GeneralSecurityException, IOException
+    {
+        Cipher cipher = this.createCipher( Cipher.ENCRYPT_MODE, PasswordFactory.getInstance().create() );
+        return new CipherOutputStream( os, cipher );    }
+
+    /**
+     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getOutputStream(java.io.OutputStream, char[])
+     */
+    public OutputStream getOutputStream( OutputStream os, char[] password )
+        throws GeneralSecurityException, IOException
+    {
+        Cipher cipher = this.createCipher( Cipher.ENCRYPT_MODE, password );
+        return new CipherOutputStream( os, cipher );
+    }
+    protected abstract Cipher createCipher(int encryptMode, char[] password) throws GeneralSecurityException, IOException;
+
+}
diff --git a/src/java/org/apache/fulcrum/jce/crypto/CryptoUtil.java b/src/java/org/apache/fulcrum/jce/crypto/CryptoUtil.java
index 153d905..7272f76 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/CryptoUtil.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/CryptoUtil.java
@@ -19,13 +19,16 @@
  * under the License.
  */
 
-
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 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.
  *
@@ -36,168 +39,236 @@
  * @author <a href="mailto:maakus@earthlink.net">Markus Hahn</a>
  */
 
-public final class CryptoUtil
-{
+public class CryptoUtil {
+
+    /** the default instance */
+    private static CryptoUtil instance;
+    
+    
+    protected CryptoStreamFactory cryptoStreamFactory;
+    
+    /**
+     * Factory method to get a default instance
+     * 
+     * @return an instance of the CryptoUtil
+     */
+    public synchronized static CryptoUtil getInstance() {
+        if (CryptoUtil.instance == null) {
+            CryptoUtil.instance = new CryptoUtil();
+        }
+
+        return CryptoUtil.instance;
+    }
+    
+    /**
+     * 
+     */
+    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
      *
-     * @param source the source object
-     * @param target the target object
+     * @param source   the source object
+     * @param target   the target object
      * @param password the password to use for encryption
      * @throws GeneralSecurityException accessing JCE failed
-     * @throws IOException accessing the souce failed
+     * @throws IOException              accessing the souce failed
      *
      */
-    public static void encrypt( Object source, Object target, char[] password )
-        throws GeneralSecurityException, IOException
-    {
-        CryptoUtil.encrypt(
-            CryptoUtil.getCryptoStreamFactory(),
-            source,
-            target,
-            password
-            );
+    public void encrypt(Object source, Object target, char[] password) throws GeneralSecurityException, IOException {
+        encrypt(getCryptoStreamFactory(), source, target, password);
     }
 
     /**
-     * Copies from a source to a target object using encryption and a
-     * caller supplied CryptoStreamFactory.
+     * Copies from a source to a target object using encryption and a caller
+     * supplied CryptoStreamFactory.
      *
-     * @param factory the factory to create the crypto streams
-     * @param source the source object
-     * @param target the target object
+     * @param factory  the factory to create the crypto streams
+     * @param source   the source object
+     * @param target   the target object
      * @param password the password to use for encryption
      * @throws GeneralSecurityException accessing JCE failed
-     * @throws IOException accessing the souce failed
+     * @throws IOException              accessing the souce failed
      */
-    public static void encrypt(
-        CryptoStreamFactory factory, Object source, Object target, char[] password )
-        throws GeneralSecurityException, IOException
-    {
-        InputStream is = StreamUtil.createInputStream( source );
-        OutputStream os = StreamUtil.createOutputStream( target );
-        OutputStream eos = factory.getOutputStream( os, password );
-        StreamUtil.copy( is, eos );
+    public void encrypt(CryptoStreamFactory factory, Object source, Object target, char[] password)
+            throws GeneralSecurityException, IOException {
+        InputStream is = StreamUtil.createInputStream(source);
+        OutputStream os = StreamUtil.createOutputStream(target);
+        OutputStream eos = factory.getOutputStream(os, password);
+        StreamUtil.copy(is, eos);
     }
 
+    
+    /**
+     * 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
+     * @return the encrypted string
+     * @throws GeneralSecurityException accessing JCE failed
+     * @throws IOException              accessing the souce failed
+     */
+    public String encryptStringWithClearCode(String plainText, char[] password) throws GeneralSecurityException, IOException {
+        return encryptString(getCryptoStreamFactory(), plainText, password, true);
+    }
+
+    /**
+     * Encrypts a string into a hex string.
+     *
+     * @param plainText the plain text to be encrypted
+     * @param password  the password for encryption
+     * @return the encrypted string
+     * @throws GeneralSecurityException accessing JCE failed
+     * @throws IOException              accessing the souce failed
+     */
+    public String encryptString(String plainText, char[] password) throws GeneralSecurityException, IOException {
+        return encryptString(getCryptoStreamFactory(), plainText, password, false);
+    }
+
+    /**
+     * Encrypts a string into a hex string.
+     *
+     * @param factory   the factory to create the crypto streams
+     * @param plainText the plain text to be encrypted
+     * @param password  the password for encryption
+     * @param withClearCode boolean to indicate, that a string containing how it was decoded is included
+     * @return the encrypted string
+     * @throws GeneralSecurityException accessing JCE failed
+     * @throws IOException              accessing the souce failed
+     */
+    public String encryptString(CryptoStreamFactory factory, String plainText, char[] password, boolean withClearCode)
+            throws GeneralSecurityException, IOException {
+        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());
+    }
+    
     /**
      * Copies from a source to a target object using decryption.
      *
-     * @param source the source object
-     * @param target the target object
+     * @param source   the source object
+     * @param target   the target object
      * @param password the password to use for decryption
      * @throws GeneralSecurityException accessing JCE failed
-     * @throws IOException accessing the souce failed
+     * @throws IOException              accessing the souce failed
      */
-    public static void decrypt( Object source, Object target, char[] password )
-        throws GeneralSecurityException, IOException
-    {
-        CryptoUtil.decrypt(
-            CryptoUtil.getCryptoStreamFactory(),
-            source,
-            target,
-            password
-            );
+    public void decrypt(Object source, Object target, char[] password) throws GeneralSecurityException, IOException {
+        decrypt(getCryptoStreamFactory(), source, target, password);
+    }
+    
+    /**
+     * 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_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
+     * @return the decrypted string
+     * @throws GeneralSecurityException accessing JCE failed
+     * @throws IOException              accessing the souce failed
+     */
+    public String decryptStringWithClearCode(String cipherText, char[] password) throws GeneralSecurityException, IOException {
+        return decryptString(getCryptoStreamFactory(), cipherText.substring(10), password);
     }
 
     /**
-     * Copies from a source to a target object using decryption and a
-     * caller-suppier CryptoStreamFactory.
+     * Decrypts an encrypted string into the plain text. The encrypted string must
+     * be a hex string created by encryptString.
      *
-     * @param factory the factory to create the crypto streams
-     * @param source the source object
-     * @param target the target object
+     * @param cipherText the encrypted text to be decrypted
+     * @param password   the password for decryption
+     * @return the decrypted string
+     * @throws GeneralSecurityException accessing JCE failed
+     * @throws IOException              accessing the souce failed
+     */
+    public String decryptString(String cipherText, char[] password) throws GeneralSecurityException, IOException {
+        return decryptString(getCryptoStreamFactory(), cipherText, password);
+    }
+    
+    /**
+     * Decrypts an encrypted string into the plain text. The encrypted string must
+     * be a hex string created by encryptString.
+     *
+     * @param cipherText the encrypted text to be decrypted
+     * @param password   the password for decryption
+     * @param withClearCode boolean to indicate, that a string containing how it was decoded was included during encryption
+     * @return the decrypted string
+     * @throws GeneralSecurityException accessing JCE failed
+     * @throws IOException              accessing the souce failed
+     */
+    public String decryptString(String cipherText, char[] password, boolean withClearCode) throws GeneralSecurityException, IOException {
+        return decryptString(getCryptoStreamFactory(), withClearCode?
+                cipherText.substring(CryptoParametersJ8.CLEAR_CODE_DEFAULT.length()):
+                cipherText, password);
+    }
+
+    /**
+     * Copies from a source to a target object using decryption and a caller-suppier
+     * CryptoStreamFactory.
+     *
+     * @param factory  the factory to create the crypto streams
+     * @param source   the source object
+     * @param target   the target object
      * @param password the password to use for decryption
      * @throws GeneralSecurityException accessing JCE failed
-     * @throws IOException accessing the souce failed
+     * @throws IOException              accessing the souce failed
      */
-    public static void decrypt(
-        CryptoStreamFactory factory, Object source, Object target, char[] password )
-        throws GeneralSecurityException, IOException
-    {
-        InputStream is = StreamUtil.createInputStream( source );
-        OutputStream os = StreamUtil.createOutputStream( target );
-        InputStream dis = factory.getInputStream( is, password );
-        StreamUtil.copy( dis, os );
+    protected void decrypt(CryptoStreamFactory factory, Object source, Object target, char[] password)
+            throws GeneralSecurityException, IOException {
+        InputStream is = StreamUtil.createInputStream(source);
+        OutputStream os = StreamUtil.createOutputStream(target);
+        InputStream dis = factory.getInputStream(is, password);
+        StreamUtil.copy(dis, os);
     }
 
     /**
-     * Encrypts a string into a hex string.
+     * Decrypts an encrypted string into the plain text. The encrypted string must
+     * be a hex string created by encryptString.
      *
-     * @param plainText the plain text to be encrypted
-     * @param password the password for encryption
-     * @return the encrypted string
-     * @throws GeneralSecurityException accessing JCE failed
-     * @throws IOException accessing the souce failed
-     */
-    public static String encryptString( String plainText, char[] password )
-        throws GeneralSecurityException, IOException
-    {
-        return CryptoUtil.encryptString(
-            CryptoUtil.getCryptoStreamFactory(),
-            plainText,
-            password
-            );
-    }
-
-    /**
-     * Encrypts a string into a hex string.
-     *
-     * @param factory the factory to create the crypto streams
-     * @param plainText the plain text to be encrypted
-     * @param password the password for encryption
-     * @return the encrypted string
-     * @throws GeneralSecurityException accessing JCE failed
-     * @throws IOException accessing the souce failed
-     */
-    public static String encryptString(
-        CryptoStreamFactory factory, String plainText, char[] password )
-        throws GeneralSecurityException, IOException
-    {
-        ByteArrayOutputStream bais = new ByteArrayOutputStream();
-        CryptoUtil.encrypt( factory, plainText, bais, password );
-        return HexConverter.toString( bais.toByteArray() );
-    }
-
-    /**
-     * Decrypts an encrypted string into the plain text. The encrypted
-     * string must be a hex string created by encryptString.
-     *
+     * @param factory    the factory to create the crypto streams
      * @param cipherText the encrypted text to be decrypted
-     * @param password the password for decryption
+     * @param password   the password for decryption
      * @return the decrypted string
      * @throws GeneralSecurityException accessing JCE failed
-     * @throws IOException accessing the souce failed
+     * @throws IOException              accessing the souce failed
      */
-    public static String decryptString( String cipherText, char[] password )
-        throws GeneralSecurityException, IOException
-    {
-        return CryptoUtil.decryptString(
-            CryptoUtil.getCryptoStreamFactory(),
-            cipherText,
-            password
-            );
-    }
-
-    /**
-     * Decrypts an encrypted string into the plain text. The encrypted
-     * string must be a hex string created by encryptString.
-     *
-     * @param factory the factory to create the crypto streams
-     * @param cipherText the encrypted text to be decrypted
-     * @param password the password for decryption
-     * @return the decrypted string
-     * @throws GeneralSecurityException accessing JCE failed
-     * @throws IOException accessing the souce failed
-     */
-    public static String decryptString(
-        CryptoStreamFactory factory, String cipherText, char[] password )
-        throws GeneralSecurityException, IOException
-    {
-        byte[] buffer = HexConverter.toBytes( cipherText );
+    public String decryptString(CryptoStreamFactory factory, String cipherText, char[] password)
+            throws GeneralSecurityException, IOException {
+        byte[] buffer = HexConverter.toBytes(cipherText);
         ByteArrayOutputStream bais = new ByteArrayOutputStream();
-        CryptoUtil.decrypt( factory, buffer, bais, password );
-        return new String( bais.toByteArray(), "utf-8" );
+        decrypt(factory, buffer, bais, password);
+        return new String(bais.toByteArray(), "utf-8");
     }
 
     /**
@@ -209,17 +280,15 @@
      * @throws IOException the copying failed
      * @deprecated use StreamUtil instead
      */
-    public static long copy( InputStream is, OutputStream os )
-        throws IOException
-    {
+    public static long copy(InputStream is, OutputStream os) throws IOException {
         return StreamUtil.copy(is, os);
     }
 
     /**
      * @return the CryptoStreamFactory to be used
      */
-    public static CryptoStreamFactory getCryptoStreamFactory()
-    {
-        return CryptoStreamFactoryImpl.getInstance();
+    public CryptoStreamFactory getCryptoStreamFactory() {
+        return cryptoStreamFactory;
     }
+    
 }
diff --git a/src/java/org/apache/fulcrum/jce/crypto/PasswordFactory.java b/src/java/org/apache/fulcrum/jce/crypto/PasswordFactory.java
index c96713a..1668d20 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/PasswordFactory.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/PasswordFactory.java
@@ -39,6 +39,68 @@
 public class PasswordFactory implements PasswordParameters
 {
 
+    private static PasswordFactory instance;
+    
+    String algo;
+    
+    int count = PasswordParameters.COUNT;
+    
+    public PasswordFactory(String algo) {
+       this.algo = algo;
+    }
+    
+    public PasswordFactory(String algo, int count) {
+        this.algo = algo;
+        this.count = count;
+     }
+      
+    /**
+     * Factory method to get a default instance
+     * @return an instance of the CryptoStreamFactory
+     */
+    public synchronized static PasswordFactory getInstance() 
+    {
+        if( PasswordFactory.instance == null )
+        {
+           PasswordFactory.instance = new PasswordFactory("SHA1");
+        }
+
+        return PasswordFactory.instance;
+    }
+    
+    /**
+     * Factory method to get a default instance
+     * 
+     * @param algo algorithm
+     * @return an instance of the CryptoStreamFactory
+     */
+    public synchronized static PasswordFactory getInstance(String algo) 
+    {
+        if( PasswordFactory.instance == null )
+        {
+           PasswordFactory.instance = new PasswordFactory(algo);
+        }
+
+        return PasswordFactory.instance;
+    }
+    
+    /**
+     * Factory method to get a default instance
+     * 
+     * @param algo algorithm
+     * @param count the number of MessageDigest iterations
+     * @return an instance of the CryptoStreamFactory
+     */
+    public synchronized static PasswordFactory getInstance(String algo, int count) 
+    {
+        if( PasswordFactory.instance == null )
+        {
+           PasswordFactory.instance = new PasswordFactory(algo, count);
+        }
+
+        return PasswordFactory.instance;
+    }
+    
     /**
      * Create a new password
      * 
@@ -47,13 +109,13 @@
      * @throws NoSuchAlgorithmException the encryption algorithm is not supported
      * @throws UnsupportedEncodingException the requested encoding is not supported
      */
-    public static char[] create()
+    public char[] create()
         throws NoSuchAlgorithmException, UnsupportedEncodingException
     {
         return create(
-            PasswordParameters.DEFAULTPASSWORD,
-            PasswordParameters.SALT,
-            PasswordParameters.COUNT
+            PasswordParameters.DefaultPassword(),
+            PasswordParameters.Salt(),
+            count
             );
     }
 
@@ -66,7 +128,7 @@
      * @throws NoSuchAlgorithmException the encryption algorithm is not supported
      * @throws UnsupportedEncodingException the requested encoding is not supported
      */
-    public static char[] create( String seed )
+    public char[] create( String seed )
         throws NoSuchAlgorithmException, UnsupportedEncodingException
     {
         return create(
@@ -80,13 +142,13 @@
      * @throws NoSuchAlgorithmException the encryption algorithm is not supported
      * @throws UnsupportedEncodingException the requested encoding is not supported
      */
-    public static final char[] create( char[] seed )
+    public final char[] create( char[] seed )
         throws NoSuchAlgorithmException, UnsupportedEncodingException
     {
         return create(
             seed,
-            PasswordFactory.SALT,
-            PasswordFactory.COUNT
+            PasswordParameters.Salt(),
+            count
             );
     }
 
@@ -100,11 +162,11 @@
      * @throws NoSuchAlgorithmException the encryption algorithm is not supported
      * @throws UnsupportedEncodingException the requested encoding is not supported
      */
-    public static char [] create( char[] password, byte[] salt, int count )
+    public char [] create( char[] password, byte[] salt, int count )
         throws NoSuchAlgorithmException, UnsupportedEncodingException
     {
         char [] result = null;
-        MessageDigest sha1 = MessageDigest.getInstance( "SHA1" );
+        MessageDigest sha1 = MessageDigest.getInstance( algo );
         byte [] passwordMask = new String( password ).getBytes( "UTF-8" );
         byte [] temp = new byte[salt.length + passwordMask.length];
         byte [] digest = null;
diff --git a/src/java/org/apache/fulcrum/jce/crypto/PasswordParameters.java b/src/java/org/apache/fulcrum/jce/crypto/PasswordParameters.java
index efb5022..2836a78 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/PasswordParameters.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/PasswordParameters.java
@@ -27,20 +27,29 @@
 
 public interface PasswordParameters
 {
-    /** Parameter for the number of SHA1 invocation */
-    int COUNT = 20;
+    /** Parameter for the number of SHA256 invocation */
+    int COUNT = 1000;
 
-    /** The default password used for creating the internal password */
-    char[] DEFAULTPASSWORD = {
+    /** 
+     * The default password used for creating the internal password 
+     * @return the default password: <code>fulcrum-yaafi</code>.
+     * */
+    public static char[] DefaultPassword() { 
+    	return new char[] {
         (char) 'f', (char) 'u', (char) 'l', (char) 'c',
         (char) 'r', (char) 'u', (char) 'm', (char) '-',
         (char) 'y', (char) 'a', (char) 'a', (char) 'f',
         (char) 'i'
         };
+    }
 
-    /** The password salt */
-    byte[] SALT = {
+    /** The password salt 
+     * @return the 8bit default salt as byte array
+     * */
+    public static byte[] Salt() {
+    	return new byte[] {
         (byte)0xc6, (byte)0x74, (byte)0x81, (byte)0x8a,
         (byte)0x7b, (byte)0xe8, (byte)0xfe, (byte)0x99
         };
+    }
 }
diff --git a/src/java/org/apache/fulcrum/jce/crypto/SmartDecryptingInputStream.java b/src/java/org/apache/fulcrum/jce/crypto/SmartDecryptingInputStream.java
index 1521134..58a3ce9 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/SmartDecryptingInputStream.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/SmartDecryptingInputStream.java
@@ -115,7 +115,7 @@
 
     /**
      * Determine if the content is encrypted. We are
-     * using our knowledge about block lenght, check
+     * using our knowledge about block length, check
      * for XML, ZIP and PDF files and at the end of
      * the day we are just guessing.
      *
@@ -227,8 +227,12 @@
      */
     private boolean hasByteOrderMark( byte[] content )
     {
-        if( ( (content[0] == 0xFF) && (content[1] == 0xFF) ) ||
-            ( (content[0] == 0xFF) && (content[1] == 0xFF) ) )
+        // bytes ar always signed in java, ff is 255
+        // removes signed parts
+        int firstUnsigned = content[0] & 0xFF;
+        int second = content[1] & 0xFF;
+        if( ((firstUnsigned == 0xFF) && (second == 0xFE)) ||
+                ((firstUnsigned == 0xFE) && (second == 0xFF)))
         {
             return true;
         }
diff --git a/src/java/org/apache/fulcrum/jce/crypto/StreamUtil.java b/src/java/org/apache/fulcrum/jce/crypto/StreamUtil.java
index fccd6d9..2ff5e41 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/StreamUtil.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/StreamUtil.java
@@ -180,7 +180,11 @@
         
         if((parentFile != null) && !parentFile.exists())
         {
-            parentFile.mkdirs();
+            boolean success = parentFile.mkdirs();
+            if ( !success )
+            {
+            	System.err.println("Error, could not create directory to write parent file");
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamGCMImpl.java b/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamGCMImpl.java
new file mode 100644
index 0000000..0fad268
--- /dev/null
+++ b/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamGCMImpl.java
@@ -0,0 +1,215 @@
+package org.apache.fulcrum.jce.crypto.algo;
+
+import java.io.ByteArrayOutputStream;
+
+/*
+ * 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.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+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;
+
+/**
+ * Concrete implementation for creating encrypting/decrypting streams. The
+ * implementation uses the JCA (Java Crypto Extension) supplied
+ * by SUN (using SunJCE 1.42).
+ *
+ * The implementation uses @see {@link CryptoParametersJ8.TYPES_IMPL#ALGORITHM_J8_GCM} for encryption which
+ * should be sufficent for most applications.
+ *
+ * The implementation also supplies a default password in the case that
+ * the programmer don't want to have additional hassles. It is easy to
+ * reengineer the password being used but much better than a hard-coded
+ * password in the application.
+ *
+ *
+ * @author <a href="mailto:gk@apache.org">Georg Kallidis</a>
+ * 
+ * The Implementation for {@link TYPES} GCM.
+ */
+
+public final class CryptoStreamGCMImpl extends CryptoStreamFactoryJ8Template
+{  
+
+    protected static final int IV_SIZE = 12;
+    
+    /**
+     * Constructor
+     * @throws GeneralSecurityException  - wraps {@link NoSuchAlgorithmException}
+     */
+    public CryptoStreamGCMImpl() throws GeneralSecurityException
+    {
+        this(generateSalt());
+    }
+
+
+    /**
+     * Constructor
+     *
+     * @param salt the salt for the GCM algorithm
+
+     */
+    public CryptoStreamGCMImpl( byte[] salt) 
+    {
+        setSalt(salt);
+        this.providerName = PROVIDERNAME;
+        setType(TYPES.GCM);
+        this.algorithm = CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_GCM.getAlgorithm();
+    }
+
+    /**
+     * Create a AES/GCM key.
+     *
+     * @param password the password to use.
+     * @param salt if provided this is used, otherweise {@link #getSalt()}.
+     * @return the key
+     * @throws GeneralSecurityException if creating the key failed
+     */
+    @Override
+    protected Key createKey( char[] password, byte[] salt ) 
+            throws GeneralSecurityException
+    {
+        SecretKey key = new SecretKeySpec(((salt == null)? this.getSalt(): salt.clone()), "AES");
+        return key;
+    }
+
+    /**
+     * Create a Cipher.
+     * 
+     * Find additional information here: {@link GCMParameterSpec}
+     *
+     * @param mode the cipher mode
+     * @param password the password
+     * @return an instance of a cipher
+     * @throws GeneralSecurityException if creating a cipher failed
+     * @throws IOException creating a cipher failed
+     * 
+     */
+    @Override
+    protected byte[] createCipher(InputStream is, int mode, char[] password )
+        throws GeneralSecurityException, IOException
+    {
+        Cipher cipher;
+        
+        ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
+        StreamUtil.copy(is, bos);
+        byte[] input = bos.toByteArray();
+        
+        byte[] ciphertext = null;  
+        byte[] salt = null;
+        byte[] iv = null;
+        
+        if (mode == Cipher.DECRYPT_MODE) {   
+            
+            ByteBuffer byteBuffer = ByteBuffer.wrap(input);
+            salt = new byte[ SALT_SIZE ];
+            byteBuffer.get(salt);
+            iv = new byte[ IV_SIZE ];
+            byteBuffer.get(iv);
+            ciphertext = new byte[byteBuffer.remaining()];
+            byteBuffer.get(ciphertext);
+            
+//            salt = Arrays.copyOfRange(input, 0, SALT_SIZE );
+//            iv = Arrays.copyOfRange(input, salt.length, salt.length + 16 );
+//            ciphertext = Arrays.copyOfRange(input, salt.length + iv.length, input.length);// cut out salt and iv
+        }
+        
+        Key key = this.createKey( password, salt );
+        
+        if( this.getProviderName() == null )
+        {
+            cipher = Cipher.getInstance( this.getAlgorithm() );
+        }
+        else
+        {
+            cipher = Cipher.getInstance( this.getAlgorithm(), this.getProviderName() );
+        }
+        
+        // save
+        if (mode == Cipher.DECRYPT_MODE) {
+            
+            GCMParameterSpec gcmParamSpec = new GCMParameterSpec(128, iv);
+            cipher.init( mode, key, gcmParamSpec );
+            
+            //cipher.init( mode, key, algorithmParameters );
+            ciphertext = cipher.doFinal(ciphertext); // actually the unencrypted bytes
+        }
+        
+        // save
+        if (mode == Cipher.ENCRYPT_MODE) {        
+            iv = generateIV();
+            GCMParameterSpec gcmParamSpec = new GCMParameterSpec(128, iv);
+            
+            salt = this.getSalt();
+            cipher.init( mode, key, gcmParamSpec );
+
+            //algorithmParameters = cipher.getParameters();
+            // might update with associated Data
+            // cipher.updateAAD(associatedData );// not supported PBEWithHmacSHA256AndAES_256
+            
+            byte[] result = cipher.doFinal(input);
+            //iv = cipher.getIV(); // AES has 128bit block size, but iv is 16bit 
+           
+            // Salt and IV need to be stored with the result, otherwise we can't decrypt the message later.
+            ByteBuffer byteBuffer = ByteBuffer.allocate(salt.length + iv.length + result.length);
+            ciphertext = byteBuffer.put(salt).put(iv).put(result).array();
+            
+//            ciphertext = new byte[salt.length + iv.length + result.length];
+//            
+//            System.arraycopy(salt, 0, ciphertext, 0, salt.length);
+//            System.arraycopy(iv, 0, ciphertext, salt.length, iv.length);
+//            System.arraycopy(result, 0, ciphertext, salt.length + iv.length, result.length);// push after salt and iv  
+        }
+        return ciphertext;
+    }
+    
+    /**
+     * 
+     * @return the random byte array from {@link SecureRandom} SHA1PRNG (as default)
+     * @throws GeneralSecurityException - if creating the key failed
+     */
+    private byte[] generateIV( ) throws GeneralSecurityException {
+        SecureRandom random;
+        try {
+            random = SecureRandom.getInstance("SHA1PRNG");
+            byte[] iv = new byte[ IV_SIZE ];
+            random.nextBytes(iv);
+            return iv;
+        } catch (NoSuchAlgorithmException e) {
+            throw new GeneralSecurityException(e);  
+        }
+    }
+
+
+
+}
diff --git a/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamPBEImpl.java b/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamPBEImpl.java
new file mode 100644
index 0000000..adc1603
--- /dev/null
+++ b/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamPBEImpl.java
@@ -0,0 +1,242 @@
+package org.apache.fulcrum.jce.crypto.algo;
+
+import java.io.ByteArrayOutputStream;
+
+/*
+ * 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.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.apache.fulcrum.jce.crypto.StreamUtil;
+import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8;
+import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8.TYPES;
+import org.apache.fulcrum.jce.crypto.extended.CryptoStreamFactoryJ8Template;
+
+/**
+ * Concrete implementation for creating encrypting/decrypting streams. The
+ * implementation uses the JCA (Java Crypto Extension) supplied
+ * by SUN (using SunJCE 1.42).
+ *
+ * The implementation uses as @see {@link CryptoParametersJ8} ALGORITHM_J8_PBE for encryption which
+ * should be sufficient for most applications.
+ *
+ * The implementation also supplies a default password in the case that
+ * the programmer don't want to have additional hassles. It is easy to
+ * re-engineer the password being used but much better than a hard-coded
+ * password in the application.
+ *
+ * The code uses parts from Markus Hahn's Blowfish library found at
+ * http://blowfishj.sourceforge.net/
+ *
+ * @author <a href="mailto:gk@apache.org">Georg Kallidis</a>
+ * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl </a>
+ * @author <a href="mailto:maakus@earthlink.net">Markus Hahn</a>
+ * 
+ * The Implementation for {@link TYPES} PBE.
+ */
+
+public final class CryptoStreamPBEImpl extends CryptoStreamFactoryJ8Template
+{
+
+    protected static final int IV_SIZE = 16;
+    
+    protected static final int KEY_SIZE = 256;
+    
+	/**
+	 * default count for pbe spec
+	 */
+	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(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)
+    {
+        setSalt(salt);
+        this.count = count;
+        this.providerName = PROVIDERNAME;
+        setType(TYPES.PBE);
+        this.algorithm = CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_PBE.getAlgorithm();
+    }
+
+    /**
+     * Create a PBE key.
+     *
+     * @param password the password to use.
+     * @param salt if provided this is used, otherweise {@link #getSalt()}.
+     * @return the key
+     * @throws GeneralSecurityException if creating the key failed
+     */
+    @Override
+    protected Key createKey( char[] password, byte[] salt ) 
+            throws GeneralSecurityException
+    {
+        SecretKeyFactory keyFactory;
+        String algorithm = this.getAlgorithm();
+        
+        PBEKeySpec keySpec = new PBEKeySpec(password, (salt == null)? this.getSalt(): salt.clone(), this.getCount(), KEY_SIZE );
+
+        byte[] encodedTmp = null;
+        try {
+            if( this.getProviderName() == null )
+            {
+                keyFactory = SecretKeyFactory.getInstance( algorithm );
+            }
+            else
+            {
+                keyFactory = SecretKeyFactory.getInstance( algorithm, this.getProviderName() );
+            }
+            return keyFactory.generateSecret(keySpec);
+            
+        } catch (NoSuchAlgorithmException e) {
+            throw new GeneralSecurityException(e);
+        } finally {
+            if (encodedTmp != null) {
+                Arrays.fill(encodedTmp, (byte)0); 
+            }
+            if (keySpec != null) {
+                keySpec.clearPassword();
+            }
+        }
+    }
+
+    /**
+     * Create a Cipher.
+     * 
+     * Find additional information here: {@link PBEParameterSpec}.
+     *
+     * @param mode the cipher mode
+     * @param password the password
+     * @return an instance of a cipher
+     * @throws GeneralSecurityException creating a cipher failed
+     * @throws IOException creating a cipher failed
+
+     */
+    @Override
+    protected byte[] createCipher(InputStream is, int mode, char[] password )
+        throws GeneralSecurityException, IOException
+    {
+        Cipher cipher;
+        PBEParameterSpec paramSpec = null; 
+        
+        ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
+        StreamUtil.copy(is, bos);
+        byte[] input = bos.toByteArray();
+        
+        byte[] ciphertext = null;
+        
+        byte[] salt = null;
+        byte[] iv = null;
+        if (mode == Cipher.DECRYPT_MODE) {   
+            
+            ByteBuffer byteBuffer = ByteBuffer.wrap(input);
+            salt = new byte[SALT_SIZE ];
+            byteBuffer.get(salt);
+            iv = new byte[ IV_SIZE ];
+            byteBuffer.get(iv);
+            ciphertext = new byte[byteBuffer.remaining()];
+            byteBuffer.get(ciphertext);
+            
+//            salt = Arrays.copyOfRange(input, 0, SALT_SIZE );
+//            iv = Arrays.copyOfRange(input, salt.length, salt.length + 16 );
+//            ciphertext = Arrays.copyOfRange(input, salt.length + iv.length, input.length);// cut out salt and iv
+        }
+        
+        Key key = this.createKey( password, salt );
+        
+        if( this.getProviderName() == null )
+        {
+            cipher = Cipher.getInstance( this.getAlgorithm() );
+        }
+        else
+        {
+            cipher = Cipher.getInstance( this.getAlgorithm(), this.getProviderName() );
+        }
+        
+        // save
+        if (mode == Cipher.DECRYPT_MODE) {
+           
+            paramSpec = new PBEParameterSpec( salt, this.getCount(), new IvParameterSpec(iv) );
+     
+            cipher.init( mode, key, paramSpec );
+            //cipher.init( mode, key, algorithmParameters );
+            ciphertext = cipher.doFinal(ciphertext); // actually the unencrypted bytes
+        }
+        
+        // save
+        if (mode == Cipher.ENCRYPT_MODE) {        
+            paramSpec = new PBEParameterSpec( this.getSalt(), this.getCount() );
+            salt = paramSpec.getSalt();
+            cipher.init( mode, key, paramSpec );   
+            //algorithmParameters = cipher.getParameters();
+ 
+            byte[] result = cipher.doFinal(input);
+            iv = cipher.getIV(); // AES has 128bit block size, but iv is 16bit 
+           
+            // Salt and IV need to be stored with the result, otherwise we can't decrypt the message later.
+            ByteBuffer byteBuffer = ByteBuffer.allocate(salt.length + iv.length + result.length);
+            ciphertext = byteBuffer.put(salt).put(iv).put(result).array();
+            
+//            ciphertext = new byte[salt.length + iv.length + result.length];         
+//            System.arraycopy(salt, 0, ciphertext, 0, salt.length);
+//            System.arraycopy(iv, 0, ciphertext, salt.length, iv.length);
+//            System.arraycopy(result, 0, ciphertext, salt.length + iv.length, result.length);// push after salt and iv  
+        }
+        return ciphertext;
+    }
+
+}
diff --git a/src/test/org/apache/fulcrum/jce/crypto/Main.java b/src/java/org/apache/fulcrum/jce/crypto/cli/CLI.java
similarity index 62%
rename from src/test/org/apache/fulcrum/jce/crypto/Main.java
rename to src/java/org/apache/fulcrum/jce/crypto/cli/CLI.java
index c4488ec..9394b5f 100644
--- a/src/test/org/apache/fulcrum/jce/crypto/Main.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/cli/CLI.java
@@ -1,4 +1,4 @@
-package org.apache.fulcrum.jce.crypto;
+package org.apache.fulcrum.jce.crypto.cli;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -25,6 +25,9 @@
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 
+import org.apache.fulcrum.jce.crypto.CryptoUtil;
+import org.apache.fulcrum.jce.crypto.StreamUtil;
+
 /**
  * Command line tool for encrypting/decrypting files
  *
@@ -34,7 +37,7 @@
  * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
  */
 
-public class Main
+public class CLI
 {
     /**
      * Allows testing on the command line.
@@ -74,7 +77,7 @@
     public static void printHelp()
     {
         System.out.println("Main file [enc|dec] passwd source [target]");
-        System.out.println("Main string [enc|dec] passwd ");
+        System.out.println("Main string [enc|dec] passwd source");
     }
 
     /**
@@ -99,9 +102,13 @@
             targetFile = new File(args[4]);
             File parentFile = targetFile.getParentFile(); 
 
-            if(parentFile != null)
+            if (parentFile != null)
             {
-                parentFile.mkdirs();
+                boolean success = parentFile.mkdirs();
+                if ( !success )
+                {
+                	System.err.println("Failed to create directory");
+                }
             }
         }
 
@@ -109,47 +116,48 @@
     }
 
     /**
-     * Decrypt/encrypt a single file
+     * Decrypt and encrypt a single file
      * @param cipherMode the mode
-     * @param password the passwors
+     * @param password the password
      * @param sourceFile the file to process
-     * @param targetFile the targetf file
+     * @param targetFile the target file
      * @throws Exception the operation failed
      */
     public static void processFile(String cipherMode, char[] password, File sourceFile, File targetFile)
         throws Exception
     {
-        FileInputStream fis = new FileInputStream(sourceFile);
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
-        if( cipherMode.equals("dec") )
-        {
-            System.out.println("Decrypting " + sourceFile.getAbsolutePath() );
-            CryptoUtil.decrypt( fis, baos, password );
-            fis.close();
-
-            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-            FileOutputStream fos = new FileOutputStream(targetFile);
-            CryptoUtil.copy(bais,fos);
-            bais.close();
-            fos.close();
-        }
-        else if( cipherMode.equals("enc") )
-        {
-            System.out.println("Enrypting " + sourceFile.getAbsolutePath() );
-            CryptoUtil.encrypt( fis, baos, password );
-            fis.close();
-
-            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-            FileOutputStream fos = new FileOutputStream(targetFile);
-            CryptoUtil.copy(bais,fos);
-            bais.close();
-            fos.close();
-        }
-        else
-        {
-            String msg = "Don't know what to do with : " + cipherMode;
-            throw new IllegalArgumentException(msg);
+        try (FileInputStream fis = new FileInputStream(sourceFile)) {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    
+            if( cipherMode.equals("dec") )
+            {
+                System.out.println("Decrypting " + sourceFile.getAbsolutePath() );
+                CryptoUtil.getInstance().decrypt( 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 if( cipherMode.equals("enc") )
+            {
+                System.out.println("Encrypting " + sourceFile.getAbsolutePath() );
+                CryptoUtil.getInstance().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);
+            }
         }
     }
 
@@ -169,11 +177,11 @@
 
         if( cipherMode.equals("dec") )
         {
-            result = CryptoUtil.decryptString(value,password);
+            result = CryptoUtil.getInstance().decryptString(value,password);
         }
         else
         {
-            result = CryptoUtil.encryptString(value,password);
+            result = CryptoUtil.getInstance().encryptString(value,password);
         }
 
         System.out.println( result );
diff --git a/src/java/org/apache/fulcrum/jce/crypto/cli/CLI2.java b/src/java/org/apache/fulcrum/jce/crypto/cli/CLI2.java
new file mode 100644
index 0000000..84ad218
--- /dev/null
+++ b/src/java/org/apache/fulcrum/jce/crypto/cli/CLI2.java
@@ -0,0 +1,380 @@
+package org.apache.fulcrum.jce.crypto.cli;
+
+/*
+ * 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.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+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;
+import java.util.stream.Collectors;
+
+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
+ * 
+ * Example :
+ * 
+ * <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 java -jar target/fulcrum-yaafi-crypto-1.0.8.jar string dec changeit anothersecret
+ * </pre>
+ * 
+ *  @author gk@apache.org
+ *
+ */
+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];
+
+			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");
+			}
+
+			if (operationMode.equals("file")) {
+				processFiles(args);
+			} else if (operationMode.equals("string")) {
+				processString(args);
+			}
+		} catch (Exception e) {
+			System.out.println("Error : " + e.getMessage());
+			e.printStackTrace();
+		}
+	}
+
+	private static void printInfo() {
+		CryptoUtilJ8 cryptoUtilJ8 = CryptoUtilJ8.getInstance();
+		System.out.println("");
+		System.out.println("\t| Default 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("");
+		if (debug) {
+			Arrays.stream(CryptoParametersJ8.TYPES.values()).forEach(t -> {
+				CryptoUtilJ8 testcu = CryptoUtilJ8.getInstance(t);
+				System.out.println("\t| Crypto factory class: \t" + testcu.getCryptoStreamFactory().getClass());
+				System.out.println("\t|_Algorithm used: \t" + testcu.getCryptoStreamFactory().getAlgorithm());
+
+			});
+		}
+		System.out.println(
+				"\t|_ More Info: https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html\r\n");
+	}
+	
+
+	/**
+	 * 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-------------------");
+		System.out.println("\toperation mode: file|string|info");
+		System.out.println("\tcoding mode: enc|dec|enc:GCM. Default algorithm is " + TYPES.PBE);
+		System.out.println("\t<password: string or empty:''");
+		System.out.println("\tcode|coderef: path|string");
+		System.out.println("\ttarget: optional\r\n");
+		System.out.println("\t-------------------");
+		System.out.println("\t*** Usage: ***\r\n");
+		System.out.println("\t" + CLI2.class.getSimpleName() + " file [enc|dec] passwd source [target]");
+		System.out.println("\t" + CLI2.class.getSimpleName() + " string [enc|dec] passwd source");
+		System.out.println("\t" + CLI2.class.getSimpleName() + " info");
+	}
+
+	/**
+	 * 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 (args.length == 4) {
+			targetFile = sourceFile;
+		} else {
+			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");
+				}
+			}
+		}
+
+		processFile(cipherMode, password, sourceFile, targetFile);
+	}
+
+	/**
+	 * 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);
+			}
+		}
+	}
+
+	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();
+	}
+}
diff --git a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoParametersJ8.java b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoParametersJ8.java
new file mode 100644
index 0000000..152219a
--- /dev/null
+++ b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoParametersJ8.java
@@ -0,0 +1,192 @@
+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
+ * 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.
+ */
+
+/**
+ * CryptoParameters used for encryption/decryption.
+ *
+ * @author <a href="mailto:gk@apache.org">Georg Kallidis</a>
+ */
+
+public interface CryptoParametersJ8 {
+	
+	/**
+	 * 
+	 * Implementing classes are either using
+	 * 
+	 * <ul>
+	 * <li>PBEWith &lt;digest&gt;And&lt;encryption&gt; - the password-based encryption algorithm defined in PKCS #5: PBEWithHmacSHA256AndAES_256/CBC/PKCS5Padding in {@link #ALGORITHM_J8_PBE}</li>
+	 * </ul>
+	 * 
+	 * or
+	 * 
+	 * <ul>
+	 * <li>AES/GCM/NoPadding in {@link #ALGORITHM_J8_GCM} (Cipher Algorithm Names/Cipher Algorithm Modes/Cipher Algorithm Padding). Cipher is Galois/Counter Mode, as defined in NIST Special Publication SP 800-38D: </li>
+	 * </ul>
+	 * 
+	 * 
+	 * <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:
+	 * 
+	 * 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>
+	 * 
+	 * 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 {
+		
+		// key size 256
+		ALGORITHM_J8_PBE("PBEWithHmacSHA256AndAES_256"), 
+		// key size 128
+		ALGORITHM_J8_GCM("AES_128/GCM/NoPadding");
+
+		private final String algorithm;
+
+		private TYPES_IMPL(String algo) {
+			algorithm = algo;
+		}
+
+		@Override
+		public String toString() {
+			return this.algorithm;
+		}
+
+		public String getAlgorithm() {
+			return algorithm;
+		}
+		
+		/**
+		 * 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));
+		}
+	}
+
+	/**
+	 * 
+	 * short names, exact names @see {@link TYPES_IMPL}.
+	 *
+	 */
+	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/CryptoStreamFactoryJ8.java b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8.java
new file mode 100644
index 0000000..3d73493
--- /dev/null
+++ b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8.java
@@ -0,0 +1,50 @@
+package org.apache.fulcrum.jce.crypto.extended;
+
+/*
+ * 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.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
+
+import org.apache.fulcrum.jce.crypto.CryptoStreamFactory;
+
+/**
+ * Interface for creating encrypting/decrypting streams. 
+ *
+ * @author <a href="mailto:gk@apache.org">Georg Kallidis </a>
+ */
+
+public interface CryptoStreamFactoryJ8 extends CryptoStreamFactory
+{
+    /**
+     * Creates an encrypting output stream using the given password.
+     *
+     * @param is the input stream to be encoded
+     * @param os the output stream to be wrapped
+     * @param password the password to be used
+     * @return the encrypting output stream
+     * @throws GeneralSecurityException creating the output stream failed
+     * @throws IOException creating the output stream failed
+     */
+    OutputStream getOutputStream(InputStream is, OutputStream os, char[] password)
+        throws GeneralSecurityException, IOException;
+    
+}
diff --git a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8Template.java b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8Template.java
new file mode 100644
index 0000000..7de7f52
--- /dev/null
+++ b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8Template.java
@@ -0,0 +1,340 @@
+package org.apache.fulcrum.jce.crypto.extended;
+
+/*
+ * 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.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.crypto.Cipher;
+
+import org.apache.fulcrum.jce.crypto.PasswordFactory;
+import org.apache.fulcrum.jce.crypto.StreamUtil;
+import org.apache.fulcrum.jce.crypto.algo.CryptoStreamGCMImpl;
+import org.apache.fulcrum.jce.crypto.algo.CryptoStreamPBEImpl;
+import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8.TYPES;
+
+/**
+ * Concrete factory for creating encrypting/decrypting streams. 
+ * 
+ * 
+ **/
+public abstract class CryptoStreamFactoryJ8Template /*  extends CryptoStreamFactoryImpl*/ implements CryptoStreamFactoryJ8
+{
+	
+	/** the salt for the algorithm */
+    protected byte[] salt;
+
+    /** the count parameter for the algorithm, not used for GCM */
+    protected int count;
+
+    /** the name of the JCE provider */
+    protected String providerName;
+
+    /** 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
+     * used.
+     */
+    protected static final String PROVIDERNAME = null;
+
+    protected static final int SALT_SIZE = 16; //might increase cipher length
+
+    /** the default instances */
+    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
+     * 
+     * @param type the @see {@link TYPES} of the instance.
+     * @return an instance of the CryptoStreamFactory
+     */
+    public static CryptoStreamFactoryJ8 getInstance(TYPES type) 
+    {
+        synchronized (CryptoStreamFactoryJ8Template.class) {
+            if( !instances.containsKey(type) )
+            {
+                try {
+                    instances.put(type, 
+                            (type.equals(TYPES.PBE))? new CryptoStreamPBEImpl():
+                                new CryptoStreamGCMImpl()
+                            );
+                } catch (GeneralSecurityException e) {
+                    e.printStackTrace();
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+    
+            return instances.get(type);
+        }
+    }
+    
+    /**
+     * 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 static CryptoStreamFactoryJ8 getInstance(TYPES type, byte[] salt, int count) 
+    {
+        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);
+        }
+    }
+
+
+    /**
+     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getSmartInputStream(java.io.InputStream)
+     */
+
+    public InputStream getSmartInputStream(InputStream is)
+        throws GeneralSecurityException, IOException
+    {
+        return this.getSmartInputStream(
+            is,
+            PasswordFactory.getInstance("SHA-256").create()
+            );
+    }
+
+    /**
+     * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getInputStream(java.io.InputStream,char[])
+     */
+    public InputStream getInputStream( InputStream is, char[] password )
+        throws GeneralSecurityException, IOException
+    {
+        byte[] decrypted =  this.createCipher( is, Cipher.DECRYPT_MODE, password.clone() );
+        InputStream eis = new ByteArrayInputStream(decrypted);
+        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() );
+        InputStream eis = new ByteArrayInputStream(encrypted);
+        StreamUtil.copy(eis, os);
+        return os;
+    }
+    
+    /**
+     * resets the default instances
+     */
+    public static void resetInstances()
+    {
+        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;
+//    }
+    
+    /** not used / implemented methods **/
+    
+    @Override
+	public InputStream getInputStream(InputStream is, String decryptionMode)
+			throws GeneralSecurityException, IOException {
+		throw new UnsupportedOperationException("not implemented");
+	}
+
+	@Override
+	public InputStream getInputStream(InputStream is, String decryptionMode, char[] password)
+			throws GeneralSecurityException, IOException {
+		throw new UnsupportedOperationException("not implemented");
+	}
+
+	@Override
+	public InputStream getInputStream(InputStream is) throws GeneralSecurityException, IOException {
+		throw new UnsupportedOperationException("not implemented");
+	}
+
+	@Override
+	public InputStream getSmartInputStream(InputStream is, char[] password)
+			throws GeneralSecurityException, IOException {
+		throw new UnsupportedOperationException("not implemented");
+	}
+
+	@Override
+	public OutputStream getOutputStream(OutputStream os) throws GeneralSecurityException, IOException {
+		throw new UnsupportedOperationException("not implemented");
+	}
+
+	@Override
+	public OutputStream getOutputStream(OutputStream os, char[] password) throws GeneralSecurityException, IOException {
+		throw new UnsupportedOperationException("not implemented");
+	}
+    /** not used methods end **/
+
+    /**
+     * Create a PBE key.
+     *
+     * @param password the password to use.
+     * @param salt if provided this is used, otherweise {@link #getSalt()}.
+     * @return the key
+     * @throws GeneralSecurityException creating the key failed
+     */
+    protected abstract Key createKey( char[] password, byte[] salt ) 
+            throws GeneralSecurityException;
+
+    /**
+     * Create a Cipher.
+     *
+     * @param is the input stream
+     * @param mode the cipher mode
+     * @param password the password
+     * @return an instance of a cipher
+     * @return the cipher as byte array
+     * @throws GeneralSecurityException creating a cipher failed
+     * @throws IOException creating a cipher failed
+     */
+    protected abstract byte[] createCipher(InputStream is, int mode, char[] password )
+        throws GeneralSecurityException, IOException;
+    
+    /**
+     * creates salt from {@link SecureRandom#getInstance(String)} by default was algorithm SHA1PRNG
+     * 
+     * changed to {@link SecureRandom#getInstanceStrong()} and let the system decide, what PRNG to use for salt random.
+     * 
+     * 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 static byte[] generateSalt() throws GeneralSecurityException {
+        SecureRandom random;
+        try {
+            random = SecureRandom.getInstanceStrong();
+            byte[] salt = new byte[SALT_SIZE ];
+            random.nextBytes(salt);
+            return salt;
+        } catch (NoSuchAlgorithmException e) {
+            throw new GeneralSecurityException(e);  
+        }
+    }
+
+	public byte[] getSalt() {
+		return salt.clone();
+	}
+
+	protected void setSalt(byte[] salt) {
+		this.salt = salt.clone();
+	}
+
+	public int getCount() {
+		return count;
+	}
+
+	public void setCount(int count) {
+		this.count = count;
+	}
+
+	public String getProviderName() {
+		return providerName;
+	}
+
+	public void setProviderName(String providerName) {
+		this.providerName = providerName;
+	}
+
+	public String getAlgorithm() {
+		return algorithm;
+	}
+
+	public void setAlgorithm(String algorithm) {
+		this.algorithm = algorithm;
+	}
+
+}
diff --git a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8.java b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8.java
new file mode 100644
index 0000000..51d1805
--- /dev/null
+++ b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8.java
@@ -0,0 +1,164 @@
+package org.apache.fulcrum.jce.crypto.extended;
+
+/*
+ * 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.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.fulcrum.jce.crypto.CryptoStreamFactory;
+import org.apache.fulcrum.jce.crypto.CryptoUtil;
+import org.apache.fulcrum.jce.crypto.StreamUtil;
+import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8.TYPES;
+
+/**
+ * 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:gk@apache.org">Georg Kallidis</a>
+ */
+public final class CryptoUtilJ8 extends CryptoUtil {
+
+	/** 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
+	 * 
+	 * default type PDC
+	 * 
+	 * @return an instance of the CryptoStreamFactory
+	 */
+	public static CryptoUtilJ8 getInstance() {
+		synchronized (CryptoUtilJ8.class) {
+			TYPES defaultType = CryptoParametersJ8.DEFAULT_TYPE;
+			if (instances.isEmpty() && !instances.containsKey(defaultType)) {
+				instances.put(defaultType, new CryptoUtilJ8());
+			}
+			return instances.get(defaultType);
+		}
+	}
+	
+	/**
+	 * 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() {
+		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
+	 * @param target   the target object
+	 * @param password the password to use for encryption
+	 * @throws GeneralSecurityException accessing JCE failed
+	 * @throws IOException              accessing the source failed
+	 */
+	@Override
+	public void encrypt(CryptoStreamFactory factory, Object source, Object target, char[] password)
+			throws GeneralSecurityException, IOException {
+		InputStream is = StreamUtil.createInputStream(source);
+		OutputStream os = StreamUtil.createOutputStream(target);
+		((CryptoStreamFactoryJ8) factory).getOutputStream(is, os, password);
+	}
+
+	/**
+	 * Copies from a source to a target object using decryption and a caller-suppier
+	 * CryptoStreamFactory.
+	 *
+	 * @param factory  the factory to create the crypto streams
+	 * @param source   the source object
+	 * @param target   the target object
+	 * @param password the password to use for decryption
+	 * @throws GeneralSecurityException accessing JCE failed
+	 * @throws IOException              accessing the source failed
+	 */
+	@Override
+	protected void decrypt(CryptoStreamFactory factory, Object source, Object target, char[] password)
+			throws GeneralSecurityException, IOException {
+		InputStream is = StreamUtil.createInputStream(source);
+		OutputStream os = StreamUtil.createOutputStream(target);
+		InputStream dis = factory.getInputStream(is, password);
+		StreamUtil.copy(dis, os);
+	}
+
+	public static Map<TYPES, CryptoUtilJ8> getInstances() {
+		return instances;
+	}
+
+	public static Map<TYPES, CryptoUtilJ8> getInstancesWithExplicitParams() {
+		return instancesWithExplicitParams;
+	}
+
+}
diff --git a/src/site/site.xml b/src/site/site.xml
index da3532b..321b9fb 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -24,6 +24,7 @@
   <body>
     <menu name="Overview">
       <item name="Overview"            href="/index.html"/>
+      <item name="Examples"            href="/examples.html"/>
       <item name="Downloads"           href="/downloads.html"/>
     </menu>  
     <menu ref="reports"></menu>
diff --git a/src/test/data/plain-simple.txt b/src/test/data/plain-simple.txt
new file mode 100644
index 0000000..77e51dc
--- /dev/null
+++ b/src/test/data/plain-simple.txt
@@ -0,0 +1 @@
+mysecretpassword
\ No newline at end of file
diff --git a/src/test/log4j2.xml b/src/test/log4j2.xml
new file mode 100644
index 0000000..3533c0e
--- /dev/null
+++ b/src/test/log4j2.xml
@@ -0,0 +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. -->
+<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>
+</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 2d59bc5..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
@@ -19,11 +24,16 @@
  * under the License.
  */
 
-
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
 
-import junit.framework.TestCase;
+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
@@ -31,272 +41,392 @@
  * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
  */
 
-public class CryptoUtilTest extends TestCase
-{
-    /** the password to be used */
-    private String password;
+public class CryptoUtilTest {
+	/** the password to be used */
+	private String password;
 
-    /** the test data directory */
-    private File testDataDirectory;
+	/** the test data directory */
+	private File testDataDirectory;
 
-    /** the temp data director */
-    private File tempDataDirectory;
+	/** the temp data director */
+	private File tempDataDirectory;
+	
+	private static Logger log = LogManager.getLogger(CryptoUtilTest.class);
 
-    /**
-     * Constructor
-     * @param name the name of the test case
-     */
-    public CryptoUtilTest( String name )
-    {
-        super(name);
+	/**
+	 * Constructor
+	 */
+	public CryptoUtilTest() {
+		this.password = "mysecret";
+		this.testDataDirectory = new File("./src/test/data");
+		this.tempDataDirectory = new File("./target/temp");
+		this.tempDataDirectory.mkdirs();
+	}
 
-        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 {
+	    CryptoStreamFactoryImpl factory = new CryptoStreamFactoryImpl(CryptoParameters.Salt(), CryptoParameters.COUNT);
 
-    /**
-     * @see junit.framework.TestCase#setUp()
-     *         byte[] salt,
-        int count,
-        String algorithm,
-        String providerName )
+	    CryptoStreamFactoryImpl.setInstance(factory);
+	    
+	    
+	}
 
-     */
-    protected void setUp() throws Exception
-    {
-        CryptoStreamFactoryImpl factory = new CryptoStreamFactoryImpl(
-            CryptoParameters.SALT,
-            CryptoParameters.COUNT
-            );
+	/**
+	 * @return Returns the password.
+	 */
+	protected char[] getPassword() {
+		return password.toCharArray();
+	}
 
-        CryptoStreamFactoryImpl.setInstance( factory );
-    }
+	/**
+	 * @return Returns the tempDataDirectory.
+	 */
+	protected File getTempDataDirectory() {
+		return tempDataDirectory;
+	}
 
-    /**
-     * @return Returns the password.
-     */
-    protected char[] getPassword()
-    {
-        return password.toCharArray();
-    }
+	/**
+	 * @return Returns the testDataDirectory.
+	 */
+	protected File getTestDataDirectory() {
+		return testDataDirectory;
+	}
 
-    /**
-     * @return Returns the tempDataDirectory.
-     */
-    protected File getTempDataDirectory()
-    {
-        return tempDataDirectory;
-    }
+	/** 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().encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException e) {
+			fail(e);
+		} catch (IOException e) {
+			fail(e);
+		}
+	}
 
-    /**
-     * @return Returns the testDataDirectory.
-     */
-    protected File getTestDataDirectory()
-    {
-        return testDataDirectory;
-    }
+	/** 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().decrypt(sourceFile, targetFile.getAbsolutePath(), this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
 
-    /** Encrypt a text file */
-    public void testTextEncryption() throws Exception
-    {
-        File sourceFile = new File( this.getTestDataDirectory(), "plain.txt" );
-        File targetFile = new File( this.getTempDataDirectory(), "plain.enc.txt" );
-        CryptoUtil.encrypt( sourceFile, targetFile, this.getPassword() );
-    }
+	/** 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().encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
 
-    /** Decrypt a text file */
-    public void testTextDecryption() throws Exception
-    {
-        testTextEncryption();
-        File sourceFile = new File( this.getTempDataDirectory(), "plain.enc.txt" );
-        File targetFile = new File( this.getTempDataDirectory(), "plain.dec.txt" );
-        CryptoUtil.decrypt( sourceFile, targetFile.getAbsolutePath(), this.getPassword() );
-    }
+	/** 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().decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
 
-    /** Encrypt an empty text file */
-    public void testEmptyTextEncryption() throws Exception
-    {
-        File sourceFile = new File( this.getTestDataDirectory(), "empty.txt" );
-        File targetFile = new File( this.getTempDataDirectory(), "empty.enc.txt" );
-        CryptoUtil.encrypt( sourceFile, targetFile, this.getPassword() );
-    }
+	/** 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().encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
 
-    /** Decrypt a text file */
-    public void testEmptyTextDecryption() throws Exception
-    {
-        testEmptyTextEncryption();
-        File sourceFile = new File( this.getTempDataDirectory(), "empty.enc.txt" );
-        File targetFile = new File( this.getTempDataDirectory(), "empty.dec.txt" );
-        CryptoUtil.decrypt( sourceFile, targetFile, this.getPassword() );
-    }
+	/** 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().decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
 
-    /** Encrypt a PDF file */
-    public void testPdfEncryption() throws Exception
-    {
-        File sourceFile = new File( this.getTestDataDirectory(), "plain.pdf" );
-        File targetFile = new File( this.getTempDataDirectory(), "plain.enc.pdf" );
-        CryptoUtil.encrypt( sourceFile, targetFile, this.getPassword() );
-    }
+	/** 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().encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
 
-    /** Decrypt a PDF file */
-    public void testPdfDecryption() throws Exception
-    {
-        testPdfEncryption();
-        File sourceFile = new File( this.getTempDataDirectory(), "plain.enc.pdf" );
-        File targetFile = new File( this.getTempDataDirectory(), "plain.dec.pdf" );
-        CryptoUtil.decrypt( sourceFile, targetFile, this.getPassword() );
-    }
+	/** 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().decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
 
-    /** Encrypt a ZIP file */
-    public void testZipEncryption() throws Exception
-    {
-        File sourceFile = new File( this.getTestDataDirectory(), "plain.zip" );
-        File targetFile = new File( this.getTempDataDirectory(), "plain.enc.zip" );
-        CryptoUtil.encrypt( sourceFile, targetFile, this.getPassword() );
-    }
+	/** 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().encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
 
-    /** Decrypt a ZIP file */
-    public void testZipDecryption() throws Exception
-    {
-        testZipEncryption();
-        File sourceFile = new File( this.getTempDataDirectory(), "plain.enc.zip" );
-        File targetFile = new File( this.getTempDataDirectory(), "plain.dec.zip" );
-        CryptoUtil.decrypt( sourceFile, targetFile, this.getPassword() );
-    }
+	/**
+	 * 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().decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
 
-    /** Encrypt a UTF-16 XML file */
-    public void testXmlUTF16Encryption() throws Exception
-    {
-        File sourceFile = new File( this.getTestDataDirectory(), "plain-utf16.xml" );
-        File targetFile = new File( this.getTempDataDirectory(), "plain-utf16.enc.xml" );
-        CryptoUtil.encrypt( sourceFile, targetFile, this.getPassword() );
-    }
+	/**
+	 * 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().encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
 
-    /** Decrypt a UTF-16 XML file */
-    public void testXMLUTF16Decryption() throws Exception
-    {
-        testXmlUTF16Encryption();
-        File sourceFile = new File( this.getTempDataDirectory(), "plain-utf16.enc.xml" );
-        File targetFile = new File( this.getTempDataDirectory(), "plain-utf16.dec.xml" );
-        CryptoUtil.decrypt( sourceFile, targetFile, this.getPassword() );
-    }
+	/**
+	 * 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().decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
 
-    /** Encrypt a UTF-8 XML file */
-    public void testXmlUTF8Encryption() throws Exception
-    {
-        File sourceFile = new File( this.getTestDataDirectory(), "plain-utf8.xml" );
-        File targetFile = new File( this.getTempDataDirectory(), "plain-utf8.enc.xml" );
-        CryptoUtil.encrypt( sourceFile, targetFile, this.getPassword() );
-    }
+	/**
+	 * 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().encrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
 
-    /** Decrypt a UTF-8 XML file */
-    public void testXMLUTF8Decryption() throws Exception
-    {
-        testXmlUTF8Encryption();
-        File sourceFile = new File( this.getTempDataDirectory(), "plain-utf8.enc.xml" );
-        File targetFile = new File( this.getTempDataDirectory(), "plain-utf8.dec.xml" );
-        CryptoUtil.decrypt( sourceFile, targetFile, this.getPassword() );
-    }
+	/**
+	 * 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().decrypt(sourceFile, targetFile, this.getPassword());
+		} catch (GeneralSecurityException | IOException e) {
+			fail(e);
+		}
+	}
 
-    /** Encrypt a ISO-8859-1 XML file */
-    public void testXmlISO88591Encryption() throws Exception
-    {
-        File sourceFile = new File( this.getTestDataDirectory(), "plain-iso-8859-1.xml" );
-        File targetFile = new File( this.getTempDataDirectory(), "plain-iso-8859-1.enc.xml" );
-        CryptoUtil.encrypt( sourceFile, targetFile, this.getPassword() );
-    }
+	/** Test encryption and decryption of Strings
+	 */
+	@Test
+	public void testStringEncryption()  {
+		char[] testVector = new char[513];
 
-    /** Decrypt a UTF-8 XML file */
-    public void testXmlISO88591Decryption() throws Exception
-    {
-        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.decrypt( sourceFile, targetFile, this.getPassword() );
-    }
-    /** Test encryption and decryption of Strings */
-    public void testStringEncryption() throws Exception
-    {
-        char[] testVector = new char[513];
+		for (int i = 0; i < testVector.length; i++) {
+			testVector[i] = (char) i;
+		}
 
-        for( int i=0; i<testVector.length; i++ )
-        {
-            testVector[i] = (char) i;
-        }
+		String source = new String(testVector);
+		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];
 
-        String source = new String( testVector );
-        String cipherText = CryptoUtil.encryptString( source, this.getPassword() );
-        String plainText = CryptoUtil.decryptString( cipherText, this.getPassword() );
-        assertEquals( source, plainText );
-    }
+		for (int i = 0; i < testVector.length; i++) {
+			testVector[i] = (char) i;
+		}
 
-    /** Test encryption and decryption of Strings */
-    public void testStringHandling() throws Exception
-    {
-        String source = "Nobody knows the toubles I have seen ...";
-        String cipherText = CryptoUtil.encryptString( source, this.getPassword() );
-        String plainText = CryptoUtil.decryptString( cipherText, this.getPassword() );
-        assertEquals( source, plainText );
-    }
+		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);
 
-    /** Test encryption and decryption of binary data */
-    public void testBinaryHandling() throws Exception
-    {
-        byte[] source = new byte[256];
-        byte[] result = null;
+			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));
 
-        for( int i=0; i<source.length; i++ )
-        {
-            source[i] = (byte) i;
-        }
+		} catch (GeneralSecurityException | IOException e) {
+			e.printStackTrace();
+			fail();
+		}
+	}
 
-        ByteArrayOutputStream cipherText = new ByteArrayOutputStream();
-        ByteArrayOutputStream plainText = new ByteArrayOutputStream();
+	/** Test encryption and decryption of Strings
+	 */
+	@Test
+	public void testStringHandling() {
+		String source = "Nobody knows the toubles I have seen ...";
+		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();
+		}
+	}
 
-        CryptoUtil.encrypt( source, cipherText, this.getPassword() );
-        CryptoUtil.decrypt( cipherText, plainText, this.getPassword() );
+	/** 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;
 
-        result = plainText.toByteArray();
+		for (int i = 0; i < source.length; i++) {
+			source[i] = (byte) i;
+		}
 
-        for( int i=0; i<source.length; i++ )
-        {
-            if( source[i] != result[i] )
-            {
-                fail( "Binary data are different at position " + i );
-            }
-        }
-    }
+		ByteArrayOutputStream cipherText = new ByteArrayOutputStream();
+		ByteArrayOutputStream plainText = new ByteArrayOutputStream();
 
-    /** Test creating a password */
-    public void testPasswordFactory() throws Exception
-    {
-        char[] result = null;
-        result = PasswordFactory.create();
-        System.out.println( new String(result) );
-        result = PasswordFactory.create( this.getPassword() );
-        System.out.println( new String(result) );        
-        assertNotNull(result);
-        return;
-    }
+		CryptoUtil.getInstance().encrypt(source, cipherText, this.getPassword());
+		CryptoUtil.getInstance().decrypt(cipherText, plainText, this.getPassword());
 
-    public void testHexConverter() throws Exception
-    {
-        String source = "DceuATAABWSaVTSIK";
-        String hexString = HexConverter.toString( source.getBytes() );
-        String result = new String( HexConverter.toBytes( hexString ) );
-        assertEquals( source, result );
-    }
+		result = plainText.toByteArray();
 
-    /** Test encryption and decryption of Strings */
-    public void testPasswordEncryption() throws Exception
-    {
-        char[] password = "57cb-4a23-d838-45222".toCharArray();
-        String source = "e02c-3b76-ff1e-5d9a1";
-        String cipherText = CryptoUtil.encryptString( source, password );
-        String plainText = CryptoUtil.decryptString( cipherText, password );
-        assertEquals( source, plainText );
-    }
+		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().encryptString(source, password);
+		log.info(cipherText);// len 48
+		assertEquals(48, cipherText.length());
+		String plainText = CryptoUtil.getInstance().decryptString(cipherText, password);
+		assertEquals(source, plainText);
+	}
 
 }
diff --git a/src/test/org/apache/fulcrum/jce/crypto/MainTest.java b/src/test/org/apache/fulcrum/jce/crypto/MainTest.java
index 352990f..83674b4 100644
--- a/src/test/org/apache/fulcrum/jce/crypto/MainTest.java
+++ b/src/test/org/apache/fulcrum/jce/crypto/MainTest.java
@@ -1,5 +1,7 @@
 package org.apache.fulcrum.jce.crypto;
 
+import org.apache.fulcrum.jce.crypto.cli.CLI;
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -55,9 +57,17 @@
     public void testStringEncryption()
     {
         String[] encryptionArgs = { "string", "enc", this.password, "mysecretpassword"};
-        Main.main(encryptionArgs);
+        CLI.main(encryptionArgs);
         String[] decryptionArgs = { "string", "dec", this.password, "9330419fc003b4e1461986782625db13f4c8c81c340a9caa"};
-        Main.main(decryptionArgs);
+        CLI.main(decryptionArgs);
+    }
+    
+    public void testAnotherStringEncryption()
+    {
+        String[] encryptionArgs = { "string", "enc", this.password, "secret"};
+        CLI.main(encryptionArgs);
+        String[] decryptionArgs = { "string", "dec", this.password, "39619852d48491af"};
+        CLI.main(decryptionArgs);
     }
 
     /** Encrypt a text file on the command line */
@@ -65,8 +75,8 @@
     {
         String[] encryptionArgs = { "file", "enc", this.password, "./src/test/data/plain.txt", "./target/main/plain.enc.txt" };
         String[] decryptionArgs = { "file", "dec", this.password, "./target/main/plain.enc.txt", "./target/main/plain.dec.txt" };
-        Main.main(encryptionArgs);
-        Main.main(decryptionArgs);
+        CLI.main(encryptionArgs);
+        CLI.main(decryptionArgs);
     }
 
     /** Encrypt a text file in-place on the command line */
@@ -74,8 +84,8 @@
     {
         String[] encryptionArgs = { "file", "enc", this.password, "./src/test/data/plain.txt", "./target/main/plain.txt" };
         String[] decryptionArgs = { "file", "dec", this.password, "./target/main/plain.txt" };
-        Main.main(encryptionArgs);
-        Main.main(decryptionArgs);
+        CLI.main(encryptionArgs);
+        CLI.main(decryptionArgs);
     }
 
 }
\ No newline at end of file
diff --git a/src/test/org/apache/fulcrum/jce/crypto/SmartDecryptingInputStreamTest.java b/src/test/org/apache/fulcrum/jce/crypto/SmartDecryptingInputStreamTest.java
index 7bcfd96..e44b99e 100644
--- a/src/test/org/apache/fulcrum/jce/crypto/SmartDecryptingInputStreamTest.java
+++ b/src/test/org/apache/fulcrum/jce/crypto/SmartDecryptingInputStreamTest.java
@@ -63,7 +63,7 @@
     protected void setUp() throws Exception
     {
         CryptoStreamFactoryImpl factory = new CryptoStreamFactoryImpl(
-            CryptoParameters.SALT,
+            CryptoParameters.Salt(),
             CryptoParameters.COUNT
             );
 
@@ -158,7 +158,7 @@
         String result = null;
         FileInputStream fis = new FileInputStream( file );
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        CryptoUtil.copy(fis,baos);
+        StreamUtil.copy(fis,baos);
         fis.close();
         result = new String( baos.toByteArray(), enc );
         return result;
@@ -173,8 +173,8 @@
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         FileInputStream fis = new FileInputStream( file );
 
-        CryptoUtil.encrypt(
-            CryptoStreamFactoryImpl.getInstance(),
+        CryptoUtil.getInstance().encrypt(
+                CryptoStreamFactoryImpl.getInstance(),
             fis,
             baos,
             this.getPassword()
@@ -197,12 +197,12 @@
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 
         SmartDecryptingInputStream sdis = new SmartDecryptingInputStream(
-            CryptoStreamFactoryImpl.getInstance(),
+                CryptoStreamFactoryImpl.getInstance(),
             bais,
             this.getPassword()
             );
 
-        CryptoUtil.copy(sdis,baos);
+        StreamUtil.copy(sdis,baos);
 
         return new String( baos.toByteArray(), enc );
     }
@@ -219,12 +219,12 @@
         FileInputStream fis = new FileInputStream( file );
 
         SmartDecryptingInputStream sdis = new SmartDecryptingInputStream(
-            CryptoStreamFactoryImpl.getInstance(),
+                CryptoStreamFactoryImpl.getInstance(),
             fis,
             this.getPassword()
             );
 
-        CryptoUtil.copy(sdis,baos);
+        StreamUtil.copy(sdis,baos);
         return new String( baos.toByteArray(), enc );
     }
 
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
new file mode 100644
index 0000000..0f278e7
--- /dev/null
+++ b/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8ParameterizedTest.java
@@ -0,0 +1,388 @@
+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.assertTrue;
+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.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.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.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
+ *
+ * e.g. with ExtendWith(SupportedTypeArguments.class)
+ * */
+public class CryptoUtilJ8ParameterizedTest {
+	/** the password to be used */
+	private String password;
+
+	/** the test data directory */
+	private File testDataDirectory;
+
+	/** the temp data director */
+	private File tempDataDirectory;
+
+	private List<CryptoUtilJ8> cryptoUtilJ8s = new ArrayList<>();
+
+	private static Logger log = LogManager.getLogger(CryptoUtilJ8ParameterizedTest.class);
+
+	/**
+	 * Constructor
+	 */
+	public CryptoUtilJ8ParameterizedTest() {
+		this.password = "mysecret";
+		this.testDataDirectory = new File("./src/test/data");
+		this.tempDataDirectory = new File("./target/temp");
+		this.tempDataDirectory.mkdirs();
+	}
+
+	/**
+	 * @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;
+	}
+
+	@BeforeEach
+	public void setup() {
+		cryptoUtilJ8s.clear();
+        SupportedTypeArguments.init();
+	}
+	
+
+	@AfterEach
+	public void clean() {
+		cryptoUtilJ8s.clear();
+	}
+
+	/**
+	 * Parameterized Test
+	 * 
+	 * Encrypt a text file
+	 * 
+	 * @param type the type to be tested based on {@link TYPES}
+	 * 
+	 */
+	@ParameterizedTest
+	@ArgumentsSource(SupportedTypeArguments.class)
+	public void testTextEncryption(TYPES type) {
+
+		cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
+		File sourceFile = new File(this.getTestDataDirectory(), "plain.txt");
+		File targetFile = new File(this.getTempDataDirectory(), "plain.j8.enc.txt");
+
+		cryptoUtilJ8s.forEach(cuj8 -> {
+			try {
+				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();
+				fail();
+			} catch (IOException e) {
+				e.printStackTrace();
+				fail();
+			}
+		});
+	}
+
+	/**
+	 * Parameterized Test Decrypt a text file
+	 * 
+	 * @param type the type to be tested based on {@link TYPES}
+	 * 
+	 */
+	@ParameterizedTest
+	@ArgumentsSource(SupportedTypeArguments.class)
+	public void testTextDecryption(TYPES type) {
+		cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
+		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());
+
+				File sourceFile2 = targetFile;
+				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();
+			}
+		});
+	}
+
+	/**
+	 * Parameterized Test
+	 * 
+	 * Encrypt a PDF file
+	 * 
+	 * @param type the type to be tested based on {@link TYPES}
+	 * 
+	 */
+	@ParameterizedTest
+	@ArgumentsSource(SupportedTypeArguments.class)
+	public void testPdfEncryption(TYPES type) {
+		cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
+		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();
+			}
+		});
+	}
+
+	/**
+	 * Parameterized Test Decrypt a PDF file
+	 *
+	 * @param type the type to be tested based on {@link TYPES}
+	 * 
+	 */
+	@ParameterizedTest
+	@ArgumentsSource(SupportedTypeArguments.class)
+	public void testPdfDecryption(TYPES type) {
+		cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
+		// 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 = targetFile;
+				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();
+			}
+		});
+
+	}
+
+	/**
+	 * Parameterized Test Test encryption and decryption of Strings
+	 * 
+	 * @param type the type to be tested based on {@link TYPES}
+	 * 
+	 */
+	@ParameterizedTest
+	@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++) {
+			testVector[i] = (char) i;
+		}
+
+		String source = new String(testVector);
+		String cipherText = null;
+		String plainText = null;
+		try {
+			log.info("Test without clearTextHeader in type {}", type);
+			cipherText = cuj8.encryptString(source, this.getPassword());
+			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.",clearCode) );
+			String cipherText2 = cuj8.encryptStringWithClearCode(source, this.getPassword());
+			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));
+
+		} catch (GeneralSecurityException | IOException e) {
+			e.printStackTrace();
+			fail();
+		}
+	}
+
+	/**
+	 * Parameterized Test Test encryption and decryption of Strings
+	 * 
+	 * @param type the type to be tested based on {@link TYPES}
+	 * 
+	 */
+	@ParameterizedTest
+	@ArgumentsSource(SupportedTypeArguments.class)
+	public void testStringHandling(TYPES type) {
+		cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
+		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.info("random pw:" + new String(result));
+		result = PasswordFactory.getInstance("SHA-256", 10_000).create(this.getPassword());
+		log.info("password pw with seed:" + new String(result));
+		assertNotNull(result);
+		return;
+	}
+
+	/**
+	 * Parameterized Test
+	 * 
+	 * Test encryption and decryption of binary data
+	 * 
+	 * @throws Exception Generic exception
+	 * 
+	 * @param type the type to be tested based on {@link TYPES}
+	 */
+	@ParameterizedTest
+	@ArgumentsSource(SupportedTypeArguments.class)
+	public void testBinaryHandling(TYPES type) throws Exception {
+		cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
+		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);
+				}
+			}
+		});
+
+	}
+
+	/**
+	 * Parameterized Test
+	 * 
+	 * Test encryption and decryption of Strings
+	 * 
+	 * @param type the type to be tested based on {@link TYPES}
+	 * 
+	 */
+	@ParameterizedTest
+	@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("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, 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) {
+			e.printStackTrace();
+			fail();
+		}
+	}
+
+}
diff --git a/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8Test.java b/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8Test.java
new file mode 100644
index 0000000..2b7ef55
--- /dev/null
+++ b/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8Test.java
@@ -0,0 +1,357 @@
+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;
+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;
+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 CryptoUtilJ8Test {
+    /** the password to be used */
+    private String password;
+
+    /** the test data directory */
+    private File testDataDirectory;
+
+    /** the temp data director */
+    private File tempDataDirectory;
+    
+    private static List<CryptoUtilJ8> cryptoUtilJ8s = new ArrayList<>();
+
+    private static Logger log = LogManager.getLogger(CryptoUtilJ8Test.class);
+
+    /**
+     * Constructor
+     */
+    public CryptoUtilJ8Test() {
+
+        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));
+            }
+        }
+        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.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());
+                    
+                    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
+                
+                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: {}", 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/Main8Test.java b/src/test/org/apache/fulcrum/jce/crypto/extended/Main8Test.java
new file mode 100644
index 0000000..ecd6228
--- /dev/null
+++ b/src/test/org/apache/fulcrum/jce/crypto/extended/Main8Test.java
@@ -0,0 +1,241 @@
+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.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;
+
+/*
+ * 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 Main8Test {
+	/** the password to be used */
+	private String password;
+
+	/**
+	 * Constructor
+	 */
+	public Main8Test() {
+
+		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;
+        }
+        String source = new String(testVector);
+       
+        CryptoUtilJ8.getInstances().clear();
+        CryptoUtilJ8 cuj8 = CryptoUtilJ8.getInstance();
+        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();
+        }
+    }
+
+}
\ No newline at end of file
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/downloads.xml b/xdocs/downloads.xml
index dc80df1..8531769 100644
--- a/xdocs/downloads.xml
+++ b/xdocs/downloads.xml
@@ -31,10 +31,22 @@
         </tr>
         <tr>
           <td>
-            <a href="http://www.apache.org/dyn/closer.cgi/turbine/fulcrum/fulcrum-yaafi-crypto/binaries/fulcrum-yaafi-crypto-1.0.6-bin.zip">Fulcrum's YAAFI Crypto v1.0.6</a>
+            <p>
+              <a href="http://www.apache.org/dyn/closer.cgi/turbine/fulcrum/fulcrum-yaafi-crypto/binaries/fulcrum-yaafi-crypto-2.0.1-bin.zip">Fulcrum's YAAFI Crypto v2.0.1</a>
+            </p>    
+            <p>
+              <a href="http://www.apache.org/dyn/closer.cgi/turbine/fulcrum/fulcrum-yaafi-crypto/binaries/fulcrum-yaafi-crypto-1.0.8-bin.zip">Fulcrum's YAAFI Crypto v1.0.8</a>
+            </p>
+            <p>
+              <a href="http://www.apache.org/dyn/closer.cgi/turbine/fulcrum/fulcrum-yaafi-crypto/binaries/fulcrum-yaafi-crypto-1.0.7-bin.zip">Fulcrum's YAAFI Crypto v1.0.7</a>
+            </p>
+            <p><a href="http://www.apache.org/dyn/closer.cgi/turbine/fulcrum/fulcrum-yaafi-crypto/binaries/fulcrum-yaafi-crypto-1.0.6-bin.zip">Fulcrum's YAAFI Crypto v1.0.6</a>
+            </p>
           </td>
           <td>
-            <a href="announcements/announcement-1.0.6.txt">1.0.6</a>
+            <p>See <a href="changes-report.html">project changes report</a>.</p>
+             <p></p>
+              <p></p>   
           </td>
         </tr>
       </table>
diff --git a/xdocs/examples.xml b/xdocs/examples.xml
new file mode 100644
index 0000000..d0c6102
--- /dev/null
+++ b/xdocs/examples.xml
@@ -0,0 +1,360 @@
+<?xml version="1.0"?>

+<!--

+ Licensed to the Apache Software Foundation (ASF) under one

+ or more contributor license agreements.  See the NOTICE file

+ distributed with this work for additional information

+ regarding copyright ownership.  The ASF licenses this file

+ to you under the Apache License, Version 2.0 (the

+ "License"); you may not use this file except in compliance

+ with the License.  You may obtain a copy of the License at

+

+   http://www.apache.org/licenses/LICENSE-2.0

+

+ Unless required by applicable law or agreed to in writing,

+ software distributed under the License is distributed on an

+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ KIND, either express or implied.  See the License for the

+ specific language governing permissions and limitations

+ under the License.

+-->

+<document>

+

+  <properties>

+    <title>Fulcrum Crypto Library Examples</title>

+     <author email="gk@apache.org">Georg Kallidis</author>

+  </properties>

+

+  <body>

+    <section name="Short Examples">

+          <subsection name="Command line Usage">

+              <p>

+Encrypt with default PCM the string "mysecretgeheim" and meta password "changeit", outputs encrypted string to stdout.

+                <source>

+                <![CDATA[

+ java -classpath target/classes org.apache.fulcrum.jce.crypto.cli.CLI2 string enc changeit mysecretgeheim  

+ ]]>

+                </source>

+ <source>

+                <![CDATA[

+ java -jar target/fulcrum-yaafi-crypto-<version>.jar string enc:GCM changeit mysecretgeheim  

+ ]]>

+                </source>

+This prints out the encrypted "mysecretgeheim".

+ <source>

+                <![CDATA[

+ java -jar target/fulcrum-yaafi-crypto-<version>.jar string dec:GCM changeit 88f8ecc93cc921672e13862d75f90c55a4cc2d823c36e6ac3da0225e397770f45d3944f6be859fe25d053a8442313a5a2581e7edf081030e  

+ ]]>

+                </source>

+This decrypts the result to stdout and prints information (supported type, matched type ..) to system.err.

+         </p>

+	<p>CLI Usage Help:

+ <source>

+                <![CDATA[

+ java -jar target/fulcrum-yaafi-crypto-<version>.jar help 

+ ]]>

+                </source>

+ Information about supported cipher libs:

+                <source>

+                <![CDATA[

+ java -jar target/fulcrum-yaafi-crypto-<version>.jar info 

+ ]]>

+                </source>

+	</p>

+          <p>An example using an ant build tool and property file is provided in pom-xml with phase integration-test.

+          By default running this will write the encrypted password to target/integration-test/filter-integration-test.properties and the decrypted password to target/integration-test/filtered-pw.properties. You could play with this toll on the command line providing a custom secret and meta password like this (assuming -Dskip.pw.gen=false -Dskip.pw.encrypt=false):

+                <source> 

+                <![CDATA[

+mvn integration-test -Dtest.password="xyz" -Dmeta.pw="abc"  

+ ]]>

+                </source>

+         </p>

+         

+         

+            </subsection>

+     <subsection name="Code Usage">

+       <p>

+          <source>

+<![CDATA[

+    // provide target_password, meta_password

+            

+    char[] password = meta_password.toCharArray();

+    // default

+    CryptoUtilJ8 cryptoUtilJ8 = CryptoUtilJ8.getInstance();

+

+    String result = null;

+    String encryptedValue;targetValue

+

+    try {

+        encryptedValue = cryptoUtilJ8.encryptString(target_password, password);

+        System.out.println("encrypted:" + encryptedValue);

+    } catch (GeneralSecurityException | IOException e) {

+        // fail();

+    }

+    try {

+        String encryptedValue = target_password_encrypted;

+        result = cryptoUtilJ8.decryptString(encryptedValue, password);

+        // should equal targetValue

+        System.out.println("decrypted result:" + result);

+    } catch (GeneralSecurityException | IOException e) {

+        ...

+    }

+  ]]>

+              </source>

+           </p>

+      </subsection> 

+   </section>

+   <section name="Building a Project">

+      <subsection name="Prepare the crypto-tool with Maven Assembly">

+         <p>First we build our crypto tool as executable jar in phase initialize (i.e. very early, to use it later) and name it <i>crypto-tool</i> 

+            using the assembly description saved in the file <i>build/assembly.xml</i> described below. 

+            Add this into your project pom.xml file.

+            <source>

+                <![CDATA[

+<plugin>

+    <artifactId>maven-assembly-plugin</artifactId>

+    <version>3.3.0</version>

+    <configuration>

+       <finalName>crypto-tool</finalName>  

+        <archive>

+            <manifest>

+                <mainClass>org.apache.fulcrum.jce.crypto.cli.CLI2</mainClass>

+            </manifest>

+        </archive>

+        <descriptors>

+            <descriptor>build/assembly.xml</descriptor>

+          </descriptors>

+        <appendAssemblyId>false</appendAssemblyId>

+    </configuration>

+    <executions>

+  <execution>

+    <id>make-assembly</id> <!-- this is used for inheritance merges -->

+    <phase>initialize</phase> <!-- bind to the packaging phase -->

+    <goals>

+      <goal>single</goal>

+    </goals>

+   </execution>

+  </executions>

+</plugin>

+                ]]>

+      </source>

+   </p>

+   <p>Using this assembly description (adapted to our needs from the descriptor-ref jar-with-dependencies) the executable jar will be generated 

+       in target folder and will just include fulcrum yaafi-crypto classes. 

+       Here you will get a very tiny jar (build with java 8 on windows less than 45kb), as the tool has no library dependencies!

+      <source>

+                <![CDATA[

+<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"

+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+      xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">

+  <id>crypto-tool-jar-with-dependencies</id>

+  <formats>

+    <format>jar</format>

+  </formats>

+  <includeBaseDirectory>false</includeBaseDirectory>

+  <dependencySets>

+    <dependencySet>

+      <outputDirectory>/</outputDirectory>

+      <useProjectArtifact>true</useProjectArtifact>

+      <unpack>true</unpack>

+      <scope>runtime</scope>

+      <includes>

+        <include>org.apache.fulcrum:fulcrum-yaafi-crypto</include>

+      </includes>

+    </dependencySet>

+  </dependencySets>

+</assembly>

+                ]]>

+     </source>

+ </p>

+ <p>After executing the following command the <i>crypto tool</i> is available in your project and 

+   we could use it to generate an encrypted password using a master password (to be saved separately and not in the project). 

+   This is done in the following step.

+   <source>

+            <![CDATA[

+ mvn initialize

+               ]]>

+    </source>

+    </p>

+  </subsection>

+  <subsection name="Integrate with Ant Tool - Extended">

+    <p>Check the pom.xml's integration test ant calls. The following is an extended version using its own assembly, but is very similar to the integration test.</p>

+    <p>First we <i>encrypt</i> the password on the command line using our master password and after that we copy and save the encrypted password in one of our project's configuration files. 

+      Running the following command will show the encrypted password.

+      <source>

+            <![CDATA[  

+ java -jar target/crypto-tool.jar string enc <master.pw> <unencrypted.password>

+ ]]>

+       </source>

+       Save the encrypted password as value with key <i>password_encrypted</i> 

+      in an existing configuration file of your project, which will be used later. 

+      You may include this process into your build tool (by invoking target init) similar as we do it for the <i>decrypting</i> process (see below paragraph).      

+   </p>

+   <p>Use the following ant build script (windows only) and save it into <i>build/build-pw.xml</i>. This is the ant build file we use to <i>decrypt</i> the encrypted password and 

+      use it while building the project. The example is configured as follows:

+      The global master password is set as environment variable "<i>meta.pw</i>". The already encrypted password is expected to be set in a source property file <i>source.property.path</i> 

+      (i.e. configuration file of your project) as value in key <i>password_encrypted</i> .  It will be read in automatically as ant variable ${password_encrypted}. 

+      The <i>decrypted</i> password will be saved to key "<i>password</i>" in another property file (<i>target.property.path</i>), which should not be set into version control. You may need to create it new.

+      You may use the ant tool as is setting the variables in <i>.build.properties</i> or integrate it in your pom.xml build process (see below).

+       <source>

+   <![CDATA[  

+<project basedir="."  default="build" name="build">

+  <property environment="env"/>

+   <property file=".build.properties"/>  

+   <!-- reading from the file properties: password_encrypted, password -->

+   <property file="${source.property.path}"/>

+   <property name="meta.pw" value="${env.meta.pw}"/>

+

+   <target name="testjava">

+      <echo message="executing java -version"/>

+      <exec executable="cmd" dir="" osfamily="windows" >

+        <arg value="/c"/>

+         <arg value="java -version"/>

+      </exec>

+    </target>

+    

+   <target name="decrypt">

+      <echo message="executing java -jar target/${jarname}.jar string dec ${meta.pw} ${password_encrypted}."/>

+      <exec executable="cmd" dir="${build.path}/../" osfamily="windows" resultproperty="success" outputproperty="decoded.pw">

+        <arg value="/c"/>

+         <arg value="java -jar target/${jarname}.jar string dec ${meta.pw} ${password_encrypted}"/>

+      </exec>

+    </target>

+      

+   <target name="update">

+       <echo message="updating password in properties file: ${target.property.path}."/>

+       <propertyfile file="${target.property.path}" >

+          <entry  key="password" value="${decoded.pw}"/>

+        </propertyfile>

+    </target>

+    

+   <target name="encrypt">

+      <echo message="executing java -jar target/${jarname}.jar string enc ${meta.pw} ${password}"/>

+      <exec executable="cmd" dir="${build.path}/../" osfamily="windows" resultproperty="success" outputproperty="encoded.pw">

+        <arg value="/c"/>

+         <arg value="java -jar target/${jarname}.jar string enc ${meta.pw} ${password}"/>

+      </exec>

+    </target>

+    

+  <target name="init-update">

+       <echo message="updating password_encrypted in properties file: ${target.property.path}."/>

+       <propertyfile file="${target.property.path}" >

+          <entry  key="password_encrypted" value="${encoded.pw}"/>

+        </propertyfile>

+    </target>

+  

+  <target name="clean">

+   <echo message="cleaning up key password in propert file: ${target.property.path}."/>

+       <propertyfile file="${target.property.path}" >

+          <entry  key="password" value=""/>

+        </propertyfile>

+  </target>

+

+  <!-- target name="run">

+        <echo message="test output java -jar target/${jarname}.jar string dec ${meta.pw} ${password_encrypted}."/>

+        <java jar="./../target/${jarname}.jar" fork="true">

+        <arg value="string"/>

+        <arg value="dec"/>

+        <arg value="${meta_password}"/>

+        <arg value="${password_encrypted}"/>

+        </java>

+  </target-->

+  

+  <!-- decrypt to password -->

+   <target name="build" depends="testjava, decrypt, update">

+  </target>

+  

+  <!-- encrypt to password_encrypted -->

+    <target name="init" depends="testjava, encrypt, init-update">

+  </target>

+  

+ </project>      

+                ]]>

+         </source>

+     </p>

+  </subsection>

+  <subsection name="Integration ANT Task into Maven Life cycle">

+    <p>Integrate the ant tool, check the file name and run maven command below after setting your configuration or filter files in <i>source.property.path</i> and <i>target.property.path</i>. 

+    You may add another clean-up in a later life cycle phase, e.g. post-integration-test. 

+    You may also simplify the process by cleaning always and using the same source and target property file.

+      <source>

+            <![CDATA[

+<plugin>

+   <artifactId>maven-antrun-plugin</artifactId>

+    <version>3.0.0</version>

+    <executions>

+        <execution>

+            <id>build</id> 

+            <phase>process-sources</phase>

+            <configuration>

+               <skip>${skip.pw.gen}</skip>   

+               <target>

+                <ant antfile="${basedir}/build/build-pw.xml" target="build">

+                      <property name="build.path" value="${basedir}/build" />

+                      <property name="meta.pw" value="${meta.pw}" /><!-- provided by env variable -->

+                       <property name="jarname" value="crypto-tool" /><!-- by default ${project.build.finalName} -->

+                      <!-- contains encrypted password, saved in vcs: -->

+                      <property name="source.property.path" value="${basedir}/src/main/filters/${env}-app.properties" />

+                      <!-- should NOT be saved in vcs: -->

+                      <property name="target.property.path" value="${basedir}/src/main/filters/${env}-pw.properties" />

+                  </ant>

+                </target>

+            </configuration>

+            <goals>

+              <goal>run</goal>

+            </goals>

+        </execution>

+        <execution>

+            <id>clean</id> 

+            <phase>clean</phase>

+            <configuration>

+                <skip>${skip.pw.gen}</skip>

+               <target>

+                <ant antfile="${basedir}/build/build-pw.xml" target="clean">

+                      <property name="build.path" value="${basedir}/build" />

+                      <property name="target.property.path" value="${basedir}/src/main/filters/filter-${env}-pw.properties" />

+                  </ant>

+                </target>

+            </configuration>

+            <goals>

+              <goal>run</goal>

+            </goals>

+        </execution>

+    </executions>

+  </plugin>

+            ]]>

+       </source>

+   You may add another  execution definiton with id and target "init" and probably another skip property to initially or regularily update the encoded password.

+     </p>

+  </subsection>

+  <subsection name="Maven Command line examples">

+     <p>Save the decrypted password for the build

+         <source>

+                <![CDATA[

+mvn clean test -Dmeta.pw=<securepwd>

+                ]]>

+                </source>

+                    </p>

+              <p>Keep the unencrypted password in source property files to use it during development or later (you may add a profile).

+                <source>

+                <![CDATA[

+mvn clean test install -Dskip.pw.gen=true

+                ]]>

+                </source>

+                    </p>

+ <p>Clean up finally.

+                <source>

+                <![CDATA[

+mvn clean 

+               ]]>

+        </source>

+    </p>

+    <p>This example could be extended or adapted, eg. by using multiple passwords, or encrypting an entire file. 

+       Have fun!

+    </p>

+

+    </subsection>

+   </section>

+

+  </body>

+

+</document>

diff --git a/xdocs/index.xml b/xdocs/index.xml
index 47079d7..8e21359 100644
--- a/xdocs/index.xml
+++ b/xdocs/index.xml
@@ -29,8 +29,7 @@
 
     <section name="Overview">
       <p> Fulcrum YAFFI Crypto Library is an extension library for Fulcrum YAAFI to support
-        transparent decryption of configuration files. The encryption/decryption is based on DES
-        using 56 bit key length. </p>
+        transparent decryption of configuration files. The encryption/decryption is based by default on <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html" target="blank_">PBEWith&lt;digest&gt;And&lt;encryption&gt;</a> algorithm (PBEWithHmacSHA256AndAES_256) with 128bit key length.</p>
     </section>
 
     <section name="Functionality">
@@ -42,7 +41,7 @@
       </p>
       <subsection name="Password Creation">
         <p> Why someone need a password factory to create safer password?! People tend to use weak
-          password vunerable to dictionary attacks. To improve the situation you have a base
+          password vulnerable to dictionary attacks. To improve the situation you have a base
           password which you convert into the real password using the PasswordFactory. For the
           password generation the base password is salted and repeatedly hashed to generate a UUID
           string (which you can still manually enter on the keyboard). Furthermore the password
@@ -96,11 +95,32 @@
           <tr>
             <td>JDK 1.6.x</td>
             <td> The current JDK's have the JCA built-in therefore no extra configuration is
-              required. </td>
+              required. 
+              <a href="https://docs.oracle.com/javase/6/docs/technotes/guides/security/SunProviders.html">
+            Java Cryptography Architecture Sun Providers Documentation for JavaTM Platform Standard Edition 6</a>
+               </td>
+          </tr>
+          <tr>
+            <td>JDK 1.7.x</td>
+            <td> <a href="https://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html">
+            Java Cryptography Architecture Oracle Providers Documentation for Java Platform Standard Edition 7</a>
+            </td>
+          </tr>
+          <tr>
+            <td>JDK 1.8.x</td>
+            <td> <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html">
+            Java Cryptography Architecture Oracle Providers Documentation for JDK 8</a>
+            </td>
+          </tr>
+           <tr>
+            <td>JDK 14</td>
+            <td> <a href="https://docs.oracle.com/en/java/javase/14/security/java-cryptography-architecture-jca-reference-guide.html">
+            Java Cryptography Architecture Oracle Providers Documentation for JDK 14</a>
+            </td>
           </tr>
         </table>
       </subsection>
-      <subsection name="Availabe Algorithms">
+      <subsection name="Availabe Cipher Algorithms (Algorithm Modes)">
         <table>
           <tr>
             <th>Provider Version</th>
@@ -112,12 +132,19 @@
           </tr>
           <tr>
             <td>SunJCE 1.42</td>
-            <td> PBEWithMD5AndDES </td>
+            <td>PBEWithMD5AndDES</td>
+          </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>
-
+     </section>
   </body>
 
 </document>