Created
January 18, 2017 12:16
-
-
Save ansig/28fabac59480ea6bd4715c7ea5d776a8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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