在 Java 中加密配置文件中的密码
加密是使用加密算法结合称为加密密钥
的参数将纯文本信息转换为不可读形式的过程。不可读的格式通常称为密文
格式。只有拥有解密密钥
的人才能解密数据并恢复原始明文。
我们可以将对配置文件中的密码进行加密的问题分解为以下两个子任务。
首先让我们在 src/conf/
路径下创建一个名为 config.properties
的配置文件。
password=TestPassword123
现在,要读取配置文件,请实例化 Properties
类。我们可以使用其构造函数创建 FileInputStream
类的实例。它以配置文件的路径作为输入。现在,使用属性类的实例来加载属性。使用 load
方法在类中加载属性文件,这将 InputStreamReader
实例作为参数。如果此输入流包含格式错误的 Unicode 转义序列,则抛出 IllegalArgumentException
;如果从输入流中读取时发生错误,则抛出 IOException
。
成功加载属性后,使用 getProperty()
方法在属性列表中使用指定的键搜索属性。如果找不到属性,该方法将返回 null
。如果发现文件中的密码为空,则进行外部检查以处理这种情况,并抛出 IllegalArgumentException
。
salt
是使用任意随机字符串创建的,以添加到密码字符串中。
createSecretKey
是用户定义的方法,该方法返回 SecretKeySpec
密钥,该密钥的使用是对密码进行加密和解密。encrypt
和 decrypt
方法是 Encryption
类中已使用的,定义的静态
方法。
下面是演示相同的示例代码。
package fileDataEncryption;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileInputStream;
import java.util.Properties;
import static fileDataEncryption.Encryption.*;
public class ConfigFileEncryption {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
FileInputStream inputStream = new FileInputStream("src/conf/config.properties");
properties.load(inputStream);
String password = properties.getProperty("password");
if (password == null) {
throw new IllegalArgumentException("No such parameter present in config file");
}
byte[] salt = new String("12345678").getBytes();
int iterationCount = 40000;
int keyLength = 128;
SecretKeySpec key = createSecretKey(password.toCharArray(), salt, iterationCount, keyLength);
String originalPassword = password;
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);
}
}
Encryption
类中用户定义的方法的详细说明如下。
-
createSecretKey
是一个函数,它接受诸如password
、salt
、iterationCount
和keyLength
之类的参数。password
是配置文件中的实际密码。在密码术中,salt
是随机数据,我们将其用作散列数据,密码或密码短语的附加输入。salt
的使用是为了保护存储密码。我们将iterationCount
变量用作算法应进行的迭代次数。减小变量的值可以缩短启动时间,因此在测试过程中很有用,但对于暴力攻击者来说也更容易。keyLength
变量是我们最终需要派生的密钥的长度。引发从使用它的方法中引发的异常。 -
getInstance
方法从最喜欢的提供者开始遍历已注册安全提供者的列表。它采用请求的密钥算法的标准名称,并返回新的SecretKeyFactory
对象。如果指定算法为 null,则抛出NullPointerException
,如果没有提供者支持指定算法的SecretKeyFactorySpi
实现,则抛出NoSuchAlgorithmException
。 -
PBEKeySpec
是一个类构造函数,它使用密码,盐,迭代计数和要衍生的密钥长度来生成可变密钥大小的 PBE 密码的PBEKey
。如果salt
为null
,则抛出NullPointerException
,如果 salt 为空,则抛出IllegalArgumentException
。 -
generateSecret
根据提供的密钥规范或密钥材料生成一个SecretKey
对象。它采用了密钥的规范。如果给定的规范不适合此密钥工厂产生分类的密钥值,则抛出InvalidKeySpecException
。
Encryption
类中的 encrypt
方法的详细信息。
-
encrypt
方法具有两个参数,即要加密的数据和密钥。此方法将引发从其子方法引发的异常。 -
getInstance
方法从最喜欢的提供者开始遍历已注册安全提供者的列表。它采用转换的名称,即 AES / CBC / PKCS5Padding。如果更改为 null,为空,且格式无效,则抛出NoSuchAlgorithmException
,如果更改包含不可用的填充方案,则抛出NoSuchPaddingException
。 -
init
方法为以下四个操作之一初始化Cipher
:加密,解密,密钥包装或密钥解包,具体取决于操作模式值。在我们的案例中是ENCRYPT_MODE
。如果操作模式无效,则该方法将引发UnsupportedOperationException
,如果给定密钥不适当,则将引发InvalidKeyException
。 -
getParameters
返回与此密码一起使用的参数。 -
getParameterSpec
返回参数对象的规范。paramSpec
参数标识必须在其中返回参数的规范类。例如,可能是DSAParameterSpec.class
,以指示参数必须在DSAParameterSpec
类的实例中返回。 -
doFinal
方法在单部分工作中加密或解密数据,或完成多部分操作。数据是加密还是解密,取决于我们如何初始化密码。 -
base64Encode
是一个私有方法,它使用Base64
编码方案将指定的字节数组编码为字符串。decrypt
方法中使用的功能与上述方法类似。唯一的区别是,它们根据功能DECRYPT_MODE
中指定的mode
的运行方式不同。
package fileDataEncryption;
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;
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;
public class Encryption {
public 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");
}
public static String encrypt(String dataToEncrypt, 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(dataToEncrypt.getBytes("UTF-8"));
byte[] iv = ivParameterSpec.getIV();
return base64Encode(iv) + ":" + base64Encode(cryptoText);
}
private static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
public 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);
}
}
以下是编写的用于加密和解密配置文件中密码的代码的输出。
Original password: TestPassword123
Encrypted password: Hy7fbIwpyKgp0oileu+oLg==:WNRknMJz/8u8GmWlCZFPFA==
Decrypted password: TestPassword123
相关文章
用 Java 创建一个猜数游戏
发布时间:2023/10/10 浏览次数:84 分类:Java
-
任务是为猜谜游戏编写 Java 程序。猜谜游戏是一个约束满足问题。你必须在给定次数的试验中猜出正确的数字;否则,你不会赢。
从 Mac 中卸载 JDK 8
发布时间:2023/10/10 浏览次数:79 分类:Java
-
本文介绍如何从 MacOS 卸载 JDK 8。在过去的几十年里,Java 一直是主要的编程语言之一。它是计算机科学不可或缺的一部分。
Java 中的有限状态机
发布时间:2023/10/10 浏览次数:197 分类:Java
-
本教程演示如何在 Java 中实现有限状态机。有限状态机用于识别模式。本教程演示如何在 Java 中实现有限状态机。
Java 中的位掩码操作
发布时间:2023/10/10 浏览次数:101 分类:Java
-
在 Java 中,位掩码允许我们在一个数值变量中存储多个值。我们将值的每一位都视为一个单独的值,而不是一个整体的单个变量。
Java 中的弱引用类
发布时间:2023/10/10 浏览次数:129 分类:Java
-
本教程演示了 Java 中的弱引用类。弱引用是一种强度不足以使对象保留在内存中的引用。本教程演示了 Java 中弱引用的使用。
用 Java 连接 MySQL 数据库
发布时间:2023/10/10 浏览次数:134 分类:Java
-
这篇文章将演示如何使用 Java 连接 MySQL 数据库。本教程介绍了如何在 Java 中连接 MySQL 数据库。我们还列出了一些示例代码,以便你可以进一步了解该主题。
在 Java 中调用另一个方法中的变量
发布时间:2023/10/10 浏览次数:139 分类:Java
-
本教程解释了如何在 Java 中调用另一个方法中的变量。在本文中,我们将学习如何在 Java 中调用另一个方法中的变量。这取决于变量的类型和它在类内的作用域。
在 Java 中导入自定义类
发布时间:2023/10/10 浏览次数:73 分类:Java
-
这篇文章将要导入 Java 中的自定义类。本文介绍了如何在 Java 中导入自定义类。如果该类存在于同一个包中,则通过创建其对象来使用该类,如果该类存在于另一个包中