Why PBE generates same key with different salt and iteration count?

12,740

Solution 1

You got spectacularly lucky, and your random salts and iteration counts just happened to match. Go directly to Las Vegas. Now. ;)

I googled for PBEWithSHA1andDESede and tracked down this example: http://cryptofreek.org/2010/06/04/encrypting-and-decrypting-files-with-java wherein he specifies the key alone with new PBEKeySpec(password) and creates a separate PBEParameterSpec using the salt and iteration count which is then passed to Cipher.init().

So, no, you did nothing wrong, you just stopped before the salt and count got stuffed into the cipher.

Solution 2

If you use PBKDF2WithHmacSHA1 instead of PBEWithSHA1andDESede your assumption works as it supports salt. You just need to add a the keyLength parameter to PBEKeySpec:

        String algo = "PBKDF2WithHmacSHA1";

...

        PBEKeySpec decPBESpec = new PBEKeySpec( password, salt, iterationCount, 128 );

I have run a test and the result is: false.

However, note that for encryption and decryption to work properly you need to use the same salt and iteration count when generating the key.

Share:
12,740
Michael
Author by

Michael

Updated on June 06, 2022

Comments

  • Michael
    Michael about 2 years

    I am trying to test PBE encryption/decryption. I found that PBE generates same key with different salt and iteration count. Of course, the password used is same. As what I understand, same password and different salt/iteration should get different keys. Below is my test code:

    import java.security.Key;
    import java.security.SecureRandom;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.PBEKeySpec;
    
    public class PBETest
    {
        public static void main(String[] args)
            throws Exception
        {
            String algo = "PBEWithSHA1andDESede";
            System.out.println("====== " + algo + " ======");
    
            char[] password = "password".toCharArray();
            SecureRandom rand = new SecureRandom();
            byte[] salt = new byte[32];
            rand.nextBytes(salt);
            int iterationCount = rand.nextInt(2048);
    
            //encryption key
            PBEKeySpec          encPBESpec = new PBEKeySpec(password, salt, iterationCount);
            SecretKeyFactory    encKeyFact = SecretKeyFactory.getInstance(algo);
            Key encKey = encKeyFact.generateSecret(encPBESpec);
            System.out.println("encryptioin iteration: " + iterationCount);
    
            //decryption key
            rand.nextBytes(salt);
            iterationCount = rand.nextInt(2048);
            PBEKeySpec          decPBESpec = new PBEKeySpec(password, salt, iterationCount);
            SecretKeyFactory    decKeyFact = SecretKeyFactory.getInstance(algo);
            Key decKey = decKeyFact.generateSecret(decPBESpec);
            System.out.println("decryptioin iteration: " + iterationCount);
    
            System.out.println("encryption key is same as decryption key? " + encKey.equals(decKey));
    
        }
    
    }
    

    I am expecting the final output is a false. Did I do anything wrong?

  • Michael
    Michael almost 12 years
    Thanks tbroberg for your reply. 1, "salts and iteration counts just happened to match". The salt and iteration counts are generated randomly, and I do not think they can match for each run on this test. 2, "you just stopped before the salt and count got stuffed into the cipher". Do you mean the salt and iteration count only take effect when encryption/decryption is performing? 3, I found the keys are always "70 61 73 73 77 6f 72 64". I think that is for "password", and it is not related to salt or iteration count. Is that a correct result?
  • Michael
    Michael almost 12 years
    #2 and #3 seem explain the situation. I tried to go ahead to encrypt some text, and the encrypted data is different each time. So my conclusion now is: The key generated by SecretKeyFactory.generateSecret() is only related to the password. That is true at least from the comparison's point of view, i.e. key.getEncoded() is same. Salt and iteration count take effect when encrypting the plain text. Thanks again for your help!
  • tbroberg
    tbroberg almost 12 years
    Excellent! (#1 was a joke.) If you found the answer useful, please mark it so. :^)
  • Michael
    Michael almost 12 years
    I will do that. However, my reputation is too low. I can only accept it, but cannot mark it as useful. I am very sorry I could not do it for now. I promise to come back and mark it :)