Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher?

Using tomcat, I have two web-applications i.e app1 and app2. I sent url from app1 in encrypted form (using below code) to app2 . Then at app2 I decrypted this encrypted url. But am getting below exception at line 50 of decryp method.

"Getting javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher"

Though for debugging when I try to decrypt(using same code) the encrypted url at app1, it works fine. But not able to figure out what causing this exception at app2?

Here is the code

import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

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

public class AESEncryptionDecryptionTest {

    private static final String ALGORITHM       = "AES";
    private static final String myEncryptionKey = "ThisIsFoundation";
    private static final String UNICODE_FORMAT  = "UTF8";

    public static String encrypt(String valueToEnc) throws Exception {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGORITHM);
        c.init(Cipher.ENCRYPT_MODE, key);  
        byte[] encValue = c.doFinal(valueToEnc.getBytes());
        String encryptedValue = new BASE64Encoder().encode(encValue);
        return encryptedValue;
    }

    public static String decrypt(String encryptedValue) throws Exception {
         Key key = generateKey();
         Cipher c = Cipher.getInstance(ALGORITHM);
         c.init(Cipher.DECRYPT_MODE, key);
         byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedValue);
         byte[] decValue = c.doFinal(decordedValue);//////////LINE 50
         String decryptedValue = new String(decValue);
         return decryptedValue;
    }

    private static Key generateKey() throws Exception {
         byte[] keyAsBytes;
         keyAsBytes = myEncryptionKey.getBytes(UNICODE_FORMAT);
         Key key = new SecretKeySpec(keyAsBytes, ALGORITHM);
         return key;
    }

    public static void main(String[] args) throws Exception {

         String value = "password1";
         String valueEnc = AESEncryptionDecryptionTest.encrypt(value);
         String valueDec = AESEncryptionDecryptionTest.decrypt(valueEnc);

         System.out.println("Plain Text : " + value);
         System.out.println("Encrypted : " + valueEnc);
         System.out.println("Decrypted : " + valueDec);
    }

}
like image 446
M Sach Avatar asked May 31 '12 15:05

M Sach


1 Answers

Works on my machine. Does it help if you use `UNICODE_FORMAT' in every instance where you transform bytes to Strings and vice versa? This line could be a problem:

byte[] encValue = c.doFinal(valueToEnc.getBytes()); 

should be

byte[] encValue = c.doFinal(valueToEnc.getBytes(UNICODE_FORMAT));

Anyway, if you use "AES" as the algorithm and you use the JCE, the algorithm actually being used will be "AES/ECB/PKCS5Padding". Unless you are 100% sure about what you are doing, ECB shouldn't be used for anything. I'd recommend to always specify the algorithm explicitly in order to avoid such confusion. "AES/CBC/PKCS5Padding" would be a good choice. But watch out, with any reasonable algorithm you will also have to provide and manage an IV.

Using an ECB cipher is even less desirable in the context of encrypting passwords, which is what you seem to be doing with your encryption if I interpret your example correctly. You should use password-based encryption as specified in PKCS#5 for that purpose, in Java this is provided for you in SecretKeyFactory. Be sure to use "PBKDF2WithHmacSHA1" with a high enough iteration count (anything ranging from ~ 5-20 000, depends on your target machine) for using passwords to derive symmetric keys from them.

The same technique can be used if it is actually password storage instead of password encryption what you are trying to achieve.

like image 71
emboss Avatar answered Sep 19 '22 17:09

emboss