在 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/12/17 浏览次数:217 分类:Java
-
本篇文章主要介绍如何在 Java 中制造程序延迟。本教程介绍了如何在 Java 中制造程序延时,并列举了一些示例代码来了解它。
如何在 Java 中把 Hashmap 转换为 JSON 对象
发布时间:2023/12/17 浏览次数:187 分类:Java
-
它描述了允许我们将哈希图转换为简单的 JSON 对象的方法。本文介绍了在 Java 中把 Hashmap 转换为 JSON 对象的方法。我们将看到关于创建一个 hashmap,然后将其转换为 JSON 对象的详细例子。
如何在 Java 中按值排序 Map
发布时间:2023/12/17 浏览次数:171 分类:Java
-
本文介绍了如何在 Java 中按值对 Map 进行排序。本教程介绍了如何在 Java 中按值对 Map
进行排序,并列出了一些示例代码来理解它。
如何在 Java 中打印 HashMap
发布时间:2023/12/17 浏览次数:192 分类:Java
-
本帖介绍了如何在 Java 中打印 HashMap。本教程介绍了如何在 Java 中打印 HashMap 元素,还列举了一些示例代码来理解这个主题。
在 Java 中更新 Hashmap 的值
发布时间:2023/12/17 浏览次数:146 分类:Java
-
本文介绍了如何在 Java 中更新 HashMap 中的一个值。本文介绍了如何在 Java 中使用 HashMap 类中包含的两个方法-put() 和 replace() 更新 HashMap 中的值。
Java 中的 hashmap 和 map 之间的区别
发布时间:2023/12/17 浏览次数:79 分类:Java
-
本文介绍了 Java 中的 hashmap 和 map 接口之间的区别。本教程介绍了 Java 中 Map 和 HashMap 之间的主要区别。在 Java 中,Map 是用于以键值对存储数据的接口,
在 Java 中获取用户主目录
发布时间:2023/12/17 浏览次数:218 分类:Java
-
这篇文章向你展示了如何在 Java 中获取用户主目录。本教程介绍了如何在 Java 中获取用户主目录,并列出了一些示例代码以指导你完成该主题。
Java 中 size 和 length 的区别
发布时间:2023/12/17 浏览次数:179 分类:Java
-
这篇文章教你如何知道 Java 中大小和长度之间的区别。本教程介绍了 Java 中大小和长度之间的区别。我们还列出了一些示例代码以帮助你理解该主题。
Java 中的互斥锁
发布时间:2023/12/17 浏览次数:111 分类:Java
-
了解有关 Java 中互斥锁的一切,在计算机科学领域,互斥或互斥被称为并发控制的属性。每台计算机都使用称为线程的最小程序指令序列。有一次,计算机在一个线程上工作。为了更好地理解,

