Skip to content

Instantly share code, notes, and snippets.

@ansig
Created January 18, 2017 12:16
Show Gist options
  • Save ansig/28fabac59480ea6bd4715c7ea5d776a8 to your computer and use it in GitHub Desktop.
Save ansig/28fabac59480ea6bd4715c7ea5d776a8 to your computer and use it in GitHub Desktop.
import com.sun.org.apache.xml.internal.security.utils.Base64;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
public class EncryptionUtils {
private static final String HASHING_ALGORITHM = "PBKDF2WithHmacSHA1";
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
private static final String SECURE_RANDOM_ALGORITHM = "SHA1PRNG";
private static final String KEY_ALGORITHM = "AES";
private static final String STRING_ENCODING = "UTF-8";
private static final int SALT_BYTES = 16;
private static final int HASH_KEY_BITS = 128;
private static final int HASH_ITERATIONS = 65536;
public static void main(String[] args) throws Exception {
String clearText = "Detta är strängen";
String key = "This is the passphrase";
System.out.printf("The plaintext: %s%n", clearText);
System.out.printf("The key: %s%n", key);
EncryptedPassword encryptedPassword = encrypt(clearText, key);
System.out.printf("The ciphertext: %s%n", Base64.encode(encryptedPassword.getEncryptedString()));
// Decrypt the text
String decrypted = decrypt(encryptedPassword, key);
System.out.printf("The cleartext: %s%n", decrypted);
}
/**
* Encrypt the string using the specified key and a randomly generated salt.
*
* @param plaintext the plain text string to encrypt
* @param key the key string to use when encrypting the string
* @return the encrypted bytes together with the salt and the iv
*/
public static EncryptedPassword encrypt(String plaintext, String key) {
byte[] salt = generateSalt();
byte[] keyHash = hash(key, salt);
Cipher cipher;
try {
cipher = Cipher.getInstance(CIPHER_ALGORITHM);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new UnsupportedOperationException("Could not get cipher instance", e);
}
try {
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyHash, KEY_ALGORITHM));
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Could not initialize cipher", e);
}
// the iv needs to be saved together with the encrypted bytes
// in order to be able to decrypt the password at a later stage
AlgorithmParameters params = cipher.getParameters();
byte[] iv;
try {
iv = params.getParameterSpec(IvParameterSpec.class).getIV();
} catch (InvalidParameterSpecException e) {
throw new UnsupportedOperationException("Could not get iv bytes", e);
}
byte[] encryptedText;
try {
encryptedText = cipher.doFinal(plaintext.getBytes(STRING_ENCODING));
} catch (IllegalBlockSizeException | BadPaddingException | UnsupportedEncodingException e) {
throw new UnsupportedOperationException("Could not do final encryption", e);
}
return new EncryptedPassword(encryptedText, iv, salt);
}
/**
* Decrypt the string using the specified key.
*
* @param password the encrypted password to decrypt
* @param key the key string to use when decrypting the string
* @return the cleartext string
*/
public static String decrypt(EncryptedPassword password, String key) {
byte[] keyHash = hash(key, password.getSalt());
Cipher cipher;
try {
cipher = Cipher.getInstance(CIPHER_ALGORITHM);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new UnsupportedOperationException("Could not get cipher instance", e);
}
try {
cipher.init(
Cipher.DECRYPT_MODE,
new SecretKeySpec(keyHash, KEY_ALGORITHM),
new IvParameterSpec(password.getIv()));
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new UnsupportedOperationException("Could not initialize cipher", e);
}
byte[] encryptedText;
try {
encryptedText = cipher.doFinal(password.getEncryptedString());
} catch (IllegalBlockSizeException | BadPaddingException e) {
throw new UnsupportedOperationException("Could not do final encryption", e);
}
return new String(encryptedText);
}
/**
* Hash the specified string.
*
* @param string the string to hash
* @param salt a salt to use when hashing the string
* @return the hash of the string
*/
public static byte[] hash(String string, byte[] salt) {
PBEKeySpec spec = new PBEKeySpec(string.toCharArray(), salt, HASH_ITERATIONS, HASH_KEY_BITS);
SecretKeyFactory factory = null;
try {
factory = SecretKeyFactory.getInstance(HASHING_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("Could not get SecretKeyFactory instance", e);
}
byte[] hash;
try {
hash = factory.generateSecret(spec).getEncoded();
} catch (InvalidKeySpecException e) {
throw new UnsupportedOperationException("Could not generate hash", e);
}
return hash;
}
/**
* Generate a salt that can be used for encryption.
*
* @return a randomly generated salt
*/
public static byte[] generateSalt() {
SecureRandom random = null;
try {
random = SecureRandom.getInstance(SECURE_RANDOM_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("Could not get SecureRandom instance", e);
}
byte[] salt = new byte[SALT_BYTES];
random.nextBytes(salt);
return salt;
}
/**
* Represents an encrypted string.
*/
public static class EncryptedPassword {
private byte[] encryptedString;
private byte[] iv;
private byte[] salt;
public EncryptedPassword(byte[] encryptedString, byte[] iv, byte[] salt) {
this.encryptedString = encryptedString;
this.iv = iv;
this.salt = salt;
}
public byte[] getEncryptedString() {
return encryptedString;
}
public byte[] getIv() {
return iv;
}
public byte[] getSalt() {
return salt;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment