Search code examples
javapassword-hash

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


I was experimenting with key derivation functions and I noticed that the secret keys I generate via all the PBE algorithms encode to the plain text password.

With that I mean that:

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()));
    }
}

prints password where I expected 1024 seemingly-random bytes. This doesn't quite add up for me.. can you explain it?

BTW: Note the same code does seem to work as I expect with PBKDF2 algorithms.

PS: In case it matters, I'm using vanilla OpenJDK 13 on mac (13.0.1.hs-adpt)


Solution

  • Encoded doesn't mean encrypted. As per Key class javadoc getEncoded() method returns a representation of the key:

     * 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.
    

    Since PBEWithHMACSHA512AndAES_256 is a symmetric algorithm the observed behavior makes sense. The same key is used to perform both encryption and decryption, it can't be modified.

    Taking a look at How do I properly use the “PBEWithHmacSHA512AndAES_256” algorithm? question. You need to encrypt the input, below byte[] messageBytes, with correct Cipher instance:

    Cipher cipherEncrypt = Cipher.getInstance("PBEWithHMACSHA512AndAES_256");
    cipherEncrypt.init(Cipher.ENCRYPT_MODE, key);
    
    byte[] cipherBytes = cipherEncrypt.doFinal(messageBytes);
    byte[] iv = cipherEncrypt.getIV();