- allow algorithm mode in cli mode
- add test in Main8Test to test different operation modes / algo
- allow reading hexadecimal encrypted code from file
- fix test log4j2
- remove class field useClearTextHeader in CryptoUtil, add methods instead

git-svn-id: https://svn.apache.org/repos/asf/turbine/fulcrum/trunk/yaafi-crypto@1866395 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index a090b32..f7fc829 100644
--- a/pom.xml
+++ b/pom.xml
@@ -72,13 +72,20 @@
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-core</artifactId>
       <version>${turbine.log4j2.version}</version>
-      <scope>test</scope>
+      <scope>test</scope><!-- chnage to provided ? -->
     </dependency>
   </dependencies>
 
   <build>
     <sourceDirectory>${basedir}/src/java</sourceDirectory>
     <testSourceDirectory>${basedir}/src/test</testSourceDirectory>
+    <testResources>
+      <testResource>
+        <directory>src/test</directory>
+        <includes> <include>**/*.xml</include>
+        </includes>
+      </testResource>
+    </testResources>
   </build>
   
   <properties>
diff --git a/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactory.java b/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactory.java
index 9957c0c..5a4e5be 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactory.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactory.java
@@ -133,5 +133,11 @@
      */
     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 35078ee..21334b5 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactoryImpl.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/CryptoStreamFactoryImpl.java
@@ -143,6 +143,7 @@
     /**
      * @return Returns the algorithm.
      */
+    @Override
     public String getAlgorithm()
     {
         return algorithm;
diff --git a/src/java/org/apache/fulcrum/jce/crypto/CryptoUtil.java b/src/java/org/apache/fulcrum/jce/crypto/CryptoUtil.java
index 17b5130..81f8d3a 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/CryptoUtil.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/CryptoUtil.java
@@ -42,12 +42,13 @@
     /** the default instance */
     private static CryptoUtil instance;
     
-    protected boolean useClearTextHeader = false; // backward compatible
+    
+    private CryptoStreamFactory cryptoStreamFactory;
     
     /**
      * Factory method to get a default instance
      * 
-     * @return an instance of the CryptoStreamFactory
+     * @return an instance of the CryptoUtil
      */
     public synchronized static CryptoUtil getInstance() {
         if (CryptoUtil.instance == null) {
@@ -56,6 +57,13 @@
 
         return CryptoUtil.instance;
     }
+    
+    /**
+     * 
+     */
+    protected CryptoUtil() {
+        cryptoStreamFactory = CryptoStreamFactoryImpl.getInstance();
+    }
 
     /**
      * Copies from a source to a target object using encryption
@@ -90,36 +98,18 @@
         StreamUtil.copy(is, eos);
     }
 
+    
     /**
-     * Copies from a source to a target object using decryption.
+     * Encrypts a string into a hex string using {@link CryptoParametersJ8#CLEAR_CODE_J8}
      *
-     * @param source   the source object
-     * @param target   the target object
-     * @param password the password to use for decryption
+     * @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 void decrypt(Object source, Object target, char[] password) throws GeneralSecurityException, IOException {
-        decrypt(getCryptoStreamFactory(), source, target, 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
-     */
-    public 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 String encryptStringWithClearCode(String plainText, char[] password) throws GeneralSecurityException, IOException {
+        return encryptString(getCryptoStreamFactory(), plainText, password, true);
     }
 
     /**
@@ -132,7 +122,7 @@
      * @throws IOException              accessing the souce failed
      */
     public String encryptString(String plainText, char[] password) throws GeneralSecurityException, IOException {
-        return encryptString(getCryptoStreamFactory(), plainText, password);
+        return encryptString(getCryptoStreamFactory(), plainText, password, false);
     }
 
     /**
@@ -141,17 +131,47 @@
      * @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)
+    public String encryptString(CryptoStreamFactory factory, String plainText, char[] password, boolean withClearCode)
             throws GeneralSecurityException, IOException {
         ByteArrayOutputStream bais = new ByteArrayOutputStream();
         encrypt(factory, plainText, bais, password);
-        return (useClearTextHeader)? CryptoParametersJ8.CLEAR_CODE_J8 + HexConverter.toString(bais.toByteArray()):
+        return (withClearCode)? CryptoParametersJ8.CLEAR_CODE_J8 + HexConverter.toString(bais.toByteArray()):
             HexConverter.toString(bais.toByteArray());
     }
+    
+    /**
+     * Copies from a source to a target object using decryption.
+     *
+     * @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
+     */
+    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_J8}.
+     *
+     * @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(CryptoParametersJ8.CLEAR_CODE_J8.length()), password);
+    }
 
     /**
      * Decrypts an encrypted string into the plain text. The encrypted string must
@@ -164,12 +184,46 @@
      * @throws IOException              accessing the souce failed
      */
     public String decryptString(String cipherText, char[] password) throws GeneralSecurityException, IOException {
-        return decryptString(getCryptoStreamFactory(), (useClearTextHeader)?
+        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_J8.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
+     */
+    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);
+    }
+
+    /**
      * Decrypts an encrypted string into the plain text. The encrypted string must
      * be a hex string created by encryptString.
      *
@@ -205,6 +259,7 @@
      * @return the CryptoStreamFactory to be used
      */
     public CryptoStreamFactory getCryptoStreamFactory() {
-        return CryptoStreamFactoryImpl.getInstance();
+        return cryptoStreamFactory;
     }
