· 8 years ago · Dec 17, 2017, 03:32 PM
1package util.crypto;
2
3import javax.crypto.Cipher;
4import javax.crypto.SecretKey;
5import javax.crypto.SecretKeyFactory;
6import javax.crypto.spec.IvParameterSpec;
7import javax.crypto.spec.PBEKeySpec;
8import javax.crypto.spec.SecretKeySpec;
9import java.io.*;
10import java.nio.file.NoSuchFileException;
11import java.security.AlgorithmParameters;
12import java.security.GeneralSecurityException;
13import java.security.NoSuchAlgorithmException;
14import java.security.spec.InvalidKeySpecException;
15import java.util.Base64;
16import java.util.Properties;
17
18/**
19 * This utility class is used to encrypt and decrypt values. This class requires a keyring file with the correct key
20 * for the application that is running
21 *
22 * User: rhmiller
23 * Date: 5/31/17
24 */
25public class EncryptionUtil {
26 private String appName;
27 private String salt;
28 private int iterationCount;
29 private int keyLength;
30
31 /**
32 * Constructor that loads values from the application.conf file
33 *
34 * @throws IOException
35 */
36 public EncryptionUtil() throws IOException {
37 Properties config = new Properties();
38 config.load(new FileInputStream(new File(System.getProperty("user.dir")).getParentFile().getParentFile().getParentFile().getPath() + "/conf/application.conf"));
39
40 appName = config.getProperty("application.name", "Uploader");
41 salt = config.getProperty("application.secret", "123456789");
42 iterationCount = Integer.parseInt(config.getProperty("encryption.iterationCount", "10000"));
43 keyLength = Integer.parseInt(config.getProperty("encryption.keyLength", "128"));
44 }
45
46 /**
47 * Method that is used to decrypt cypher text that has been encrypted by the encrypt method in this class
48 *
49 * @param cypherText the text that will be decrypted
50 * @return the decrypted message
51 * @throws GeneralSecurityException if there is an error decrypting the cypher text
52 * @throws IOException if the keyring file can't be loaded
53 */
54 public String decrypt(String cypherText) throws GeneralSecurityException, IOException {
55 String iv = cypherText.split(":")[0];
56 String property = cypherText.split(":")[1];
57 Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
58 pbeCipher.init(Cipher.DECRYPT_MODE, createSecretKey(), new IvParameterSpec(base64Decode(iv)));
59
60 return new String(pbeCipher.doFinal(base64Decode(property)), "UTF-8");
61 }
62
63 /**
64 * Method that is used to encrypt a property and can be decrypted by the decrypt method in this class
65 *
66 * @param property the property that will be ecnrypted
67 * @return the cypher text of the property provided
68 * @throws GeneralSecurityException if there is an error encrypting the
69 * @throws UnsupportedEncodingException if the encryption algorithm is not supported
70 * @throws NoSuchFileException if the keyring cannot be loaded
71 */
72 public String encrypt(String property) throws GeneralSecurityException, UnsupportedEncodingException, NoSuchFileException {
73 Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
74 pbeCipher.init(Cipher.ENCRYPT_MODE, createSecretKey());
75 AlgorithmParameters parameters = pbeCipher.getParameters();
76 IvParameterSpec ivParameterSpec = parameters.getParameterSpec(IvParameterSpec.class);
77 byte[] cryptoText = pbeCipher.doFinal(property.getBytes("UTF-8"));
78 byte[] iv = ivParameterSpec.getIV();
79 return base64Encode(iv) + ":" + base64Encode(cryptoText);
80 }
81
82 /**
83 * Helper method that builds the secret key spec that is used as the initialization vector for encrypting the property
84 *
85 * @return the secret key based on the salt and secret from the keyring
86 * @throws NoSuchAlgorithmException if the encryption algorithm isn't supported
87 * @throws InvalidKeySpecException if there is an issue building the key spec
88 * @throws NoSuchFileException if the keyring cannot be loaded
89 */
90 private SecretKeySpec createSecretKey() throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchFileException {
91 char[] secret = loadKeyring().toCharArray();
92
93 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
94 PBEKeySpec keySpec = new PBEKeySpec(secret, salt.getBytes(), iterationCount, keyLength);
95 SecretKey keyTmp = keyFactory.generateSecret(keySpec);
96 return new SecretKeySpec(keyTmp.getEncoded(), "AES");
97 }
98
99 /**
100 * Helper method that loads the keyring file and gets the key that applies to the application
101 *
102 * @return the key for the current application from the keyring file
103 * @throws NoSuchFileException if the keyring file cannot be loaded
104 */
105 private String loadKeyring() throws NoSuchFileException {
106 Properties prop = new Properties();
107 String[] possibleFiles = {
108 System.getProperty("user.home") + "/.keyring",
109 System.getProperty("user.home") + "/keyring.txt",
110 "C:/Projects/.keyring",
111 "C:/Projects/keyring.txt",
112 System.getProperty("user.home") + "/Projects/.keyring",
113 System.getProperty("user.home") + "/Projects/keyring.txt",
114 "/Projects/.keyring",
115 "/Projects/keyring.txt",
116 "/local/web/.keyring" };
117
118 for (String possibleFile : possibleFiles) {
119 File file = new File(possibleFile);
120 if (file.isFile()) {
121 try {
122 prop.load(new FileInputStream(file));
123
124 return prop.getProperty(appName);
125 } catch (Exception e) {
126 throw new NoSuchFileException("Could not find a keyring file. " + e.getMessage());
127 }
128 }
129 }
130
131 throw new NoSuchFileException("Could not find a keyring file. ");
132 }
133
134 private String base64Encode(byte[] bytes) {
135 return Base64.getEncoder().encodeToString(bytes);
136 }
137
138 private byte[] base64Decode(String property) throws IOException {
139 return Base64.getDecoder().decode(property);
140 }
141}