Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

badPaddingException on some call of the doFinal. Not all. Same input

I use a javax.crypto.cipher for encrypt and decrypt some data. It's working well. But sometimes, the decryption faill with a badPaddingException. If i compare a succefull call with a failling call, the input given to the cipher are the same, and the cipher is initialised the same way.

that how i instanciate my cipher

dcipher = Cipher.getInstance("PBEWithMD5AndDES");
KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount);
SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec);
dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);

That how i use it

dec = Base64.decode(str) ;
byte[] utf8 = dcipher.doFinal(dec);

The exception is raised on the doFinal.

Any idea ?

Thanks !

Oh, btw, i use bouncyCastle as a provider, and add it on top on the list with

Security.insertProviderAt(new org.bouncycastle.jce.provider.BouncyCastleProvider(), 1);

For the sake of the completeness, and because the problem still appeart from time to time. Here is the complete class.

public class EncryptDecryptUtil {
    /** Encryption Cipher */
    private static Cipher ecipher;
    /** Decription Cipher */
    private static Cipher dcipher;

    private static Logger logger = Logger.getLogger(EncryptDecryptUtil.class);

    /**
     * Constructor used to create this object. Responsible for setting and initializing this object's encrypter and
     * decrypter Cipher instances given a Secret Key and algorithm.
     * 
     * @param key Secret Key used to initialize both the encrypter and decrypter instances.
     * @param algorithm Which algorithm to use for creating the encrypter and decrypter instances.
     */
    public EncryptDecryptUtil(SecretKey key, String algorithm) {
        Security.insertProviderAt(new org.bouncycastle.jce.provider.BouncyCastleProvider(), 1);
        try {
            ecipher = Cipher.getInstance(algorithm);
            dcipher = Cipher.getInstance(algorithm);
            ecipher.init(Cipher.ENCRYPT_MODE, key);
            dcipher.init(Cipher.DECRYPT_MODE, key);
        } catch (NoSuchPaddingException e) {
            System.out.println("EXCEPTION: NoSuchPaddingException");
        } catch (NoSuchAlgorithmException e) {
            System.out.println("EXCEPTION: NoSuchAlgorithmException");
        } catch (InvalidKeyException e) {
            System.out.println("EXCEPTION: InvalidKeyException");
        }
    }

    /**
     * Constructor used to create this object. Responsible for setting and initializing this object's encrypter and
     * decrypter Chipher instances given a Pass Phrase and algorithm.
     * 
     * @param passPhrase Pass Phrase used to initialize both the encrypter and decrypter instances.
     */
    public EncryptDecryptUtil(String passPhrase) {
        Security.insertProviderAt(new org.bouncycastle.jce.provider.BouncyCastleProvider(), 1);
        // 8-bytes Salt
        byte[] salt = { (byte) 0xB9, (byte) 0x8B, (byte) 0xD8, (byte) 0x31, (byte) 0x55, (byte) 0x24, (byte) 0xF3, (byte) 0x13 };

        // Iteration count
        int iterationCount = 19;

        try {
            // Generate the secret key associated to the passphrase.
            KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount);
            SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec);

            // Get instance of the cipher
            ecipher = Cipher.getInstance("PBEWithMD5AndDES");
            dcipher = Cipher.getInstance("PBEWithMD5AndDES");

