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?
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:
generatePswdBasedKey
and compare that they give the same encrypted stringor you
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;
}