+    
 }
diff --git a/src/java/org/apache/fulcrum/jce/crypto/StreamUtil.java b/src/java/org/apache/fulcrum/jce/crypto/StreamUtil.java
index fccd6d9..2fe609c 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/StreamUtil.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/StreamUtil.java
@@ -27,6 +27,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.stream.IntStream;
 
 /**
  * Helper class to provde generic stream functions.
diff --git a/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamGCMImpl.java b/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamGCMImpl.java
index 85133ee..75ca0c2 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamGCMImpl.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamGCMImpl.java
@@ -43,7 +43,7 @@
  * implementation uses the JCA (Java Crypto Extension) supplied
  * by SUN (using SunJCE 1.42).
  *
- * The implementation uses @see {@link CryptoParametersJ8#ALGORITHM_J8_GCM} for encryption which
+ * 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
@@ -67,7 +67,7 @@
         this.salt =  generateSalt();
         this.count = CryptoParametersJ8.COUNT_J8;// not used
         this.providerName = PROVIDERNAME;
-        this.algorithm = CryptoParametersJ8.ALGORITHM_J8_GCM;
+        this.algorithm = CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_GCM.getAlgorithm();
     }
 
 
@@ -82,7 +82,7 @@
         this.salt = salt;
         this.count = count;
         this.providerName = PROVIDERNAME;
-        this.algorithm = CryptoParametersJ8.ALGORITHM_J8_GCM;
+        this.algorithm = CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_GCM.getAlgorithm();
     }
 
     /**
diff --git a/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamPBEImpl.java b/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamPBEImpl.java
index e45cebf..256a15d 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamPBEImpl.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/algo/CryptoStreamPBEImpl.java
@@ -72,7 +72,7 @@
         this.salt =  generateSalt();
         this.count = CryptoParametersJ8.COUNT_J8;
         this.providerName = PROVIDERNAME;
-        this.algorithm = CryptoParametersJ8.ALGORITHM_J8_PBE;
+        this.algorithm = CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_PBE.getAlgorithm();
     }
     
     /**
@@ -86,7 +86,7 @@
         this.salt = salt;
         this.count = count;
         this.providerName = PROVIDERNAME;
-        this.algorithm = CryptoParametersJ8.ALGORITHM_J8_PBE;
+        this.algorithm = CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_PBE.getAlgorithm();
     }
 
     /**
diff --git a/src/java/org/apache/fulcrum/jce/crypto/cli/CLI2.java b/src/java/org/apache/fulcrum/jce/crypto/cli/CLI2.java
index 9ec83bb..81e747c 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/cli/CLI2.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/cli/CLI2.java
@@ -1,5 +1,7 @@
 package org.apache.fulcrum.jce.crypto.cli;
 
+import java.io.BufferedReader;
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -24,8 +26,20 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.Reader;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Arrays;
+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.CryptoParametersJ8.TYPES;
 import org.apache.fulcrum.jce.crypto.extended.CryptoUtilJ8;
 
 /**
@@ -36,7 +50,7 @@
  * 
  * Example :
  * 
- * java -classpath target/classes org.apache.fulcrum.jce.crypto.cli.Main string enc changeit mysecretgeheim
+ * java -classpath target/classes org.apache.fulcrum.jce.crypto.cli.CLI2 string enc changeit mysecretgeheim
  * ...
  * 
  * java -cp target/classes org.apache.fulcrum.jce.crypto.cli.Main string dec changeit J8_AES256;<hashcode>
@@ -55,14 +69,29 @@
     {
         try
         {
+
+            String operationMode = args[0];
+            
+            String msg = "No operationMode" ;
+            if (operationMode == null || operationMode.equals("")) {
+                throw new IllegalArgumentException(msg);
+            }
+            
+            if( operationMode.equals("info") )
+            {
+                printInfo();
+                return;
+            } else if (operationMode.equals("help") ) {
+                printHelp();
+                return;
+            }
+            
             if( args.length < 3 )
             {
                 printHelp();
                 throw new IllegalArgumentException("Invalid command line");
             }
 
-            String operationMode = args[0];
-
 
             if( operationMode.equals("file") )
             {
@@ -76,19 +105,38 @@
         catch (Exception e)
         {
             System.out.println("Error : " + e.getMessage());
+            e.printStackTrace();
         }
     }
 
+    private static void printInfo() {
+        CryptoUtilJ8 cryptoUtilJ8 = CryptoUtilJ8.getInstance();
+        System.out.println("\tCrypto factory class: " + cryptoUtilJ8.getCryptoStreamFactory().getClass());
+        System.out.println("\tDefault Algorithm used: " + cryptoUtilJ8.getCryptoStreamFactory().getAlgorithm());
+        String algoShortList= Arrays.stream(CryptoParametersJ8.TYPES.values()).map(t-> t.toString()).collect(Collectors.joining(","));
+        System.out.println("\tAlgorithms (shortcut) available: " + algoShortList);
+        String algoList= Arrays.stream(CryptoParametersJ8.TYPES_IMPL.values()).map(t-> t.toString()).collect(Collectors.joining(", "));
+        System.out.println("\tAlgorithms available: " + algoList);
+        System.out.println("\tMore Info: https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html");
+    }
+
     /**
      * Prints usage information.
      */
     public static void printHelp()
     {
-        System.out.println("\r\n*** Command line tool for encrypting/decrypting strings/files ***\r\n*** algorithm based on "+ CryptoParametersJ8.ALGORITHM_J8_PBE+ "***\r\n");
+        System.out.println("\r\n*** Command line tool for encrypting/decrypting strings/files ***\r\n*** algorithm based on "+ CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_PBE+ "***\r\n");
+        System.out.println("java -cp target\\classes; "+ CLI2.class.getName()+ " <operation mode> <coding mode> <password> <path|string> [target]");
         System.out.println( "*** Usage: ***\r\n");
-        System.out.println("java -cp target\\classes; "+ CLI2.class.getName()+ " <operation mode:file|string> <coding mode:enc|dec> <password> <path|string> [target]\r\ne.g.\r\n");
+        System.out.println("java -cp target\\classes; "+ CLI2.class.getName()+ " <operation mode:file|string|info> <coding mode:enc<optional:algoshortcut>|dec<optional:algoshortcut>> <password> <code|coderef> [target]\r\ne.g.\r\n");
+        System.out.println("operation mode: file|string|info");
+        System.out.println("coding mode: enc|dec|enc:GCM. Default algorithm is " + TYPES.PBE);
+        System.out.println("<password: string or empty:''");
+        System.out.println("code|coderef: path|string");
+        System.out.println("target: ");
         System.out.println( CLI2.class.getSimpleName()+ " file [enc|dec] passwd source [target]");
         System.out.println(CLI2.class.getSimpleName() + " string [enc|dec] passwd source");
+        System.out.println(CLI2.class.getSimpleName() + " info");
     }
 
     /**
@@ -125,7 +173,7 @@
     /**
      * Decrypt/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
      * @throws Exception the operation failed
@@ -133,40 +181,73 @@
     public static void processFile(String cipherMode, char[] password, File sourceFile, File targetFile)
         throws Exception
     {
-        FileInputStream fis = new FileInputStream(sourceFile);
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        
-        CryptoUtilJ8 cryptoUtilJ8 = CryptoUtilJ8.getInstance();
-
-        if( cipherMode.equals("dec") )
-        {
-            System.out.println("Decrypting " + sourceFile.getAbsolutePath() );
-            cryptoUtilJ8.decrypt( fis, baos, password );
-            fis.close();
-
-            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-            FileOutputStream fos = new FileOutputStream(targetFile);
-            CryptoUtilJ8.copy(bais,fos);
-            bais.close();
-            fos.close();
+                
+        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(new String(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);
+            }
         }
-        else if( cipherMode.equals("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);
-            CryptoUtilJ8.copy(bais,fos);
-            bais.close();
-            fos.close();
+    private static CryptoUtilJ8 createCryptoUtil(String cipherMode) throws Exception {
+        CryptoUtilJ8 cryptoUtilJ8 = null;
+        if (cipherMode.endsWith(TYPES.PBE.toString()) || cipherMode.substring("enc".length()).equals("") ) {
+            cryptoUtilJ8 = CryptoUtilJ8.getInstance();
+        } else {
+            Optional<TYPES> algoShortcut = Arrays.stream(CryptoParametersJ8.TYPES.values()).filter(a-> cipherMode.endsWith(a.toString())).findFirst(); //.collect(Collectors.toList());
+            if (algoShortcut.isPresent()) {
+                cryptoUtilJ8 = CryptoUtilJ8.getInstance(algoShortcut.get());
+            }
         }
-        else
-        {
-            String msg = "Don't know what to do with : " + cipherMode;
-            throw new IllegalArgumentException(msg);
+        if (cryptoUtilJ8 == null) {
+            throw new Exception("Could not find any algorithms. check provided alog shortcuts with CLI2 info!");
         }
+        return cryptoUtilJ8;
     }
 
     /**
@@ -180,20 +261,47 @@
     {
         String cipherMode = args[1];
         char[] password = args[2].toCharArray();
-        String value = args[3];
-        String result = null;
+        String value = args[3];        
+        File targetFile = null;
         
-        CryptoUtilJ8 cryptoUtilJ8 = CryptoUtilJ8.getInstance();
+        if( args.length == 5 ) {
+            targetFile = new File(args[4]);
+            File parentFile = targetFile.getParentFile(); 
 
-        if( cipherMode.equals("dec") )
-        {
-            result = cryptoUtilJ8.decryptString(value,password);
+            if(parentFile != null)
+            {
+                parentFile.mkdirs();
+            }
         }
-        else
-        {
-            result = cryptoUtilJ8.encryptString(value,password);
+        
+        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);
+            }
+    
+            System.out.println( result );
+            
+            if (targetFile != null) {
+                try ( FileOutputStream outputStream = new FileOutputStream(targetFile)) {
+                    outputStream.write(result.getBytes());         
+                }
+            }
         }
+    }
+    
+    private static final Pattern HEXADECIMAL_PATTERN = Pattern.compile("\\p{XDigit}+");
 
-        System.out.println( result );
+    public static boolean isHexadecimal(String input) {
+        final Matcher matcher = HEXADECIMAL_PATTERN.matcher(input);
+        return matcher.matches();
     }
 }
\ No newline at end of file
diff --git a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoParametersJ8.java b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoParametersJ8.java
index 8195819..b185ea7 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoParametersJ8.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoParametersJ8.java
@@ -46,8 +46,24 @@
      *  
      *  <li>AES/GCM/NoPadding 
      */
