2

I'm having problem with decoding an encrypted text.
When the encrypted message is received, Java would sometimes throw an exception below.

javax.crypto.BadPaddingException: Given final block not properly padded
    at com.sun.crypto.provider.SunJCE_h.b(DashoA12275)
    at com.sun.crypto.provider.SunJCE_h.b(DashoA12275)
    at com.sun.crypto.provider.SunJCE_af.b(DashoA12275)
    at com.sun.crypto.provider.PBEWithMD5AndDESCipher.engineDoFinal(DashoA12275)
    at javax.crypto.Cipher.doFinal(DashoA12275)
    at com.inv.my.encrypt.StringEncrypter.decrypt(StringEncrypter.java:206)
    at com.inv.my.encrypt.EncryptDecryptMachine.decrypt(EncryptDecryptMachine.java:56)
    at com.inv.my.servlet.transfer.hq.RequestStockQty.doPost(RequestStockQty.java:47)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:709)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:592)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:244)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAsPrivileged(Subject.java:517)
    at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:276)
    at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:162)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:262)
    at org.apache.catalina.core.ApplicationFilterChain.access$0(ApplicationFilterChain.java:192)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:171)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:167)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:172)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:151)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:874)
    at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
    at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
    at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
    at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)
    at java.lang.Thread.run(Thread.java:595)

My server setup is...

  1. Ubuntu 8.04 LTS
  2. Java 5
  3. Tomcat5.5

Weirdly enough the problem is intermittent. After restarting the server, it would go away but would come back later again which I would restart my tomcat again just to temporarily fix it.

Thanks!


Edit-Add Code:

The code I use is from...

http://www.idevelopment.info/data/Programming/java/security/java_cryptography_extension/StringEncrypter.java

and modified it a bit, below is my actual code. I removed the comments to make it shorter.

Thanks!

public class StringEncrypter {
Cipher ecipher;
Cipher dcipher;


public StringEncrypter(SecretKey key, String algorithm) {
    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");
    }
}



public StringEncrypter(String passPhrase) {

    setPassPhrase( passPhrase );

}


public void setPassPhrase( String passPhrase ) {

    // 8-bytes Salt
    byte[] salt = {
        (byte)0xA9, (byte)0x9B, (byte)0xC8, (byte)0x32,
        (byte)0x56, (byte)0x34, (byte)0xE3, (byte)0x03
    };

    // Iteration count
    int iterationCount = 19;

    try {

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

        ecipher = Cipher.getInstance(key.getAlgorithm());
        dcipher = Cipher.getInstance(key.getAlgorithm());

        // 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) {
        System.out.println("EXCEPTION: InvalidAlgorithmParameterException");
    } catch (InvalidKeySpecException e) {
        System.out.println("EXCEPTION: InvalidKeySpecException");
    } catch (NoSuchPaddingException e) {
        System.out.println("EXCEPTION: NoSuchPaddingException");
    } catch (NoSuchAlgorithmException e) {
        System.out.println("EXCEPTION: NoSuchAlgorithmException");
    } catch (InvalidKeyException e) {
        System.out.println("EXCEPTION: InvalidKeyException");
    }
}


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 sun.misc.BASE64Encoder().encode(enc);

    } catch (BadPaddingException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}



public String decrypt(String str) {

    try {

        // Decode base64 to get bytes
        byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);
        System.out.println( "[decrypt]BASE64Decoded????? " + dec );
        System.out.println( "[decrypt]Algo: " + dcipher.getAlgorithm() );
        System.out.println( "[decrypt]Block Size: " + dcipher.getBlockSize() );
        System.out.println( "[decrypt]Parameters: " + dcipher.getParameters().getEncoded() );

        // Decrypt
        byte[] utf8 = dcipher.doFinal(dec);

        // Decode using utf-8
        return new String(utf8, "UTF8");

    } catch (BadPaddingException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

}


Edit-Added Debugging Log

