在java中加密和解密属性文件值

2022-09-03 15:24:58

我正在寻找一种方法来加密Java程序正在读取的配置文件中的密码。目前,我从文本文件中读入密码,但如果有人查看配置文件,密码就会处于打开状态。

我正在考虑构建一个简单的类,用户可以在其中键入所需的密码,获取密码的加密版本,然后将加密版本粘贴到配置文本文件中。然后,应用程序将读取加密的密码,将密码解密回字符串,然后继续。

我在字符串上遇到了问题 - >crytped字节 - >字符串转换。

我正在使用内置的java安全类来实现此代码。下面是一些示例测试代码:

    // Reads password from config file
String password = ScriptConfig.getString( "password" );

// Generate Key
KeyGenerator kg = KeyGenerator.getInstance("DES");
Key key = kg.generateKey();

// Create Encryption cipher
Cipher cipher = Cipher.getInstance( "DES" );
cipher.init( Cipher.ENCRYPT_MODE, key );

// Encrypt password
byte[] encrypted = cipher.doFinal( password.getBytes() );

// Create decryption cipher
cipher.init( Cipher.DECRYPT_MODE, key );
byte[] decrypted = cipher.doFinal( encrypted );

// Convert byte[] to String
String decryptedString = new String(decrypted);

System.out.println("password: " + password);
System.out.println("encrypted: " + encrypted);
System.out.println("decrypted: " + decryptedString);

// Read encrypted string from config file
String encryptedPassword = ScriptConfig.getString( "encryptedPassword"
);

// Convert encryptedPassword string into byte[]
byte[] encryptedPasswordBytes = new byte[1024];
encryptedPasswordBytes = encryptedPassword.getBytes();

// Decrypt encrypted password from config file
byte[] decryptedPassword = cipher.doFinal( encryptedPasswordBytes );//error here

System.out.println("encryptedPassword: " + encryptedPassword);
System.out.println("decryptedPassword: " + decryptedPassword);


The config file has the following variables:
password=password
encryptedPassword=[B@2a4983


When I run the code, I get the following output:
password: passwd
encrypted: [B@2a4983
decrypted: passwd
javax.crypto.IllegalBlockSizeException: Input length must be multiple
of 8 when decrypting with padded cipher
at com.sun.crypto.provider.SunJCE_h.b(DashoA12275)
at com.sun.crypto.provider.SunJCE_h.b(DashoA12275)
at com.sun.crypto.provider.DESCipher.engineDoFinal(Da shoA12275)
at javax.crypto.Cipher.doFinal(DashoA12275)
at com.sapient.fbi.uid.TestEncryption.main(TestEncryp tion.java:4

有关我用来执行此操作的错误,结构或过程的任何帮助都将很棒。谢谢。


答案 1

看看Jasypt。它已经为您完成了繁重的工作。具体来说,就是 和 类。org.jasypt.encryption.pbe.StandardPBEStringEncryptororg.jasypt.properties.PropertyValueEncryptionUtils

创建加密器:

SimplePBEConfig config = new SimplePBEConfig(); 
config.setAlgorithm("PBEWithMD5AndTripleDES");
config.setKeyObtentionIterations(1000);
config.setPassword("propertiesFilePassword");

StandardPBEStringEncryptor encryptor = new org.jasypt.encryption.pbe.StandardPBEStringEncryptor();
encryptor.setConfig(config);
encryptor.initialize();

然后用于加密/解密值:PropertyValueEncryptionUtils

PropertyValueEncryptionUtils.encrypt(value, encryptor);
PropertyValueEncryptionUtils.decrypt(encodedValue, encryptor)

请注意,编码值将以 开头和结尾,因此很容易判断文件中的属性是否已加密。ENC()

另请注意,用于的密码不是要编码以存储在属性文件中的密码。相反,它是加密/解密您正在存储的值的密码。此密码是什么以及如何设置它取决于您。我默认为正在读取属性文件的任何内容的完全限定类名。config.setPassword()

最后,如果您使用的是Spring,Jasypt有一个类,您可以使用该类来加载属性文件,并使用Spring XML文件中的语法来对数据库密码之类的内容进行变量替换。EncryptablePropertyPlaceholderConfigurer${foo}


答案 2

以下是一些在Java中使用AES进行加密或解密的帮助程序:

public static final String AES = "AES";

/**
 * Encrypt a value and generate a keyfile.
 * If the keyfile is not found, then a new one will be created.
 * 
 * @throws GeneralSecurityException
 * @throws IOException if an I/O error occurs
 */
public static String encrypt(String value, File keyFile)
        throws GeneralSecurityException, IOException {
    if (!keyFile.exists()) {
        KeyGenerator keyGen = KeyGenerator.getInstance(CryptoUtils.AES);
        keyGen.init(128);
        SecretKey sk = keyGen.generateKey();
        FileWriter fw = new FileWriter(keyFile);
        fw.write(byteArrayToHexString(sk.getEncoded()));
        fw.flush();
        fw.close();
    }

    SecretKeySpec sks = getSecretKeySpec(keyFile);
    Cipher cipher = Cipher.getInstance(CryptoUtils.AES);
    cipher.init(Cipher.ENCRYPT_MODE, sks, cipher.getParameters());
    byte[] encrypted = cipher.doFinal(value.getBytes());
    return byteArrayToHexString(encrypted);
}

/**
 * Decrypt a value.
 * 
 * @throws GeneralSecurityException
 * @throws IOException if an I/O error occurs
 */
public static String decrypt(String message, File keyFile)
        throws GeneralSecurityException, IOException {
    SecretKeySpec sks = getSecretKeySpec(keyFile);
    Cipher cipher = Cipher.getInstance(CryptoUtils.AES);
    cipher.init(Cipher.DECRYPT_MODE, sks);
    byte[] decrypted = cipher.doFinal(hexStringToByteArray(message));
    return new String(decrypted);
}

private static SecretKeySpec getSecretKeySpec(File keyFile)
        throws NoSuchAlgorithmException, IOException {
    byte[] key = readKeyFile(keyFile);
    SecretKeySpec sks = new SecretKeySpec(key, CryptoUtils.AES);
    return sks;
}

private static byte[] readKeyFile(File keyFile)
        throws FileNotFoundException {
    Scanner scanner = new Scanner(keyFile).useDelimiter("\\Z");
    String keyValue = scanner.next();
    scanner.close();
    return hexStringToByteArray(keyValue);
}

private static String byteArrayToHexString(byte[] b) {
    StringBuffer sb = new StringBuffer(b.length * 2);
    for (int i = 0; i < b.length; i++) {
        int v = b[i] & 0xff;
        if (v < 16) {
            sb.append('0');
        }
        sb.append(Integer.toHexString(v));
    }
    return sb.toString().toUpperCase();
}

private static byte[] hexStringToByteArray(String s) {
    byte[] b = new byte[s.length() / 2];
    for (int i = 0; i < b.length; i++) {
        int index = i * 2;
        int v = Integer.parseInt(s.substring(index, index + 2), 16);
        b[i] = (byte) v;
    }
    return b;
}

只需调用适当的方法。


推荐