Karthik Sivam
Karthik Sivam

Reputation: 2565

javax.crypto.IllegalBlockSizeException: last block incomplete in decryption

I'm working on a android project in which I have to decrypt string from a file in PHP server, encryption was done using PHP.(AES 128 algorithm)

Encryption Code:

 function aes128Encrypt($key, $data) {
      $key = md5($key);
      return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, str_repeat("\0", 16));
    }

My code for getting string from URL:

String myUri = "http://www.example.com/lib2.php";
HttpClient httpClient = new DefaultHttpClient();
HttpGet get = new HttpGet(myUri);

HttpResponse response = httpClient.execute(get);

String bodyHtml = "";
String xmlFile = "";
bodyHtml = EntityUtils.toString(response.getEntity());
System.out.println(bodyHtml);
xmlFile = decrypt(bodyHtml);
System.out.println(xmlFile);

decrypt() method:

public static String decrypt(String encData) throws Exception
    {
        Key key = generateKey();

        Cipher c = Cipher.getInstance(algo + "/CBC/PKCS7Padding");

        //Cipher c = Cipher.getInstance(algo);

        IvParameterSpec ivSpec = new IvParameterSpec(ivbytes);

        c.init(Cipher.DECRYPT_MODE, key , ivSpec);

        //byte[] decValue = Base64.decode(encData , Base64.NO_PADDING);

        //byte[] decFin = Base64.decode(decValue, Base64.NO_PADDING);

        //byte[] decFinal = c.doFinal(decValue);

        byte[] decFinal = c.doFinal(encData.getBytes());

        String getAns = new String(decFinal, "UTF8");

        return getAns;
    }

In generateKey():

public static Key generateKey()
    {

        try {
            MessageDigest digest = java.security.MessageDigest
                    .getInstance("MD5");

            digest.update(myChar.getBytes());

            key1 = digest.digest();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }



        Key key = new SecretKeySpec(key1,algo);     
        return key;
    }
}

The Logcat shows below exception:

javax.crypto.IllegalBlockSizeException: last block incomplete in decryption

at the line c.doFinal()

The Codes I'v commented out are also the codes I'v used to check. What is wrong with this code?. Any help will be appreciated.

Upvotes: 1

Views: 10649

Answers (3)

user6525118
user6525118

Reputation: 1

I solved my problem by avoiding reuse of cipher. each time i init it again. just initing might be enough.

 try {
            SecretKeyFactory factory = SecretKeyFactory
                    .getInstance(SECRET_KEY_ALGORITHM);
            KeySpec spec = new PBEKeySpec(ps, salt, ITERATIONS, KEY_LENGTH);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKey secret = new SecretKeySpec(tmp.getEncoded(), ALGORITHM);

            // Build encryptor and get IV
            ecipher = Cipher.getInstance(TRANSFORMATION);
            ecipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(iv));

            // Build decryptor
            dcipher = Cipher.getInstance(TRANSFORMATION);
            dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
        } catch (Exception e) {
            e.printStackTrace();
        }

Upvotes: 0

Maarten Bodewes
Maarten Bodewes

Reputation: 93978

The problem probably is the way you treat the value from the PHP server as a Java String. The PHP mcrypt_encrypt function returns a binary string, where each byte can have any value. PHP mcrypt_encrypt does not use any character encoding. So using EntityUtils.toString() is already an error - and using String.getBytes() without specifying the encoding generally is as well.

You just need to use either getContent() or writeTo(OutputStream outstream) to get the the binary ciphertext. If you opt for the first option, you can wrap a CipherInputStream around it. Initialize it with the "AES/CBC/NoPadding" cipher and you can directly decrypt the plain text string. Beware that you may have to trim a certain number of 00 valued bytes from the result to get to the plaintext.

Upvotes: 1

Max Power
Max Power

Reputation: 178

Your chiper is expecting padding "/CBC/PKCS7Padding". This has nothing to do with encoding of messages (BASE64). Either change expected chipher on java side or encrypt with padding on php side.

Chipers are specified algorithm/mode/padding or algortihm, see http://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html for details.

Your are specifying a chiper with padding but actually do zero padding on php side,

excerpt from http://www.php.net/manual/de/function.mcrypt-encrypt.php:

# creates a cipher text compatible with AES (Rijndael block size = 128)
# to keep the text confidential 
# only suitable for encoded input that never ends with value 00h
# (because of default zero padding)
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,
                             $plaintext, MCRYPT_MODE_CBC, $iv);

Upvotes: 2

Related Questions