views:

154

answers:

2

Hi, This is the code for encrypting and decrypting a string in java using AES algorithm. Its throwing illegalblocksize exception while decrypting. I know it is occuring because length of input string to the decryption method isn't matching with the padding. I don't have an idea of how to solve this. I am a new bie to the encryption decryption. Plz help me....

StackTrace:

    javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
    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 test.AES.AESdecryptalgo(AES.java:76)
    at test.AES.main(AES.java:95)

Code:

package test;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;

public class AES
{
  public byte[] encrypted;
  public byte[] original;

  public String originalString;
  Cipher cipher;
  SecretKeySpec skeySpec;
  IvParameterSpec spec;
  byte [] iv;
  /*public static String asHex (byte buf[])
  {
    StringBuffer strbuf = new StringBuffer(buf.length * 2);
    int i;
    for (i = 0; i < buf.length; i++) {
    if (((int) buf[i] & 0xff) < 0x10)
    strbuf.append("0");
    strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
  }
  return strbuf.toString();
}*/
  public AES()
  {
        try
        {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            kgen.init(128);
            SecretKey skey = kgen.generateKey();
            byte[] raw = skey.getEncoded();
            skeySpec = new SecretKeySpec(raw, "AES");
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

        }
        catch(Exception ex)
        {ex.printStackTrace();}
  }
public String AESencryptalgo(byte[] text)
{
    String newtext="";
    try
    {
        // byte[] raw = skey.getEncoded();
        //SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
            AlgorithmParameters param = cipher.getParameters();
            IvParameterSpec ivspec=param.getParameterSpec(IvParameterSpec.class);
            iv=ivspec.getIV();
            spec=new IvParameterSpec(iv);
        //AlgorithmParameters params = cipher.getParameters();
        //iv = params.getParameterSpec(IvParameterSpec.class).getIV();
        encrypted = cipher.doFinal(text);

    }
   catch(Exception e)
   {
       e.printStackTrace();
   }
   finally
   {
      newtext=new String(encrypted);
       //System.out.println("ENCRYPTED "+newtext);
       return newtext;
    }
}
public  String AESdecryptalgo(byte[] text)
{
    try
    {

        cipher.init(Cipher.DECRYPT_MODE, skeySpec,spec);
        original = cipher.doFinal(text);   //Exception occurs here
        originalString = new String(original);

    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
    finally
    {

        return originalString;
    }
}
public static void main(String[] args)
{
    AES a=new AES();
    String encrypt=a.AESencryptalgo("hello".getBytes());
    System.out.println(encrypt);
    String decrypt=a.AESdecryptalgo(encrypt.getBytes());
    System.out.println(decrypt);
}

}`

+1  A: 

You have to provide an initialization vector when using CBC mode.

When encrypting, let the provider choose the IV for you:

…
cipher.init(Cipher.ENCRYPT_MODE, key);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
…

Later, when decrypting, use the same IV to initialize the cipher:

…
IvParameterSpec spec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
…
erickson
I made this change...but then it is throwing null pointer exception atbyte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
sparkle
@user372066 - Please replace the code in your question with your current version.
erickson
i have replaced the code
sparkle
A: 

You must change AESencryptalgo to return byte[] rather than a String. This is where the trouble begins:

newtext = new String(encrypted);
// System.out.println("ENCRYPTED "+newtext);
return newtext;

After changing the return type of the method, you should make the following change:

//newtext = new String(encrypted);
// System.out.println("ENCRYPTED "+newtext);
//return newtext;
return encrypted;

The problem is that a String is a sequence of characters, whereas the encrypted text is a sequence of bytes (for a good summary of this difference, see The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)).

When you try to construct a String from a byte array, Java tries its best to convert those bytes into characters, using the system's default character set. Unfortunately, this mapping doesn't always work successfully (typically when the encrypted bytes fall outside the ASCII character set). You will only ever notice the problem when it comes time to decrypt your new String (which will fail to properly convert the sequence of characters back into the original sequence of bytes).

Adam Paynter