为什么 SecretKey.getEncoded() returns PBE 生成的密钥的明文密码?

How come SecretKey.getEncoded() returns the plaintext password for PBE-generated secret keys?

我正在试验密钥派生函数,我注意到我通过所有 PBE 算法生成的密钥都编码为纯文本密码。

我的意思是:

public class Main {
    public static void main(String[] args) throws Exception {
        byte[] salt = new byte[256/8];
        SecureRandom.getInstanceStrong().nextBytes(salt);
        KeySpec spec = new PBEKeySpec("password".toCharArray(), salt, /*iterations*/ 1000, /*key length*/ 1024);
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWithHMACSHA512AndAES_256"); // PBE with HMAC SHA512 and AES_256
        SecretKey secret = factory.generateSecret(spec);
        System.out.println(new String(secret.getEncoded()));
    }
}

打印 password 我预期的 1024 个看似随机的字节。这对我来说不太合乎情理。你能解释一下吗?

顺便说一句:请注意,使用 PBKDF2 算法时,相同的代码似乎确实可以正常工作。

PS:以防万一,我在 mac (13.0.1.hs-adpt)

上使用 vanilla OpenJDK 13

编码并不意味着加密。根据 Key class javadoc getEncoded() 方法 returns 键的表示:

 * This is an external encoded form for the key used when a standard
 * representation of the key is needed outside the Java Virtual Machine,
 * as when transmitting the key to some other party. The key
 * is encoded according to a standard format (such as
 * X.509 {@code SubjectPublicKeyInfo} or PKCS#8), and
 * is returned using the {@link #getEncoded() getEncoded} method.

由于 PBEWithHMACSHA512AndAES_256 是一种对称算法,因此观察到的行为是有意义的。加密和解密使用同一个密钥,不能修改。

正在查看 问题。您需要使用正确的 Cipher 实例对 byte[] messageBytes 以下的输入进行加密:

Cipher cipherEncrypt = Cipher.getInstance("PBEWithHMACSHA512AndAES_256");
cipherEncrypt.init(Cipher.ENCRYPT_MODE, key);

byte[] cipherBytes = cipherEncrypt.doFinal(messageBytes);
byte[] iv = cipherEncrypt.getIV();