Files
crypto/src/main/java/net/locusworks/crypto/AES.java
2019-09-30 15:40:29 -05:00

165 lines
5.3 KiB
Java

package net.locusworks.crypto;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.lang3.StringUtils;
import net.locusworks.crypto.utils.RandomString;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
/**
* AES encryption/decryption class
* This class will encrypt/decrypt data. The encryption key is never known.
* Instead it is is generated by the provided seed. As long as the seed stays the same
* the key will remain the same and the encryption/decryption will work. This
* provides and added security.
* @author Isaac Parenteau
* @version 1.0.0
* @date 02/15/2018
*
*/
public class AES {
private static final String ENCRYPTION_TYPE = "AES";
private static final String ENCRYPTION_ALGORITH = "AES/CBC/PKCS5Padding";
private static final String PROVIDER = "SunJCE";
private static final String ALGORITHM = "SHA1PRNG";
private Cipher cipher;
private SecretKeySpec secretKeySpec;
private IvParameterSpec ivParamSpec;
private String seed;
private void initSecureKey(String seed) {
try {
SecureRandom sr = getSecureRandom(seed);
KeyGenerator generator = KeyGenerator.getInstance(ENCRYPTION_TYPE);
generator.init(128, sr);
init(generator.generateKey().getEncoded(), sr);
} catch (Exception ex) {
System.err.println(ex);
throw new IllegalArgumentException("Unable to initalize encryption:", ex);
}
}
/**
* Initializes the secure random object to be the same across all platforms
* with regard to provider and algorithm used
* @param seed Seed to initialize SecureRandom with
* @return SecureRandom object
* @throws NoSuchAlgorithmException thrown when algorithm can't be used
* @throws NoSuchProviderException thrown when the provider cant be found
*/
private static SecureRandom getSecureRandom(String seed) throws NoSuchAlgorithmException {
SecureRandom sr = SecureRandom.getInstance(ALGORITHM);
sr.setSeed(seed.getBytes(StandardCharsets.UTF_8));
return sr;
}
/**
* Initialize the aes engine
* @param key secret key to use
* @param sr
*/
private void init(final byte[] key, SecureRandom sr) {
try {
this.cipher = Cipher.getInstance(ENCRYPTION_ALGORITH, PROVIDER);
this.secretKeySpec = new SecretKeySpec(key, ENCRYPTION_TYPE);
this.ivParamSpec = new IvParameterSpec(RandomString.getBytes(16, sr));
} catch (Exception ex) {
System.err.println(ex);
throw new IllegalArgumentException("Unable to initalize encryption:", ex);
}
}
/***
* Encrypt a text string
* @param plainText String to encrypt
* @return encrypted string
*/
public String encrypt(String plainText) {
if (StringUtils.isBlank(plainText)) {
plainText = "";
}
try {
cipher.init(Cipher.ENCRYPT_MODE, this.secretKeySpec, this.ivParamSpec);
byte[] cypherText = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
return new String(Base64.getEncoder().encode(cypherText), StandardCharsets.UTF_8);
} catch (Exception ex) {
throw new IllegalArgumentException(ex.getMessage(), ex);
}
}
/***
* Decrypt an encrypted string
* @param cipherString encrypted string to decrypt
* @return unecrypted string
*/
public String decrypt(String cipherString) {
if (StringUtils.isBlank(cipherString)) {
return "";
}
byte[] cipherText = Base64.getDecoder().decode(cipherString.getBytes(StandardCharsets.UTF_8));
try {
cipher.init(Cipher.DECRYPT_MODE, this.secretKeySpec, this.ivParamSpec);
return new String(cipher.doFinal(cipherText), StandardCharsets.UTF_8);
} catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
}
public AES setSeed(String seed) {
if (this.seed == null || !this.seed.equals(seed)) {
initSecureKey(seed);
}
this.seed = seed;
return this;
}
public final String getSeed() {
return this.seed;
}
public static AES createInstance() {
return createInstance(RandomString.getString(16));
}
public static AES createInstance(byte[] byteSeed) {
String seed = new String(byteSeed, StandardCharsets.UTF_8);
return createInstance(seed);
}
public static AES createInstance(String seed) {
AES aes = new AES();
aes.setSeed(seed);
return aes;
}
public static void main(String[] args) throws NoSuchAlgorithmException {
if (args == null || !(args.length > 0)) {
throw new IllegalArgumentException("No args provided. Need password as argument");
}
if (args.length % 2 == 0) {
System.out.println(AES.createInstance(String.valueOf(args[1])).decrypt(String.valueOf(args[0])));
} else {
System.out.println(AES.createInstance().encrypt(String.valueOf(args[0])));
}
}
}