Frederik
Frederik

Reputation: 83

AES BadPaddingException

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

Answers (3)

Nik theGeeK
Nik theGeeK

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

maybeWeCouldStealAVan
maybeWeCouldStealAVan

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

L&#233;o Germond
L&#233;o Germond

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

Related Questions