[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 "${meta.pw}" "${password_encrypted}"."/>
+ <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 "${meta.pw}" "${password}""/>
+ <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 <digest>And<encryption> - 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_<size>;</pre>.
+ * {@link CryptoParametersJ8#CLEAR_CODE_DEFAULT}
+ *
+ * @return clear code J8AES_<size>; 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<digest>And<encryption></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>