-    String ALGORITHM_J8_PBE = "PBEWithHmacSHA256AndAES_256"; //"PBEWithHmacSHA256AndAES_128 ";
-    String ALGORITHM_J8_GCM = "AES/GCM/NoPadding";
+    
+    public enum TYPES_IMPL {
+        ALGORITHM_J8_PBE("PBEWithHmacSHA256AndAES_256"), 
+        ALGORITHM_J8_GCM("AES/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;
+        }
+    }
     
     public enum TYPES {
         PBE, GCM
diff --git a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8Impl.java b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8Impl.java
index c692d29..87f1418 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8Impl.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8Impl.java
@@ -111,7 +111,7 @@
         this.salt =  generateSalt();
         this.count = CryptoParametersJ8.COUNT_J8;
         this.providerName = PROVIDERNAME;
-        this.algorithm = CryptoParametersJ8.ALGORITHM_J8_PBE;
+        this.algorithm = CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_PBE.getAlgorithm();
     }
     
     /**
@@ -136,7 +136,7 @@
         this.salt = salt;
         this.count = count;
         this.providerName = PROVIDERNAME;
-        this.algorithm = CryptoParametersJ8.ALGORITHM_J8_PBE;
+        this.algorithm = CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_PBE.getAlgorithm();
     }
 
 
diff --git a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8Template.java b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8Template.java
index aef5e35..1753d7c 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8Template.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoStreamFactoryJ8Template.java
@@ -52,7 +52,7 @@
     protected static final int KEY_SIZE = 256;
 
     /** the default instances */
