问题描述
我有一个程序可以从配置文件中读取服务器信息,我想加密该配置中的密码,以便我的程序可以读取和解密.
I have a program that reads server information from a configuration file and would like to encrypt the password in that configuration that can be read by my program and decrypted.
要求:
- 加密明文密码以存储在文件中
- 解密从我的程序文件中读取的加密密码
关于我将如何去做的任何建议?我正在考虑编写自己的算法,但我觉得它非常不安全.
Any reccomendations on how i would go about doing this? I was thinking of writing my own algorithm but i feel it would be terribly insecure.
推荐答案
一个简单的方法是在 Java 中使用基于密码的加密.这允许您使用密码加密和解密文本.
A simple way of doing this is to use Password Based Encryption in Java. This allows you to encrypt and decrypt a text by using a password.
这基本上意味着使用算法 "AES/CBC/PKCS5Padding"
初始化 javax.crypto.Cipher
并从 javax.crypto.SecretKeyFactory 使用
"PBKDF2WithHmacSHA512"
算法.
This basically means initializing a javax.crypto.Cipher
with algorithm "AES/CBC/PKCS5Padding"
and getting a key from javax.crypto.SecretKeyFactory
with the "PBKDF2WithHmacSHA512"
algorithm.
这是一个代码示例(已更新以替换安全性较低的基于 MD5 的变体):
Here is a code example (updated to replace the less secure MD5-based variant):
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class ProtectedConfigFile {
public static void main(String[] args) throws Exception {
String password = System.getProperty("password");
if (password == null) {
throw new IllegalArgumentException("Run with -Dpassword=<password>");
}
// The salt (probably) can be stored along with the encrypted data
byte[] salt = new String("12345678").getBytes();
// Decreasing this speeds down startup time and can be useful during testing, but it also makes it easier for brute force attackers
int iterationCount = 40000;
// Other values give me java.security.InvalidKeyException: Illegal key size or default parameters
int keyLength = 128;
SecretKeySpec key = createSecretKey(password.toCharArray(),
salt, iterationCount, keyLength);
String originalPassword = "secret";
System.out.println("Original password: " + originalPassword);
String encryptedPassword = encrypt(originalPassword, key);
System.out.println("Encrypted password: " + encryptedPassword);
String decryptedPassword = decrypt(encryptedPassword, key);
System.out.println("Decrypted password: " + decryptedPassword);
}
private static SecretKeySpec createSecretKey(char[] password, byte[] salt, int iterationCount, int keyLength) throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterationCount, keyLength);
SecretKey keyTmp = keyFactory.generateSecret(keySpec);
return new SecretKeySpec(keyTmp.getEncoded(), "AES");
}
private static String encrypt(String property, SecretKeySpec key) throws GeneralSecurityException, UnsupportedEncodingException {
Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
pbeCipher.init(Cipher.ENCRYPT_MODE, key);
AlgorithmParameters parameters = pbeCipher.getParameters();
IvParameterSpec ivParameterSpec = parameters.getParameterSpec(IvParameterSpec.class);
byte[] cryptoText = pbeCipher.doFinal(property.getBytes("UTF-8"));
byte[] iv = ivParameterSpec.getIV();
return base64Encode(iv) + ":" + base64Encode(cryptoText);
}
private static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
private static String decrypt(String string, SecretKeySpec key) throws GeneralSecurityException, IOException {
String iv = string.split(":")[0];
String property = string.split(":")[1];
Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(base64Decode(iv)));
return new String(pbeCipher.doFinal(base64Decode(property)), "UTF-8");
}
private static byte[] base64Decode(String property) throws IOException {
return Base64.getDecoder().decode(property);
}
}
仍然存在一个问题:您应该将用于加密密码的密码存储在哪里?您可以将其存储在源文件中并对其进行混淆,但再次找到它并不难.或者,您可以在启动 Java 进程时将其作为系统属性提供 (-DpropertyProtectionPassword=...
).
One problem remains: Where should you store the password that you use to encrypt the passwords? You can store it in the source file and obfuscate it, but it's not too hard to find it again. Alternatively, you can give it as a system property when you start the Java process (-DpropertyProtectionPassword=...
).
如果您使用同样受密码保护的 KeyStore,同样的问题仍然存在.基本上,您需要在某处拥有一个主密码,而且很难保护.
The same issue remains if you use the KeyStore, which also is protected by a password. Basically, you will need to have one master password somewhere, and it's pretty hard to protect.
这篇关于在配置文件中加密密码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!