无法将 Jasypt 加密密码保存到 .properties 文件

Can't save Jasypt encrypted password to .properties file

我正在尝试将一些字符串存储在 .properties 文件中。现在我想用 Jasypt 加密这些字符串。但是当我尝试将其保存到 .properties 文件时,它缺少周围的 "ENC()"。当我尝试手动插入时,字符串以明文形式存储。为什么?

StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
encryptor.setPassword("123456789");
Properties prop = new EncryptableProperties(encryptor);
prop.setProperty("key", "ENC(" + encryptor.encrypt("value") + ")");
prop.store(new FileOutputStream(System.getProperty("user.home") + "/.application-name/config.properties"), "Test");

查看 JDK 源代码可以解释这里发生了什么。原因是涉及的 class 层次结构; org.jasypt.properties.EncryptableProperties 扩展 java.util.Properties 进而扩展 java.util.Hashtable.

所以当prop.store()被调用时,java.util.Properties中的方法被调用:

public void store(OutputStream out, String comments)
    throws IOException
{
    store0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")),
           comments,
           true);
}

private void store0(BufferedWriter bw, String comments, boolean escUnicode)
    throws IOException
{
    if (comments != null) {
        writeComments(bw, comments);
    }
    bw.write("#" + new Date().toString());
    bw.newLine();
    synchronized (this) {
        for (Enumeration e = keys(); e.hasMoreElements();) {
            String key = (String)e.nextElement();
            String val = (String)get(key);
            key = saveConvert(key, true, escUnicode);
            /* No need to escape embedded and trailing spaces for value, hence
             * pass false to flag.
             */
            val = saveConvert(val, false, escUnicode);
            bw.write(key + "=" + val);
            bw.newLine();
        }
    }
    bw.flush();
}

有趣的是

String val = (String)get(key);

EncryptableProperties 定义一个

public Object get(Object key)

方法,覆盖 java.util.Hashtable - see the Jasypt API docs for EncryptableProperties 的方法。因此调用了下面的方法,正如您通过阅读 decode 方法看到的那样,它将执行解密,在您的情况下这不是您想要的!

public synchronized Object get(final Object key) {
    final Object value = super.get(key);
    final String valueStr = 
            (value instanceof String) ? (String)value : null;
    return decode(valueStr);
}


private synchronized String decode(final String encodedValue) {

    if (!PropertyValueEncryptionUtils.isEncryptedValue(encodedValue)) {
        return encodedValue;
    }
    if (this.stringEncryptor != null) {
        return PropertyValueEncryptionUtils.decrypt(encodedValue, this.stringEncryptor);

    }
    if (this.textEncryptor != null) {
        return PropertyValueEncryptionUtils.decrypt(encodedValue, this.textEncryptor);
    }

    /*
     * If neither a StringEncryptor nor a TextEncryptor can be retrieved
     * from the registry, this means that this EncryptableProperties
     * object has been serialized and then deserialized in a different
     * classloader and virtual machine, which is an unsupported behaviour. 
     */
    throw new EncryptionOperationNotPossibleException(
            "Neither a string encryptor nor a text encryptor exist " +
            "for this instance of EncryptableProperties. This is usually " +
            "caused by the instance having been serialized and then " +
            "de-serialized in a different classloader or virtual machine, " +
            "which is an unsupported behaviour (as encryptors cannot be " +
            "serialized themselves)");

}

为避免这种情况,请勿使用 EncryptableProperties 来存储您的属性,只需使用 java.util.Properties 即可。只需替换

Properties prop = new EncryptableProperties(encryptor);

Properties prop = new Properties();

并且加密值将存储在属性文件中。