            // Prepare the parameters to the cipthers
            AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);

            ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
            dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);

        } catch (InvalidAlgorithmParameterException e) {
            logger.error("during encrypter instantiation",e);
        } catch (InvalidKeySpecException e) {
            logger.error("during encrypter instantiation",e);
        } catch (NoSuchPaddingException e) {
            logger.error("during encrypter instantiation",e);
        } catch (NoSuchAlgorithmException e) {
            logger.error("during encrypter instantiation",e);
        } catch (InvalidKeyException e) {
            logger.error("during encrypter instantiation",e);
        }
    }

    /**
     * Takes a single String as an argument and returns an Encrypted version of that String.
     * 
     * @param str String to be encrypted
     * @return <code>String</code> Encrypted version of the provided String
     */
    public String encrypt(String str) {
        try {
            // Encode the string into bytes using utf-8
            byte[] utf8 = str.getBytes("UTF8");

            // Encrypt
            byte[] enc = ecipher.doFinal(utf8);

            // Encode bytes to base64 to get a string
            return new String( Base64.encode(enc), "UTF8");

        } catch (BadPaddingException e) {
            logger.error("during encryption : ",e);
        } catch (IllegalBlockSizeException e) {
            logger.error("during encryption : ",e);
        } catch (UnsupportedEncodingException e) {
            logger.error("during encryption : ",e);
        } 
        return new String();
    }


    /**
     * Takes a encrypted String as an argument, decrypts and returns the decrypted String.
     * 
     * @param str Encrypted String to be decrypted
     * @return <code>String</code> Decrypted version of the provided String
     */
    public String decrypt(String str) {
        byte[] dec = new byte[0];
        try {
            // Decode base64 to get bytes. Not sure to understand why.
            dec = Base64.decode(str) ;
            // Decrypt
            byte[] utf8 = dcipher.doFinal(dec);
            // Decode using utf-8
            return new String(utf8, "UTF8");

        } catch (BadPaddingException e) {
            logger.error("error during decryption. String to decode was : "+str + " byte array to decode was : "+ Arrays.toString(dec) ,e);
        } catch (IllegalBlockSizeException e) {
            logger.error("during decryption : ",e);
        } catch (UnsupportedEncodingException e) {
            logger.error("during decryption : ",e);
        }  
        return new String();
    }
}

Edit : I would like to stress this 2 points :

  • the same input will sometime fail / sometime be sucessfully decrypted. ( i know that thanks to the logs in the BadPaddingException )
  • this main calling the decrypt method 1 000 000 000 times doest reproduce the issus.

...

for( int i = 0 ; i<1000000000 ; i++){
    EncryptDecryptUtil encryptDecript = new EncryptDecryptUtil("pass");
    if ( !"YES".equals(encryptDecript.decrypt("Q3qWLKo6yJY="))){
        System.out.println("Fail at call " + i);
        throw new InvalidParameterException() ;
    }
}

So maybe it could come from the way i use the EncryptDecryptUtils class ? It's a field of a Spring bean, instancied one time.

com.myStuff.dlm.cryptography.EncryptDecryptUtil  error during decryption. String to   decode was : Q3qWLKo6yJY= byte array to decode was : [114, 52, -52, -54, 82, 87, 124, 84]
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.SunJCE_ab.b(DashoA13*..)
    at com.sun.crypto.provider.PBEWithMD5AndDESCipher.engineDoFinal(DashoA13*..)
    at javax.crypto.Cipher.doFinal(DashoA13*..)
    at com.dvidea.dlm.cryptography.EncryptDecryptUtil.decrypt(EncryptDecryptUtil.java:166)
like image 855
Antoine Claval Avatar asked Feb 04 '11 08:02

Antoine Claval


People also ask

What causes bad padding exception?

Class BadPaddingException This exception is thrown when a particular padding mechanism is expected for the input data but the data is not padded properly.

What is ciphering in android?

This class provides the functionality of a cryptographic cipher for encryption and decryption. It forms the core of the Java Cryptographic Extension (JCE) framework. In order to create a Cipher object, the application calls the Cipher's getInstance method, and passes the name of the requested transformation to it.

What is bad padding?

The "bad padding" message appears when the encryption between the agent and scheduler do not match.

What is IllegalBlockSizeException?

javax.crypto.IllegalBlockSizeException. This exception is thrown when the length of data provided to a block cipher is incorrect, i.e., does not match the block size of the cipher.


1 Answers

Just an idea: Maybe you are jumping among different providers (Sun/BC/etc)

Regards.

like image 182
ATorras Avatar answered Sep 28 '22 13:09

ATorras