Encrypted: HS/uG4F/TZEN/lzX4xGvEQ==
[decrypt]BASE64Decoded????? [B@18df65f
[decrypt]Algo: PBEWithMD5AndDES
[decrypt]Block Size: 8
[decrypt]Parameters: [B@1139ac8

Better Logging Data

Encrypted: HS/uG4F/TZEN/lzX4xGvEQ==
[decrypt]BASE64Decoded????? [B@11b7a20
[decrypt]BASE64Decoded String??? 1D 2F EE 1B 81 7F 4D 91 0D FE 5C D7 E3 11 AF 11 
[decrypt]BASE64Decoded Length: 16
[decrypt]Algo: PBEWithMD5AndDES
[decrypt]Block Size: 8
[decrypt]Parameters: 30 0D 04 08 A9 9B C8 32 56 34 E3 03 02 01 13 
[decrypt]After decryption:68 71 53 69 64 5F 37 36 39 
Decrypted: hqSid_769

Added more logging after synchronizing function

Request data: hqSid_3443
[encrypt] String??? 68 71 53 69 64 5F 33 34 34 33
[encrypt] Encrypted??? C7 02 03 2D BD F9 A6 6A 93 C0 40 48 2E 5F 2B E5
[encrypt]Encrypted �-��j��@H._+�
[encrypt]Encrypted Length 16
[encrypt]Algo: PBEWithMD5AndDES
[encrypt]Block Size: 8
[encrypt]Parameters: [B@f5cbda

received

Encrypted: xwIDLb35pmqTwEBILl8r5Q==
[decrypt]BASE64Decoded????? [B@13cd5ba
[decrypt]BASE64Decoded String??? C7 02 03 2D BD F9 A6 6A 93 C0 40 48 2E 5F 2B E5
[decrypt]BASE64Decoded Length: 16
[decrypt]Algo: PBEWithMD5AndDES
[decrypt]Block Size: 8
[decrypt]dcipher.Parameters().getEncoded(): 30 0D 04 08 A9 9B C8 32 56 34 E3 03 02 01 13
javax.crypto.BadPaddingException: Given final block not properly padded...
YABADABADOU
  • 1,238
  • 1
  • 16
  • 38
Jeff
  • 23
  • 1
  • 5
  • Can you show us some code ? What encryption do you use? – Alex May 29 '12 at 06:18
  • look here. http://stackoverflow.com/questions/8049872/given-final-block-not-properly-padded – ditkin May 29 '12 at 06:21
  • Code added as requested. – Jeff May 29 '12 at 06:50
  • I'm rather new to cryptography and I'm still trying to understand the link posted by ditkin. What I'm still trying to get is why restarting my tomcat fix it? =/ – Jeff May 29 '12 at 07:10
  • @Jeff what is the debugging output you get when you run your code (both encrypt and decrypt)? – Christopher Schultz May 29 '12 at 19:00
  • @ChristopherSchultz I Added the debugging log for the decryption above... After the last log... it returns NULL, which I think is logical since an exception was thrown =/ Encryption doesn't have any logs, since it didnt fail... what do have in mind that I will log on the encryption side? – Jeff May 30 '12 at 02:53
  • Both your base64decoded and "parameters" values are byte arrays. Can you fix the code to expand those and write-out the byte values? It looks like @ditkin is suggesting that you simply have the wrong decryption key. Is that possible? – Christopher Schultz May 30 '12 at 14:39
  • @ChristopherSchultz updated logs above, thanks! :) P.s.: The newer log is the successful one.. as of the moment, I have not captured any exception logs, gonna have to do some waiting game agian :( – Jeff May 31 '12 at 06:35
  • This code is not thread-safe. Is that a possible problem, here? What does your driver code look like? Also, instrument the 'encrypt' operation and show that output. – Christopher Schultz May 31 '12 at 16:04
  • I made the function synchronized ( thread safe ) and ill see if this fixes anything but i doubt it since only one app is sending the encrypted data to the decrypter :/ – Jeff Jun 01 '12 at 04:53
  • little update.. so far no exceptions... could i have been wrong with the threading? =/ – Jeff Jun 02 '12 at 06:56
  • @ChristopherSchultz bad news.. didnt work.. still got the error..updated the logs above... – Jeff Jun 04 '12 at 08:32
  • also, im reading around to try BouncyCastle APIs.... hope that would help... – Jeff Jun 04 '12 at 09:03
  • Using BC probably won't change anything. But, if you re-write all your code you may fix the bug without knowing why. – Christopher Schultz Jun 04 '12 at 13:58

1 Answers1

2

This code is definitely not threadsafe, and it appears to be the problem. You will need to use a different Cipher object for each thread.

Christopher Schultz
  • 20,221
  • 9
  • 60
  • 77
  • Hmmm... not sure about the password since I stored the password/salt in our mysql database... ill try to log it if the password was retrieved properly.. – Jeff Jun 05 '12 at 01:29
  • 1
    FWIW, a constant salt isn't really a salt. You should use a random salt and store it with the hashed password. – Christopher Schultz Jun 05 '12 at 14:46
  • wow... so far so good.. whole day no exception... What happened before was that I placed the class above inside a Singleton so that I can reuse it over again.... I changed it so that every call it creates a new object of the class above... =/ – Jeff Jun 06 '12 at 06:47
  • Looks like my comment about threadsafety was probably the read problem: you can't share a Cipher instance across threads or nothing will work properly because all threads will use the same cipher objects and create chaos. I'll edit the answer to reflect that. – Christopher Schultz Jun 06 '12 at 18:52
  • I will do more testing but this made good progress ^_^ One question though, anywhere I can look into more about cryptography and best practices? – Jeff Jun 07 '12 at 07:11
  • That's a fairly open-ended question. Go to the library or a bookstore and browse the crypto section looking for things that appear to meet your needs. As for best coding practices: unless a class claims that it (or subclasses of it) are thread-safe, you certainly don't want to try to share them amongst threads without synchronizing access. Ciphers aren't that heavyweight anyway, so sharing one between threads doesn't really buy you anything -- it just makes things worse as you've seen. – Christopher Schultz Jun 07 '12 at 14:24