-    protected static Map<TYPES,CryptoStreamFactoryJ8Template> instances = new ConcurrentHashMap();
+    protected static Map<TYPES,CryptoStreamFactoryJ8Template> instances = new ConcurrentHashMap<>();
     
     protected AlgorithmParameters algorithmParameters;// used only for debugging
    
@@ -97,8 +97,8 @@
         this.salt = salt;
         this.count = count;
         this.providerName = PROVIDERNAME;
-        this.algorithm = type.equals(TYPES.PBE)? CryptoParametersJ8.ALGORITHM_J8_PBE:
-            CryptoParametersJ8.ALGORITHM_J8_GCM;
+        this.algorithm = type.equals(TYPES.PBE)? CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_PBE.getAlgorithm():
+            CryptoParametersJ8.TYPES_IMPL.ALGORITHM_J8_GCM.getAlgorithm();;
     }
 
 
@@ -122,8 +122,8 @@
     public InputStream getInputStream( InputStream is, char[] password )
         throws GeneralSecurityException, IOException
     {
-        byte[] encrypted =  this.createCipher( is, Cipher.DECRYPT_MODE, password );
-        InputStream eis = new ByteArrayInputStream(encrypted);
+        byte[] decrypted =  this.createCipher( is, Cipher.DECRYPT_MODE, password );
+        InputStream eis = new ByteArrayInputStream(decrypted);
         return eis;
     }
 
