I have the following simple encryption/decryption code:
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.RandomStringUtils;
:
public class MyUtility {
private static Cipher instance = Cipher.getInstance("AES/CBC/PKCS5Padding");
private static Cipher instance2 = Cipher.getInstance("AES/CBC/PKCS5Padding");
private static byte[] iv = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
private static String encrypt(String data, DataParameters params) throws Exception {
IvParameterSpec ivspec = new IvParameterSpec(iv);
String privateKey = MyUtility.getKey(params);
SecretKey key = new SecretKeySpec(privateKey.getBytes(), "AES");
instance.init(Cipher.ENCRYPT_MODE, key, ivspec);
String paddedData = addPaddDate(data);
byte[] encryptedBytes = instance.doFinal(paddedData.getBytes());
byte[] encodeBase64 = Base64.encodeBase64(encryptedBytes);
String encryptedStr = new String(encodeBase64);
then soon perform an decryption:
byte[] decodeBytes = Base64.decodeBase64(encryptedStr.getBytes()); // Decode
String padDecryptedStr = new String(instance2.doFinal(decodeBytes));
Then 95% of the time, the decrypted values are correct. However, occasionally, I got the following error:
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:420)
at javax.crypto.Cipher.doFinal(Cipher.java:1966)
at myCode.decrypt(MyEncryptDecryptUtility.java:97)
where line 97 is String padDecryptedStr = new String(instance2.doFinal(decodeBytes));
And the decrypted values look like weird character strings such as: \u001d��tq@s�2�a or �w�����$�X\u0005
This is the padding function I use:
private static String addPaddDate(String data) {
return data + RandomStringUtils.randomAlphanumeric(10);
}
Any idea what is missing in the above code?
Thank you!
Just want to update some more information I found:
When the decrypted value is a weird character string, I decrypted again, then the second time I got the correct value. Anyone know why is that? Thanks!
BadPaddingExceptionString.getBytes()andnew String(byte[])may use different Charset's that damage your data. Pick one suitable Charset and specify it at both ends; UTF-8 is popular and safe for anything.instance.init(Cipher.ENCRYPT_MODE, key); byte[] iv = instance.getIV();I'm not sure how creating (a potentially blocking operation) and managingSecureRandominstances could be simpler than that. When you specify the same IV every time, attackers can tell that you are encrypting the same message. The purpose of the IV is to produce different cipher text from the same message. Your padding won't do that if the plain text is longer than one block. It will only change the end of the message. Using the IV correctly will change the whole cipher text.