From 11a3456c5307abbe1fd83ff847da0643fbfb97ae Mon Sep 17 00:00:00 2001 From: Captain ALM Date: Wed, 13 Jul 2022 15:53:09 +0100 Subject: [PATCH] Initial commit. --- .gitignore | 30 ++ .idea/.gitignore | 8 + .idea/discord.xml | 7 + .idea/misc.xml | 6 + .idea/modules.xml | 8 + .idea/runConfigurations.xml | 10 + LICENSE | 29 ++ README.md | 7 + calmstdcrypt.iml | 11 + .../lib/stdcrypt/digest/DigestComparer.java | 42 ++ .../lib/stdcrypt/digest/DigestProvider.java | 190 +++++++++ .../lib/stdcrypt/digest/package-info.java | 6 + .../AESPasswordRfc2898CipherFactory.java | 367 ++++++++++++++++++ .../stdcrypt/encryption/CipherException.java | 60 +++ .../stdcrypt/encryption/ICipherFactory.java | 71 ++++ .../lib/stdcrypt/encryption/package-info.java | 6 + .../captainalm/lib/stdcrypt/package-info.java | 8 + 17 files changed, 866 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/discord.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 calmstdcrypt.iml create mode 100644 src/com/captainalm/lib/stdcrypt/digest/DigestComparer.java create mode 100644 src/com/captainalm/lib/stdcrypt/digest/DigestProvider.java create mode 100644 src/com/captainalm/lib/stdcrypt/digest/package-info.java create mode 100644 src/com/captainalm/lib/stdcrypt/encryption/AESPasswordRfc2898CipherFactory.java create mode 100644 src/com/captainalm/lib/stdcrypt/encryption/CipherException.java create mode 100644 src/com/captainalm/lib/stdcrypt/encryption/ICipherFactory.java create mode 100644 src/com/captainalm/lib/stdcrypt/encryption/package-info.java create mode 100644 src/com/captainalm/lib/stdcrypt/package-info.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6420f34 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Built files +out/ + +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..1c2fda5 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/discord.xml b/.idea/discord.xml new file mode 100644 index 0000000..d8e9561 --- /dev/null +++ b/.idea/discord.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..c14dbda --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..6882990 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..93e4b17 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7fbe392 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022, Captain ALM +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..90a03b9 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Captain ALM Standard Crypto Library (Java) + +This is my standard cryptographic library that wraps the java cryptographic functions. + +This application targets Java 8. + +(C) Captain ALM 2022 - Under the BSD 3-Clause License diff --git a/calmstdcrypt.iml b/calmstdcrypt.iml new file mode 100644 index 0000000..9465dd8 --- /dev/null +++ b/calmstdcrypt.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/com/captainalm/lib/stdcrypt/digest/DigestComparer.java b/src/com/captainalm/lib/stdcrypt/digest/DigestComparer.java new file mode 100644 index 0000000..a8ae61f --- /dev/null +++ b/src/com/captainalm/lib/stdcrypt/digest/DigestComparer.java @@ -0,0 +1,42 @@ +package com.captainalm.lib.stdcrypt.digest; + +import java.io.IOException; +import java.io.InputStream; + +/** + * This class provides the ability to compare digests. + * + * @author Captain ALM + */ +public class DigestComparer { + /** + * Compares two digests. + * + * @param digest1 The first digest array. + * @param digest2 The second digest array. + * @return If the digests are equivalent. + */ + public static boolean compareDigests(byte[] digest1, byte[] digest2) { + if ((digest1 == null && digest2 != null) || (digest1 != null && digest2 == null)) return false; + if (digest1 == digest2) return true; + if (digest1.length != digest2.length) return false; + for (int i = 0; i < digest1.length; i++) if (digest1[i] != digest2[i]) return false; + return true; + } + + /** + * Compares a digest from an {@link InputStream} with a digest array. + * + * @param digest1Stream The input stream digest. + * @param digest2 The digest array. + * @return If the digests are equivalent. + * @throws IOException An I/O Exception has occurred. + */ + public static boolean compareDigests(InputStream digest1Stream, byte[] digest2) throws IOException { + if (digest1Stream == null || digest2 == null) return false; + if (digest2.length == 0) return false; + int c; + for (byte b : digest2) if ((c = digest1Stream.read()) == -1 || (byte) c != b) return false; + return true; + } +} diff --git a/src/com/captainalm/lib/stdcrypt/digest/DigestProvider.java b/src/com/captainalm/lib/stdcrypt/digest/DigestProvider.java new file mode 100644 index 0000000..ba3dc86 --- /dev/null +++ b/src/com/captainalm/lib/stdcrypt/digest/DigestProvider.java @@ -0,0 +1,190 @@ +package com.captainalm.lib.stdcrypt.digest; + +import java.io.InputStream; +import java.io.OutputStream; +import java.security.DigestInputStream; +import java.security.DigestOutputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * This class allows for obtaining {@link DigestInputStream} and {@link DigestOutputStream} using the specified algorithm. + * + * @author Captain ALM + */ +public final class DigestProvider implements Cloneable { + private MessageDigest digest; + private boolean shouldClone; + + /** + * Constructs a new digest provider with the specified algorithm. + * + * @param algorithm The algorithm of the digest. + * @throws NullPointerException algorithm is null. + * @throws NoSuchAlgorithmException The algorithm does not exist. + */ + public DigestProvider(String algorithm) throws NoSuchAlgorithmException { + this(algorithm, false); + } + + /** + * Constructs a new digest provider with the specified algorithm + * and if the digest should be cloned for created streams. + * + * @param algorithm The algorithm of the digest. + * @param shouldClone The digest should be cloned when creating streams. + * @throws NullPointerException algorithm is null. + * @throws NoSuchAlgorithmException The algorithm does not exist. + */ + public DigestProvider(String algorithm, boolean shouldClone) throws NoSuchAlgorithmException { + if (algorithm == null) throw new NullPointerException("algorithm is null"); + digest = MessageDigest.getInstance(algorithm); + this.shouldClone = shouldClone; + } + + /** + * Gets the digest input stream for this class. + * NOTE: If using any other streams on this digest, and {@link #digestClonedForStreams()} is false, + * The current calculated digest for this stream changes for all the other streams. + * + * @param inputStream The input stream to get the digest for. + * @return The digest input stream. + */ + public DigestInputStream getDigestInputStream(InputStream inputStream) { + if (inputStream == null) throw new NullPointerException("inputStream is null"); + digest.reset(); + try { + return new DigestInputStream(inputStream, (shouldClone) ? (MessageDigest) digest.clone() : digest); + } catch (CloneNotSupportedException e) { + return new DigestInputStream(inputStream, digest); + } + } + + /** + * Gets the digest output stream for this class. + * NOTE: If using any other streams on this digest, and {@link #digestClonedForStreams()} is false, + * The current calculated digest for this stream changes for all the other streams. + * + * @param outputStream The output stream to get the digest for. + * @return The digest output stream. + */ + public DigestOutputStream getDigestOutputStream(OutputStream outputStream) { + if (outputStream == null) throw new NullPointerException("outputStream is null"); + digest.reset(); + try { + return new DigestOutputStream(outputStream, (shouldClone) ? (MessageDigest) digest.clone() : digest); + } catch (CloneNotSupportedException e) { + return new DigestOutputStream(outputStream, digest); + } + } + + /** + * Gets the algorithm of this provider. + * + * @return The algorithm. + */ + public String getAlgorithm() { + return digest.getAlgorithm(); + } + + /** + * Gets the length of the algorithm in bytes. + * + * @return The length in bytes. + */ + public int getLength() { + return digest.getDigestLength(); + } + + /** + * Gets whether {@link MessageDigest}s are cloned for streams. + * + * @return If the digests are cloned. + */ + public boolean digestClonedForStreams() { + return shouldClone; + } + + /** + * Gets the digest of the specified array. + * NOTE: If using any streams on this digest, and {@link #digestClonedForStreams()} is false, + * The current calculated digest for all these streams are reset. + * + * @param dataIn The byte array to find the digest of. + * @return The digest array. + */ + public byte[] getDigestOf(byte[] dataIn) { + digest.reset(); + return digest.digest(dataIn); + } + + /** + * Clones this object. + * + * @return The clone of this object. + */ + @Override + public Object clone() { + try { + return new DigestProvider(digest.getAlgorithm(), shouldClone); + } catch (NoSuchAlgorithmException e) { + return this; + } + } + + /** + * Gets the instance for MD5. + * + * @param shouldClone The digest should be cloned when creating streams. + * @return The DigestProvider for MD5 or null. + */ + public static DigestProvider getMD5Instance(boolean shouldClone) { + try { + return new DigestProvider("MD5", shouldClone); + } catch (NoSuchAlgorithmException e) { + return null; + } + } + + /** + * Gets the instance for SHA-1. + * + * @param shouldClone The digest should be cloned when creating streams. + * @return The DigestProvider for SHA-1 or null. + */ + public static DigestProvider getSHA1Instance(boolean shouldClone) { + try { + return new DigestProvider("SHA-1", shouldClone); + } catch (NoSuchAlgorithmException e) { + return null; + } + } + + /** + * Gets the instance for SHA-256. + * + * @param shouldClone The digest should be cloned when creating streams. + * @return The DigestProvider for SHA-256 or null. + */ + public static DigestProvider getSHA256Instance(boolean shouldClone) { + try { + return new DigestProvider("SHA-256", shouldClone); + } catch (NoSuchAlgorithmException e) { + return null; + } + } + + /** + * Gets the instance for SHA-512. + * + * @param shouldClone The digest should be cloned when creating streams. + * @return The DigestProvider for SHA-512 or null. + */ + public static DigestProvider getSHA512Instance(boolean shouldClone) { + try { + return new DigestProvider("SHA-512", shouldClone); + } catch (NoSuchAlgorithmException e) { + return null; + } + } +} diff --git a/src/com/captainalm/lib/stdcrypt/digest/package-info.java b/src/com/captainalm/lib/stdcrypt/digest/package-info.java new file mode 100644 index 0000000..e4c0602 --- /dev/null +++ b/src/com/captainalm/lib/stdcrypt/digest/package-info.java @@ -0,0 +1,6 @@ +/** + * This package contains the digest objects. + * + * @author Captain ALM + */ +package com.captainalm.lib.stdcrypt.digest; \ No newline at end of file diff --git a/src/com/captainalm/lib/stdcrypt/encryption/AESPasswordRfc2898CipherFactory.java b/src/com/captainalm/lib/stdcrypt/encryption/AESPasswordRfc2898CipherFactory.java new file mode 100644 index 0000000..9e661e2 --- /dev/null +++ b/src/com/captainalm/lib/stdcrypt/encryption/AESPasswordRfc2898CipherFactory.java @@ -0,0 +1,367 @@ +package com.captainalm.lib.stdcrypt.encryption; + +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidKeySpecException; + +/** + * This class provides an AES cipher that uses Rfc2898 for key generation and a string password. + * + * @author Captain ALM + */ +public class AESPasswordRfc2898CipherFactory implements ICipherFactory { + protected static final int iVectorDefaultSize = 16; + protected static final int saltDefaultSize = 32; + protected static final int iterations = 2000; + protected static final int keySize = 256; + + protected final Object slock = new Object(); + + protected String password; //Cannot be exported in settings + protected byte[] salt; + protected byte[] iVector; + protected byte[] passwordCache; + + protected boolean outputSalt; + protected boolean outputIVector; + + protected boolean haveAttributesChanged; + + /** + * Constructs a new instance of AESPasswordRfc2898CipherFactory with the specified password. + * + * @param password The password to use. + * @throws NullPointerException password is null. + */ + public AESPasswordRfc2898CipherFactory(String password) { + this(password, null, null); + } + + /** + * Constructs a new instance of AESPasswordRfc2898CipherFactory with the specified password, salt and initialization vector. + * + * @param password The password to use. + * @param salt The salt to use or null. + * @param initializationVector The initialization vector to use or null. + * @throws NullPointerException password is null. + * @throws IllegalArgumentException salt or initializationVector is larger than 255. + */ + public AESPasswordRfc2898CipherFactory(String password, byte[] salt, byte[] initializationVector) { + setPassword(password); + setSalt(salt); + setInitializationVector(initializationVector); + haveAttributesChanged = false; + } + + protected void processPasswordCache() { + if (passwordCache == null) passwordCache = password.getBytes(StandardCharsets.UTF_8); + } + + /** + * Gets a new cipher instance. + * + * @param opmode The Cipher Operation Mode ({@link Cipher#ENCRYPT_MODE}, {@link Cipher#DECRYPT_MODE}, {@link Cipher#WRAP_MODE} and {@link Cipher#UNWRAP_MODE}). + * @return The new cipher instance or null. + * @throws CipherException An Exception has occurred. + */ + @Override + public Cipher getCipher(int opmode) throws CipherException { + try { + if (salt == null || salt.length < 1) { + salt = new byte[saltDefaultSize]; + SecureRandom.getInstanceStrong().nextBytes(salt); + } + + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); + PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), salt, iterations, keySize); + SecretKeySpec secretSpec = new SecretKeySpec(keyFactory.generateSecret(pbeKeySpec).getEncoded(), "AES"); + + if (iVector == null || iVector.length < 1) { + iVector = new byte[iVectorDefaultSize]; + SecureRandom.getInstanceStrong().nextBytes(iVector); + } + AlgorithmParameterSpec ivSpec = new IvParameterSpec(iVector); + + Cipher toret = Cipher.getInstance("AES/CBC/PKCS5Padding"); + toret.init(opmode, secretSpec, ivSpec); + return toret; + } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) { + throw new CipherException(e); + } + } + + /** + * Gets the name of the cipher factory. + * + * @return The name of the cipher factory. + */ + @Override + public String getName() { + return "AES Password Rfc 2898"; + } + + /** + * Gets if the cipher settings attributes have been modified. + * Resets the flag once checked. + * + * @return If the attributes have been modified. + */ + @Override + public boolean cipherAttributesModified() { + synchronized (slock) { + boolean toret = haveAttributesChanged; + haveAttributesChanged = false; + return toret; + } + } + + /** + * Gets the cipher settings as a byte array. + * + * @return The byte array of the settings. + */ + @Override + public byte[] getSettings() { + synchronized (slock) { + processPasswordCache(); + byte[] toret = new byte[1 + ((passwordCache == null) ? 0 : passwordCache.length + 4) + ((salt == null) ? 0 : salt.length + 1) + ((iVector == null) ? 0 : iVector.length + 1)]; + toret[0] = (byte) (((passwordCache == null) ? 0 : 1) + ((salt == null) ? 0 : 2) + ((iVector == null) ? 0 : 4)); + + int index = 1; + if (passwordCache != null) { + int length = passwordCache.length; + + toret[index++] = (byte) (length / 16777216); + length %= 16777216; + toret[index++] = (byte) (length / 65536); + length %= 65536; + toret[index++] = (byte) (length / 256); + length %= 256; + toret[index++] = (byte) (length); + + System.arraycopy(passwordCache, 0, toret, index, passwordCache.length); index += passwordCache.length; + } + + if (salt != null) { + toret[index++] = (byte) salt.length; + System.arraycopy(salt, 0, toret, index, salt.length); index += salt.length; + } + + if (iVector != null) { + toret[index++] = (byte) iVector.length; + System.arraycopy(iVector, 0, toret, index, iVector.length); + } + + return toret; + } + } + + /** + * Gets the length of the settings byte array. + * + * @return The length of the settings byte array. + */ + @Override + public int getSettingsLength() { + synchronized (slock) { + processPasswordCache(); + return 1 + ((passwordCache == null) ? 0 : passwordCache.length + 4) + ((salt == null) ? 0 : salt.length + 1) + ((iVector == null) ? 0 : iVector.length + 1); + } + } + + /** + * Gets the cipher settings as a byte array without secrets. + * + * @return The byte array of the settings without secrets. + */ + @Override + public byte[] getSettingsNoSecrets() { + synchronized (slock) { + byte[] toret = new byte[1 + ((salt == null) ? 0 : salt.length + 1) + ((iVector == null) ? 0 : iVector.length + 1)]; + toret[0] = (byte) (((salt == null) ? 0 : 2) + ((iVector == null) ? 0 : 4)); + + int index = 1; + if (salt != null) { + toret[index++] = (byte) salt.length; + System.arraycopy(salt, 0, toret, index, salt.length); index += salt.length; + } + + if (iVector != null) { + toret[index++] = (byte) iVector.length; + System.arraycopy(iVector, 0, toret, index, iVector.length); + } + + return toret; + } + } + + /** + * Gets the length of the settings byte array without secrets. + * + * @return The length of the settings byte array without secrets. + */ + @Override + public int getSettingsNoSecretsLength() { + synchronized (slock) { + return 1 + ((salt == null) ? 0 : salt.length + 1) + ((iVector == null) ? 0 : iVector.length + 1); + } + } + + /** + * Sets the cipher settings using a byte array. + * + * @param settingsIn The byte array to load the settings from. + * @throws NullPointerException settingsIn is null. + * @throws CipherException An Exception has occurred. + */ + @Override + public void setSettings(byte[] settingsIn) throws CipherException { + if (settingsIn == null) throw new NullPointerException("settingsIn is null"); + if (settingsIn.length < 1) throw new CipherException("no data"); + synchronized (slock) { + int index = 1; + if (((settingsIn[0] & 4) == 4)) { + int pwdLength = (settingsIn[index++] & 0xff) * 16777216; + pwdLength += (settingsIn[index++] & 0xff) * 65536; + pwdLength += (settingsIn[index++] & 0xff) * 256; + pwdLength += (settingsIn[index++] & 0xff); + if (pwdLength < 1) throw new CipherException("password length less than 1"); + + passwordCache = new byte[pwdLength]; + System.arraycopy(settingsIn, index, passwordCache, 0, pwdLength); index += pwdLength; + + password = new String(passwordCache, StandardCharsets.UTF_8); + } + + if (((settingsIn[0] & 8) == 8)) { + int length = settingsIn[index++] & 0xff; + if (length < 1) throw new CipherException("salt length less than 1"); + salt = new byte[length]; + System.arraycopy(settingsIn, index, salt, 0, length); index += length; + } + + if (((settingsIn[0] & 16) == 16)) { + int length = settingsIn[index++] & 0xff; + if (length < 1) throw new CipherException("initializationVector length less than 1"); + iVector = new byte[length]; + System.arraycopy(settingsIn, index, iVector, 0, length); + } + } + } + + /** + * Gets the password. + * + * @return The password. + */ + public String getPassword() { + return password; + } + + /** + * Sets the password. + * + * @param password The new password. + * @throws NullPointerException password is null. + */ + public void setPassword(String password) { + if (password == null) throw new NullPointerException("password is null"); + synchronized (slock) { + haveAttributesChanged = true; + this.password = password; + passwordCache = null; + } + } + + /** + * Gets the salt in use. + * + * @return The salt. + */ + public byte[] getSalt() { + return salt; + } + + /** + * Sets the salt in use, set to null to generate a random salt. + * + * @param salt The new salt or null. + * @throws IllegalArgumentException salt is larger than 255. + */ + public void setSalt(byte[] salt) { + if (salt != null && salt.length > 255) throw new IllegalArgumentException("salt is larger than 255"); + synchronized (slock) { + haveAttributesChanged = true; + this.salt = salt; + } + } + + /** + * Gets the initialization vector. + * + * @return The initialization vector. + */ + public byte[] getInitializationVector() { + return iVector; + } + + /** + * Sets the initialization vector in use, set to null to generate a random initialization vector. + * + * @param initializationVector The new initialization vector or null. + * @throws IllegalArgumentException initializationVector is larger than 255. + */ + public void setInitializationVector(byte[] initializationVector) { + if (initializationVector != null && initializationVector.length > 255) throw new IllegalArgumentException("initializationVector is larger than 255"); + synchronized (slock) { + haveAttributesChanged = true; + iVector = initializationVector; + } + } + + /** + * Gets whether the salt is output. + * + * @return Is the salt output. + */ + public boolean isOutputtingSalt() { + return outputSalt; + } + + /** + * Sets if the salt is output. + * + * @param outputSalt Should the salt be output. + */ + public void setOutputSalt(boolean outputSalt) { + this.outputSalt = outputSalt; + } + + /** + * Gets whether the InitializationVector is output. + * + * @return Is the InitializationVector output. + */ + public boolean isOutputtingInitializationVector() { + return outputIVector; + } + + /** + * Sets if the InitializationVector is output. + * + * @param outputInitializationVector Should the InitializationVector be output. + */ + public void setOutputInitializationVector(boolean outputInitializationVector) { + outputIVector = outputInitializationVector; + } +} diff --git a/src/com/captainalm/lib/stdcrypt/encryption/CipherException.java b/src/com/captainalm/lib/stdcrypt/encryption/CipherException.java new file mode 100644 index 0000000..83722c0 --- /dev/null +++ b/src/com/captainalm/lib/stdcrypt/encryption/CipherException.java @@ -0,0 +1,60 @@ +package com.captainalm.lib.stdcrypt.encryption; + +import java.security.PrivilegedActionException; + +/** + * This class provides the cipher exception wrapper class. + * See {@link CipherException#getCause()} to find out the underlying exception. + * + * @author Captain ALM + */ +public class CipherException extends Exception { + + /** + * Constructs a new exception with the specified detail message. The + * cause is not initialized, and may subsequently be initialized by + * a call to {@link #initCause}. + * + * @param message the detail message. The detail message is saved for + * later retrieval by the {@link #getMessage()} method. + */ + public CipherException(String message) { + super(message); + } + + /** + * Constructs a new exception with the specified detail message and + * cause.

Note that the detail message associated with + * {@code cause} is not automatically incorporated in + * this exception's detail message. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.4 + */ + public CipherException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new exception with the specified cause and a detail + * message of (cause==null ? null : cause.toString()) (which + * typically contains the class and detail message of cause). + * This constructor is useful for exceptions that are little more than + * wrappers for other throwables (for example, {@link + * PrivilegedActionException}). + * + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.4 + */ + public CipherException(Throwable cause) { + super(cause); + } +} diff --git a/src/com/captainalm/lib/stdcrypt/encryption/ICipherFactory.java b/src/com/captainalm/lib/stdcrypt/encryption/ICipherFactory.java new file mode 100644 index 0000000..8cf9885 --- /dev/null +++ b/src/com/captainalm/lib/stdcrypt/encryption/ICipherFactory.java @@ -0,0 +1,71 @@ +package com.captainalm.lib.stdcrypt.encryption; + +import javax.crypto.Cipher; + +/** + * This interface provides the ability to obtain a {@link Cipher} and get and set its settings. + * + * @author Captain ALM + */ +public interface ICipherFactory { + /** + * Gets a new cipher instance. + * + * @param opmode The Cipher Operation Mode ({@link Cipher#ENCRYPT_MODE}, {@link Cipher#DECRYPT_MODE}, {@link Cipher#WRAP_MODE} and {@link Cipher#UNWRAP_MODE}). + * @return The new cipher instance or null. + * @throws CipherException An Exception has occurred. + */ + Cipher getCipher(int opmode) throws CipherException; + + /** + * Gets the name of the cipher factory. + * + * @return The name of the cipher factory. + */ + String getName(); + + /** + * Gets if the cipher settings attributes have been modified. + * Resets the flag once checked. + * + * @return If the attributes have been modified. + */ + boolean cipherAttributesModified(); + + /** + * Gets the cipher settings as a byte array. + * + * @return The byte array of the settings. + */ + byte[] getSettings(); + + /** + * Gets the length of the settings byte array. + * + * @return The length of the settings byte array. + */ + int getSettingsLength(); + + /** + * Gets the cipher settings as a byte array without secrets. + * + * @return The byte array of the settings without secrets. + */ + byte[] getSettingsNoSecrets(); + + /** + * Gets the length of the settings byte array without secrets. + * + * @return The length of the settings byte array without secrets. + */ + int getSettingsNoSecretsLength(); + + /** + * Sets the cipher settings using a byte array. + * + * @param settingsIn The byte array to load the settings from. + * @throws NullPointerException settingsIn is null. + * @throws CipherException An Exception has occurred. + */ + void setSettings(byte[] settingsIn) throws CipherException; +} diff --git a/src/com/captainalm/lib/stdcrypt/encryption/package-info.java b/src/com/captainalm/lib/stdcrypt/encryption/package-info.java new file mode 100644 index 0000000..bf01123 --- /dev/null +++ b/src/com/captainalm/lib/stdcrypt/encryption/package-info.java @@ -0,0 +1,6 @@ +/** + * This package contains the encryption objects. + * + * @author Captain ALM + */ +package com.captainalm.lib.stdcrypt.encryption; \ No newline at end of file diff --git a/src/com/captainalm/lib/stdcrypt/package-info.java b/src/com/captainalm/lib/stdcrypt/package-info.java new file mode 100644 index 0000000..e77f51f --- /dev/null +++ b/src/com/captainalm/lib/stdcrypt/package-info.java @@ -0,0 +1,8 @@ +/** + * This library contains the standard {@link com.captainalm.lib.stdcrypt.digest} and {@link com.captainalm.lib.stdcrypt.encryption} logic. + * + * @since 0.0 + * @author Captain ALM + * @version 0.0 + */ +package com.captainalm.lib.stdcrypt; \ No newline at end of file