Reputation: 83
if I use a wrong key or wrong salt for decryption an BadPaddingException is thrown. I would expect an incorrect string to be returned. The doFinal() causes the exception in the decrypt-method
Message : This is just an example
Unfug : 'ΩÙΩ„SåF?V®ßs.k˚·ºç€èÀHfif∫ÙÉÕ
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
at casino.AES.decryptString(AES.java:130)
at casino.AES.main(AES.java:172)
public static void main(String[] args) throws Exception {
//Encryption
AES encr = new AES();
encr.setKey("KEY");
encr.setSalt("SALT");
encr.setup();
String message = "This is just an example";
System.out.println("Message : " + message);
byte[] code = encr.encrypt(message);
System.out.println("Encrypted Strinng : "+ new String(code, "UTF-8"));
//Decryption
AES dec = new AES();
dec.setKey("INCORRECT"); //<--- incorrect
dec.setSalt("SALT");
dec.setup();
System.out.println(dec.decryptString(code));
}
public synchronized void setKey(String key) throws UnsupportedEncodingException {
this.key = key.getBytes("UTF-8");
isPasswordAlreadySet = true;
}
public synchronized void setSalt(String salt) throws UnsupportedEncodingException {
this.salt = salt.getBytes("UTF-8");
}
public synchronized void setup() throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(key);
digest.update(salt);
byte[] raw = digest.digest();
skeySpec = new SecretKeySpec(raw, "AES");
cipher = Cipher.getInstance("AES");
}
public synchronized byte[] encrypt(byte[] klartext) throws Exception {
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(klartext);
return encrypted;
}
public synchronized byte[] encrypt(String klartext) throws Exception{
return encrypt(klartext.getBytes("UTF-8"));
}
public synchronized byte[] decrypt(byte[] code) throws Exception {
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original = cipher.doFinal(code);
return original;
}
public synchronized double decryptDouble(byte[] code) throws Exception {
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original = cipher.doFinal(code);
return doubleFromBytes( original);
}
Thank you! Frederik
Upvotes: 2
Views: 7541
Reputation: 181
SecretKeySpec specifies a secret key in a provider-independent fashion
http://themasterofmagik.wordpress.com/2014/03/19/simple-aes-encryption-and-decryption-in-java/
Upvotes: 0
Reputation: 15610
The padding is a fine sanity check. Assuming the incorrectly decrypted data is uniformly distributed, it will only appear to be correctly PKCS5/PKCS7 padded about 1 time for every 255 incorrect passwords. (1/256 + 1/256^2 + 1/256^3 ...)
So it's helpful, but it's not something you should rely on --- what is effectively an almost-8-bit message digest is not a sufficient test of data integrity.
One more thing: If an attacker can repeatedly alter the ciphertext and get you to decrypt it, (an example might be encrypted data stored in a cookie) and if they can distinguish between your behavior when the decrypted data throws an exception for bad padding and when it is simply garbage, then they can determine the plaintext via a "padding oracle attack".
By the way, if you actually want the behavior you expected, you can use "AES/CTR/NoPadding", which will not require an exact block size and will always return a decrypted byte[], whether or not the keys match.
Upvotes: 6
Reputation: 721
You should either use AES with an implicit padding declaration (see the available modes) or force the length (in bytes) of data encrypted/decrypted to be a multiple of 16.
Also, by default, java uses ECB mode, which can be really unsecured depending on which type of data you are using, you should probably use a CBC mode.
Upvotes: 3