diff --git a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8.java b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8.java
index 848834a..723e340 100644
--- a/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8.java
+++ b/src/java/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8.java
@@ -30,6 +30,9 @@
 import org.apache.fulcrum.jce.crypto.CryptoUtil;
 import org.apache.fulcrum.jce.crypto.StreamUtil;
 import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8.TYPES;
+import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8.TYPES_IMPL;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 /**
  * Helper class to provde generic functions to work with CryptoStreams.
@@ -45,14 +48,14 @@
 
     
     public TYPES type;// default see instance
-   
+       
     
     public TYPES getType() {
         return type;
     }
 
     /** the typed default instances */    
-    private static Map<TYPES,CryptoUtilJ8> cryptoUtilJ8s = new ConcurrentHashMap();
+    private static Map<TYPES,CryptoUtilJ8> cryptoUtilJ8s = new ConcurrentHashMap<>();
     
     
     /**
@@ -67,7 +70,6 @@
             {
                 cryptoUtilJ8s.put(type, new CryptoUtilJ8(type) );
             }
-    
             return cryptoUtilJ8s.get(type);
         }
     }
@@ -81,20 +83,22 @@
     public static CryptoUtilJ8 getInstance()
     {
         synchronized (CryptoUtilJ8.class) {
-            if( cryptoUtilJ8s.isEmpty() && !cryptoUtilJ8s.containsKey(TYPES.PBE) )
+            TYPES defaultType = TYPES.PBE;
+            if( cryptoUtilJ8s.isEmpty() && !cryptoUtilJ8s.containsKey(defaultType) )
             {
-                cryptoUtilJ8s.put(TYPES.PBE, new CryptoUtilJ8(TYPES.PBE) );
+                cryptoUtilJ8s.put(defaultType, new CryptoUtilJ8(defaultType) );
             }
-    
-            return cryptoUtilJ8s.get(TYPES.PBE);
+            return cryptoUtilJ8s.get(defaultType);
         }
     }
     
-    public CryptoUtilJ8(TYPES type) {
+    private CryptoUtilJ8(TYPES type) {
+        super();
         this.type = type;
     }
     
-    public CryptoUtilJ8() {
+    private CryptoUtilJ8() {
+        super();
     }
 
     /**
@@ -129,7 +133,7 @@
      * @throws IOException              accessing the source failed
      */
     @Override
