Why PBE generates same key with different salt and iteration count?
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.
Michael
Updated on June 06, 2022Comments
-
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 almost 12 yearsThanks 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 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 almost 12 yearsExcellent! (#1 was a joke.) If you found the answer useful, please mark it so. :^)
-
Michael almost 12 yearsI 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 :)