為了安全,我們會采取對文件的重要信息進行加密。本文將介紹如何使用對稱加密算法AES對文件進行加解密,包括:“替換local_policy.jar和US_export_policy.jar文件”、“加密文件內容”、“自定義PropertyPlaceholderConfigurer子類解密文件”。
1、替換local_policy.jar和US_export_policy.jar文件。
替換${java_home}/jre/lib/security下的local_policy.jar和US_export_policy.jar文件。
我們加密使用的密鑰長度大於128,而正常Java運行環境限制了密鑰長度不能大於128。所以我們需要下載能支持密鑰大於128的local_policy.jar和US_export_policy.jar文件,替換掉${java_home}/jre/lib/security下的對應的文件。
2、加密文件內容。
如數據庫連接文件,將數據庫用戶名和密文進行加密。將用戶名和密碼使用AES加密后,填寫到文件:
# 數據庫驅動
driverClassName=com.mysql.cj.jdbc.Driver
# 數據庫URL
db.mysql.url=jdbc:mysql://localhost:3306/%s?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL
# 數據庫用戶名
db.mysql.username.encryption=81A3FD464E18C4497A79CE7CC9D5B660
db.nbx.mysql.username.encryption=81A3FD464E18C4497A79CE7CC9D5B660
# 密碼
db.mysql.password.encryption=16CCEF25E22FA42E89821B7B27858DE26DD8BFF1139FF2C70BECCA88E373F809
db.nbx.mysql.password.encryption=16CCEF25E22FA42E89821B7B27858DE26DD8BFF1139FF2C70BECCA88E373F809
key鍵多了個”.encryption”,后面使用PropertyPlaceholderConfigurerUtil對其進行處理。
3、自定義 PropertyPlaceholderConfigurer子類解密文件。
PropertyPlaceholderConfigurer是個bean工廠后置處理器的實現,新建一個類PropertyPlaceholderConfigurerUtil繼承它,可以在容器啟動時,對加密的文件進行解密。
PropertyPlaceholderConfigurerUtil重寫了processProperties方法。processProperties方法找到文件里以“.encryption”結尾的key,將它的value進行解密,並去掉“.encryption”:
public class PropertyPlaceholderConfigurerUtil extends PropertyPlaceholderConfigurer {
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException {
AESUtil aesHelper = new AESUtil();
Enumeration<?> keys = props.propertyNames();
while (keys.hasMoreElements()) {
String key = (String) keys.nextElement();
String value = props.getProperty(key);
if (key.endsWith(".encryption") && null != value) {
props.remove(key);
key = key.substring(0, key.length() - 11);
value = aesHelper.decrypt(value.trim());
props.setProperty(key, value);
}
System.setProperty(key, value);
}
super.processProperties(beanFactoryToProcess, props);
}
}
解密:
/**
* * Input encrypted String represented in HEX * * @return a string decrypted in
* plain text
*/
public String decrypt(String hexCipherText) {
try {
String plaintext = new String(dcipher.doFinal(hexToByte(hexCipherText)), "UTF-8");
return plaintext;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static byte[] hexToByte(String hexString) {
int len = hexString.length();
byte[] ba = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
ba[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16));
}
return ba;
}
生成密鑰:
/**
* * Input a string that will be md5 hashed to create the key. * * @return void,
* cipher initialized
*/
public AESUtil() {
try {
SecretKeySpec skey = new SecretKeySpec("xxxxxxxxxxxxxxxx".getBytes(), "AES");
this.setupCrypto(skey);
} catch (Exception e) {
e.printStackTrace();
}
}
獲取和初始化加密、解密Cipher對象:
private void setupCrypto(SecretKey key) {
// Create an 8-byte initialization vector
byte[] iv = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
try {
ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
dcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// CBC requires an initialization vector
ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
} catch (Exception e) {
e.printStackTrace();
}
}
加密字符串:
/**
* * Input is a string to encrypt. * * @return a Hex string of the byte array
*/
public String encrypt(String plaintext) {
try {
byte[] ciphertext = ecipher.doFinal(plaintext.getBytes("UTF-8"));
return byteToHex(ciphertext);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static String byteToHex(byte[] raw) {
if (raw == null) {
return null;
}
final StringBuilder hex = new StringBuilder(2 * raw.length);
for (final byte b : raw) {
hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