-    public void decrypt(CryptoStreamFactory factory, Object source, Object target, char[] password)
+    protected void decrypt(CryptoStreamFactory factory, Object source, Object target, char[] password)
             throws GeneralSecurityException, IOException {
         InputStream is = StreamUtil.createInputStream(source);
         OutputStream os = StreamUtil.createOutputStream(target);
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/org/apache/fulcrum/jce/crypto/CryptoUtilTest.java b/src/test/org/apache/fulcrum/jce/crypto/CryptoUtilTest.java
index 7e0aa5f..bab0e8a 100644
--- a/src/test/org/apache/fulcrum/jce/crypto/CryptoUtilTest.java
+++ b/src/test/org/apache/fulcrum/jce/crypto/CryptoUtilTest.java
@@ -22,6 +22,10 @@
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 
+import org.apache.fulcrum.jce.crypto.extended.CryptoUtilJ8ParameterizedTest;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 import junit.framework.TestCase;
 
 /**
@@ -39,6 +43,8 @@
 
 	/** the temp data director */
 	private File tempDataDirectory;
+	
+	private static Logger log = LogManager.getLogger(CryptoUtilTest.class);
 
 	/**
 	 * Constructor
@@ -297,7 +303,7 @@
 		result = PasswordFactory.getInstance().create();
 		System.out.println(new String(result));
 		result = PasswordFactory.getInstance().create(this.getPassword());
-		System.out.println(new String(result));
+		log.info(new String(result));
 		assertNotNull(result);
 		return;
 	}
@@ -319,7 +325,7 @@
 		char[] password = "57cb-4a23-d838-45222".toCharArray();
 		String source = "e02c-3b76-ff1e-5d9a1";
 		String cipherText = CryptoUtil.getInstance().encryptString(source, password);
-		System.out.println(cipherText);// len 48
+		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/SmartDecryptingInputStreamTest.java b/src/test/org/apache/fulcrum/jce/crypto/SmartDecryptingInputStreamTest.java
index ca4ebb4..1c0cd0e 100644
--- a/src/test/org/apache/fulcrum/jce/crypto/SmartDecryptingInputStreamTest.java
+++ b/src/test/org/apache/fulcrum/jce/crypto/SmartDecryptingInputStreamTest.java
@@ -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;
@@ -202,7 +202,7 @@
             this.getPassword()
             );
 
-        CryptoUtil.copy(sdis,baos);
+        StreamUtil.copy(sdis,baos);
 
         return new String( baos.toByteArray(), enc );
     }
@@ -224,7 +224,7 @@
             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/CryptoUtilJ8ParameterizedTest.java b/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8ParameterizedTest.java
index 6b57a51..3339354 100644
--- a/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8ParameterizedTest.java
+++ b/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8ParameterizedTest.java
@@ -3,6 +3,7 @@
 
 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;
@@ -15,9 +16,9 @@
 import java.util.List;
 
 import org.apache.fulcrum.jce.crypto.PasswordFactory;
-import org.apache.fulcrum.jce.crypto.extended.CryptoStreamFactoryJ8Template;
-import org.apache.fulcrum.jce.crypto.extended.CryptoUtilJ8;
 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.AfterEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -41,6 +42,7 @@
     
     private List<CryptoUtilJ8> cryptoUtilJ8s = new ArrayList<>();
     
+    private static Logger log = LogManager.getLogger(CryptoUtilJ8ParameterizedTest.class);
 
     /**
      * Constructor
@@ -99,7 +101,7 @@
         
         cryptoUtilJ8s.forEach(cuj8 -> {
             try {
-                System.out.println("checking "+ cuj8.getType());
+                log.info("checking "+ cuj8.getType());
                 cuj8.encrypt(sourceFile, targetFile, this.getPassword());
             } catch (GeneralSecurityException e) {
                 e.printStackTrace();
@@ -119,7 +121,7 @@
     public void testTextDecryption(TYPES type) {
         cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
             cryptoUtilJ8s.forEach(cuj8 -> {
-                System.out.println("checking "+ cuj8.getType());
+                log.info("checking "+ cuj8.getType());
                 try {
                     File sourceFile = new File(this.getTestDataDirectory(), "plain.txt");
                     File targetFile = new File(this.getTempDataDirectory(), "plain.j8.enc.txt");
@@ -197,7 +199,7 @@
     @ParameterizedTest
     @EnumSource( TYPES.class )
     public void testStringEncryption(TYPES type) {
-        cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
+        CryptoUtilJ8 cuj8= CryptoUtilJ8.getInstance(type);
         char[] testVector = new char[513];
 
         for (int i = 0; i < testVector.length; i++) {
@@ -205,21 +207,25 @@
         }
 
         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();
-            }
-           
-        });
-        
-
+        String cipherText = null;
+        String plainText = null;
+        try {
+            log.debug("without clearTextHeader");
+            cipherText = cuj8.encryptString(source, this.getPassword());
+            plainText = cuj8.decryptString(cipherText, this.getPassword());
+            assertEquals(source, plainText, source +" is not equal with " + plainText);
+            
+            log.debug("with clearTextHeader in encrypted string:" + CryptoParametersJ8.CLEAR_CODE_J8);
+            String cipherText2 = cuj8.encryptStringWithClearCode(source, this.getPassword());
+            
+            assertTrue(cipherText2.startsWith(CryptoParametersJ8.CLEAR_CODE_J8), cipherText2 +" does not start with " + CryptoParametersJ8.CLEAR_CODE_J8);
+            String plainText2 = cuj8.decryptStringWithClearCode(cipherText2, this.getPassword());
+            assertEquals(source, plainText2, source +" is not equal with " + plainText);
+            
+        } catch (GeneralSecurityException | IOException e) {
+            e.printStackTrace();
+            fail();
+        }
     }
 
     /** Test encryption and decryption of Strings
@@ -252,9 +258,9 @@
     public void testPasswordFactory() throws Exception {
         char[] result = null;
         result = PasswordFactory.getInstance("SHA-256").create();
-        System.out.println("random pw:" + new String(result));
+        log.info("random pw:" + new String(result));
         result = PasswordFactory.getInstance("SHA-256",10_000).create(this.getPassword());
-        System.out.println("password pw with seed:" + new String(result));
+        log.info("password pw with seed:" + new String(result));
         assertNotNull(result);
         return;
     }
@@ -304,28 +310,23 @@
     public void testStringWithPasswordEncryption(TYPES type) {
         char[] password = "57cb-4a23-d838-45222".toCharArray();
         String source = "e02c-3b76-ff1e-5d9a1";
-        cryptoUtilJ8s.add(CryptoUtilJ8.getInstance(type));
-        cryptoUtilJ8s.forEach(cuj8 -> { 
-            System.out.println("checking "+ cuj8.getType());
-            String cipherText = null;
-            try {
-                cipherText = cuj8.encryptString(source, password);
-                System.out.println(cipherText);// about 128
-                
-                System.out.println("length for " + cuj8.getType() + " is:" +cipherText.length());// about 128
-                if (cuj8.type == TYPES.PBE) {
-                    assertEquals(128, cipherText.length()); // 128bytes + 10 bytes for cleartext
-                } 
-                CryptoStreamFactoryJ8Template.setInstance(null);
-                String plainText = cuj8.decryptString(cipherText, password);
-                assertEquals(source, plainText);
-            } catch (GeneralSecurityException | IOException e) {
-                e.printStackTrace();
-                fail();
-            }
-            
-        });      
-
+        CryptoUtilJ8 cuj8 = CryptoUtilJ8.getInstance(type);
+        log.debug("checking "+ cuj8.getType());
+        String cipherText = null;
+        try {
+            cipherText = cuj8.encryptString(source, password);
+            log.info(cipherText);// about 128 
+            log.info("length for " + cuj8.getType() + " is:" +cipherText.length());// about 128
+            if (cuj8.type == TYPES.PBE) {
+                assertEquals(128, cipherText.length()); // 128bytes + 10 bytes for cleartext
+            } 
+            CryptoStreamFactoryJ8Template.setInstance(null);
+            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
index 9a4d013..b8d4e54 100644
--- a/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8Test.java
+++ b/src/test/org/apache/fulcrum/jce/crypto/extended/CryptoUtilJ8Test.java
@@ -74,11 +74,6 @@
         cryptoUtilJ8s.clear();
     }
     
-//    @ParameterizedTest
-//    @EnumSource( TYPES.class )
-//    public void setUp(TYPES type) throws Exception {
-//        cryptoUtilJ8 = CryptoUtilJ8.getInstance(type); // (TYPES.PBE);
-//    }
 
     /**
      * @return Returns the password.
diff --git a/src/test/org/apache/fulcrum/jce/crypto/extended/Main8Test.java b/src/test/org/apache/fulcrum/jce/crypto/extended/Main8Test.java
index 1d85649..af6a902 100644
--- a/src/test/org/apache/fulcrum/jce/crypto/extended/Main8Test.java
+++ b/src/test/org/apache/fulcrum/jce/crypto/extended/Main8Test.java
@@ -1,6 +1,13 @@
 package org.apache.fulcrum.jce.crypto.extended;
 
+import static org.junit.jupiter.api.Assertions.fail;
+
 import org.apache.fulcrum.jce.crypto.cli.CLI2;
+import org.apache.fulcrum.jce.crypto.extended.CryptoParametersJ8.TYPES;
+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.Test;
 
 /*
@@ -32,7 +39,7 @@
 public class Main8Test
 {
     /** the password to be used */
-    static private String password;
+    private String password;
     
     /**
      * Constructor
@@ -40,6 +47,8 @@
     public Main8Test() {
 
         this.password = "foobar";
+        ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
+        builder.setStatusLevel(Level.DEBUG);
     }
    
 
@@ -87,5 +96,30 @@
         CLI2.main(encryptionArgs);
         CLI2.main(decryptionArgs);
     }
+    
+    @Test
+    public void testYetAnotherStringEncryption()
+    {
+        try {
+            String[] encryptionArgs = { "string", "enc"+TYPES.GCM, this.password, "mysecretpassword",  "./target/main8/another-plain.enc.txt"};
+            CLI2.main(encryptionArgs);
+            String[] decryptionArgs = { "string", "dec"+TYPES.GCM, this.password, "c9fa3e7d3c49d379ee8ff2dff6e6effbafee264794a03d0ffd895caac2b3c9b4558087f5b12e72a92475f1ed638b7911389234b443d4ebcf351c86cb", "./target/main8/another-plain.dec.txt"};
+            CLI2.main(decryptionArgs);
+            String[] decryptionArgs2 = { "string", "dec"+TYPES.GCM, this.password, "605efd3009a7242a9c9cab23aa712d6d116e8686732194d3306416cda2a416df1e63aeffcdc1910af1e1100b382b24fc628d9c413ebf7e1b2885c0ec"};
+            CLI2.main(decryptionArgs2);
+            
+            // should not fail, if converted from hex
+            String[] decryptionArgs3 = { "file", "dec"+TYPES.GCM, this.password, "./target/main8/another-plain.enc.txt", "./target/main8/another-plain.dec.txt"};
+            CLI2.main(decryptionArgs3);
+            
+            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);
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail();
+        }
+    }
 
 }
\ No newline at end of file
diff --git a/xdocs/index.xml b/xdocs/index.xml
index 5e282cc..67a1c6b 100644
--- a/xdocs/index.xml
+++ b/xdocs/index.xml
@@ -131,7 +131,7 @@
           </tr>
            <tr>
             <td>SunJCE (Java 8)</td>
-            <td>PBEWithHmacSHA256AndAES_128</td>
+            <td>PBEWithHmacSHA256AndAES_256</td>
           </tr>
         </table>
       </subsection>