迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 > Java >

在 Java 中加密配置文件中的密码

作者:迹忆客 最近更新:2023/10/10 浏览次数:

加密是使用加密算法结合称为加密密钥的参数将纯文本信息转换为不可读形式的过程。不可读的格式通常称为密文格式。只有拥有解密密钥的人才能解密数据并恢复原始明文。

我们可以将对配置文件中的密码进行加密的问题分解为以下两个子任务。

首先让我们在 src/conf/路径下创建一个名为 config.properties 的配置文件。

password=TestPassword123

现在,要读取配置文件,请实例化 Properties 类。我们可以使用其构造函数创建 FileInputStream 类的实例。它以配置文件的路径作为输入。现在,使用属性类的实例来加载属性。使用 load 方法在类中加载属性文件,这将 InputStreamReader 实例作为参数。如果此输入流包含格式错误的 Unicode 转义序列,则抛出 IllegalArgumentException;如果从输入流中读取时发生错误,则抛出 IOException

成功加载属性后,使用 getProperty() 方法在属性列表中使用指定的键搜索属性。如果找不到属性,该方法将返回 null。如果发现文件中的密码为空,则进行外部检查以处理这种情况,并抛出 IllegalArgumentException

salt 是使用任意随机字符串创建的,以添加到密码字符串中。

createSecretKey 是用户定义的方法,该方法返回 SecretKeySpec 密钥,该密钥的使用是对密码进行加密和解密。encryptdecrypt 方法是 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 类中用户定义的方法的详细说明如下。

  1. createSecretKey 是一个函数,它接受诸如 passwordsaltiterationCountkeyLength 之类的参数。password 是配置文件中的实际密码。在密码术中,salt 是随机数据,我们将其用作散列数据,密码或密码短语的附加输入。salt 的使用是为了保护存储密码。我们将 iterationCount 变量用作算法应进行的迭代次数。减小变量的值可以缩短启动时间,因此在测试过程中很有用,但对于暴力攻击者来说也更容易。keyLength 变量是我们最终需要派生的密钥的长度。引发从使用它的方法中引发的异常。
  2. getInstance 方法从最喜欢的提供者开始遍历已注册安全提供者的列表。它采用请求的密钥算法的标准名称,并返回新的 SecretKeyFactory 对象。如果指定算法为 null,则抛出 NullPointerException,如果没有提供者支持指定算法的 SecretKeyFactorySpi 实现,则抛出 NoSuchAlgorithmException
  3. PBEKeySpec 是一个类构造函数,它使用密码,盐,迭代计数和要衍生的密钥长度来生成可变密钥大小的 PBE 密码的 PBEKey。如果 saltnull,则抛出 NullPointerException,如果 salt 为空,则抛出 IllegalArgumentException
  4. generateSecret 根据提供的密钥规范或密钥材料生成一个 SecretKey 对象。它采用了密钥的规范。如果给定的规范不适合此密钥工厂产生分类的密钥值,则抛出 InvalidKeySpecException

Encryption 类中的 encrypt 方法的详细信息。

  1. encrypt 方法具有两个参数,即要加密的数据和密钥。此方法将引发从其子方法引发的异常。
  2. getInstance 方法从最喜欢的提供者开始遍历已注册安全提供者的列表。它采用转换的名称,即 AES / CBC / PKCS5Padding。如果更改为 null,为空,且格式无效,则抛出 NoSuchAlgorithmException,如果更改包含不可用的填充方案,则抛出 NoSuchPaddingException
  3. init 方法为以下四个操作之一初始化 Cipher:加密,解密,密钥包装或密钥解包,具体取决于操作模式值。在我们的案例中是 ENCRYPT_MODE。如果操作模式无效,则该方法将引发 UnsupportedOperationException,如果给定密钥不适当,则将引发 InvalidKeyException
  4. getParameters 返回与此密码一起使用的参数。
  5. getParameterSpec 返回参数对象的规范。paramSpec 参数标识必须在其中返回参数的规范类。例如,可能是 DSAParameterSpec.class,以指示参数必须在 DSAParameterSpec 类的实例中返回。
  6. doFinal 方法在单部分工作中加密或解密数据,或完成多部分操作。数据是加密还是解密,取决于我们如何初始化密码。
  7. 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

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

用 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 中导入自定义类。如果该类存在于同一个包中,则通过创建其对象来使用该类,如果该类存在于另一个包中

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便