Question

I'm having some trouble here while trying to decode some encrypted text. CheckpswdBasedKey is always returning false, because of the BadPaddingException at c.doFInal I'm using AES, basicaly the encryption:

public static String generatePswdBasedKey(String password){
String finalKey = null;
SecretKey sk = null;
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, IT, KEY_LENGTH);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
sk = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance(Cifrador.AES_MODE);//AES_MODE = AES/CBC/PKCS5Padding
IvParameterSpec ivParams = new IvParameterSpec(iv);//IV already initialized
cipher.init(Cipher.ENCRYPT_MODE, sk, ivParams);
byte pwdbytes[] = password.getBytes();//I also tried using Base64 to decode... without success
byte cc[] = cipher.doFinal(pwdbytes);
finalKey = Base64.encodeToString(cc, false);  //.encodeToString(byte[] sArr, boolean lineSep)
return finalKey;

Now decrypt mode:

//This method compares a password received from keyboard with the decrypted password (decrypting output from generatePswdBasedKey(String password))
public static boolean checkPswdBasedKey(String password, String passwordInput){
byte bufferBytes[] = Base64.decode(password);
SecretKey sk = new SecretKeySpec(bufferBytes, 0, bufferBytes.length, "AES"); //Also tried new SecretKeySPec(bufferBytes, "AES");...
Cipher c = Cipher.getInstance(Cifrador.AES_MODE);//AES_MODE = AES/CBC/PKCS5Padding
IvParameterSpec ivParams = new IvParameterSpec(iv);//IV already initialized
c.init(Cipher.DECRYPT_MODE, sk, ivParams);
byte result[] = c.doFinal(bufferBytes);
String resultStr = Base64.encodeToString(result, false); //.encodeToString(byte[] sArr, boolean lineSep)
if(passwordInput.equalsIgnoreCase(resultStr)){
return true;
}
return false;
}

I compared bytes from iv @checkPswdBasedKey and iv @generatePswdBasedKey and they are all the same. Same happens to the secretkey @checkPswdBasedKey (i get those bytes with: sk.getEncoded() ) and secretkey @generatePswdBasedKey... they are all equal. So basically when i decrypt i know i'm using the same key, same IV and same message... and an appropiate length (16 bytes key, 16 bytes msg, 16 bytes iv, using AES 128) Any idea?

Était-ce utile?

La solution

As Joachim Isaksson commented, if you want to implement a password check, you ought to use a secure hash representation of the password, that is not reversible. This way, the password can't be obtained by decryption even if the hash + key is compromised.

Anyway, in your generatePswdBasedKey you use the PBKDF2WithHmacSHA1 algorithm to generate a SecretKey, and then use that key to encrypt the password. Now you have two options to verify the password in checkPswdBasedKey. Either you:

  • encrypt the password the same way as in generatePswdBasedKey and compare that they give the same encrypted string

or you

  • decrypt the encrypted version and compare the result with the password in clear.

I presume that you try the later approach as you init your cipher for decrypt with:

c.init(Cipher.DECRYPT_MODE, sk, ivParams);

Hovewer, for that approach to work you need to instantiate your SecretKey the same way as you did in generatePswdBasedKey - currently you end up with two different keys.

In generatePswdBasedKey:

SecretKey sk = null;
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, IT, KEY_LENGTH);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
sk = new SecretKeySpec(keyBytes, "AES");

In checkPswdBasedKey:

byte bufferBytes[] = Base64.decode(password);
SecretKey sk = new SecretKeySpec(bufferBytes, 0, bufferBytes.length, "AES");

When that is fixed, you also need to look at your compare logic. You should not do a Base64 encoding of your result before the compare - and the compare ought to be case sensitive. Don't use:

byte result[] = c.doFinal(bufferBytes);
String resultStr = Base64.encodeToString(result, false);
if (passwordInput.equalsIgnoreCase(resultStr)) {
    return true;
}

But instead use:

byte result[] = c.doFinal(bufferBytes);
String resultStr = new String(result);
if (passwordInput.equals(resultStr)) {
    return true;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top