0
votes

NOTE: Per the accepted answer, this was simply a matter of supplying the wrong key. If it's useful to others, I've left the code and initial question below.

=======

I had encrypted some text about a year and a half ago and now I can't decrypt it. It worked then (and I know that the string itself hasn't changed), but now I get a "Given final block not properly padded" BadPaddingException.

Here's a standalone program with an encrypted string, key, and the code that I used at the time:

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;


public class DoDecode {
    private static final String DES_TYPE = "DES";
//    private static final String DES_TYPE = "DES/CBC/NoPadding";
//    private static final String DES_TYPE = "DES/CBC/PKCS5Padding";
//    private static final String DES_TYPE = "DES/ECB/NoPadding";
//    private static final String DES_TYPE = "DES/ECB/PKCS5Padding"; //Use this
//    private static final String DES_TYPE = "DESede/CBC/NoPadding";
//    private static final String DES_TYPE = "DESede/CBC/PKCS5Padding";
//    private static final String DES_TYPE = "DESede/ECB/NoPadding";
//    private static final String DES_TYPE = "DESede/ECB/PKCS5Padding";

    public synchronized static String encode(String unencodedString, String key) {
        String ret = null;

        try {
            DESKeySpec keySpec = new DESKeySpec(key.getBytes("UTF8"));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey skey = keyFactory.generateSecret(keySpec);
            sun.misc.BASE64Encoder base64encoder = new BASE64Encoder();

            byte[] cleartext = unencodedString.getBytes("UTF8");

            Cipher cipher = Cipher.getInstance(DES_TYPE);
            cipher.init(Cipher.ENCRYPT_MODE, skey);

            ret = base64encoder.encode(cipher.doFinal(cleartext));
        } catch (Exception ex) {
            System.err.println("Encode exception: "+ex.getMessage());
        }

        return ret;
    }

    public static String decode(String encodedString, String key) {
        String ret = null;

        try {
            DESKeySpec keySpec = new DESKeySpec(key.getBytes("UTF8"));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey skey = keyFactory.generateSecret(keySpec);
            sun.misc.BASE64Decoder base64decoder = new BASE64Decoder();

            byte[] encrypedPwdBytes = base64decoder.decodeBuffer(encodedString);

            Cipher cipher = Cipher.getInstance(DES_TYPE);
            cipher.init(Cipher.DECRYPT_MODE, skey);
            byte[] plainTextPwdBytes = (cipher.doFinal(encrypedPwdBytes));

            ret = new String(plainTextPwdBytes);
        } catch (Exception ex) {
            System.err.println("Decode exception: " + ex.getMessage());
        }

        return ret;
    }

    private static final String wasValidStr = "h1JTFcRjW6vveQUrQqPUgnjGXo3NEZKDnBThZQN7uLfzPEpeFFONV4mvL71cT/xQb1mz5Xa/XZ/aW2GawZNumgO0reUZSDh30F7NfK0S/rMWM8FxcjBCkfFWAbLZHcyDJ5wW3F1yl5g=";

    public static void main(String[] args) {
        System.out.println(DoDecode.decode(wasValidStr, "invpwd~~"));

        String encoded = DoDecode.encode("This has worked in the past!", "invpwd~~");
        System.out.println(encoded);
        System.out.println(DoDecode.decode(encoded, "invpwd~~"));
    }
}

Gives me output of:

Decode exception: Given final block not properly padded
null
U3ruztxHelQegTLyyA3IfMaGgVtmbP5na43S9JQmIc8=
This has worked in the past!

Note that I restored the code that I used since it may be a culprit. I'm not currently using the sun.misc packages for Base64 and I get the same errors (java.util.Base64).

I've tried this on Linux, a Mac and a PC with the same result. I utilized multiple JDK versions back to Java 1.6u45. I also run the sample code with each of the different DES_TYPEs at the top of the class.

Any help much appreciated!

1
Have you also tried it with multiple JRE versions, because that is that counts?Artjom B.
General advice: Always use a fully qualified Cipher string. Cipher.getInstance("DES"); may result in different ciphers depending on the default security provider. It most likely results in "DES/ECB/PKCS5Padding", but it doesn't have to be. If it changes, you'll lose compatibility between different JVMs. For reference: Java default Crypto/AES behaviorArtjom B.
Thanks for the comments. I have updated my code to reflect the different Cipher strings I tried today (unfortunately the original code only specified "DES"). Yes, I tried with different JRE's by setting the Java Build Path in Eclipse, rebuilding, and running.Tim.E

1 Answers

0
votes

I tracked down the answer. The secret key was, in fact incorrect. The error message is so confusing that I had been chasing far more sophisticated reasons for the Exception. When I finally broke down and tried other historical keys, one magically unlocked everything. :(

So (as other posts have highlighed), this error might just mean that you have supplied the wrong key.