0

I am getting the following error when trying to decrypted:

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

Here is the encryption class I have implemented:

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

public class StringEncrypter {

    public static String encrypt(String key, String string, String algorithm) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
        Key aesKey = new SecretKeySpec(key.getBytes("UTF-8"), algorithm);
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.ENCRYPT_MODE, aesKey);
        byte[] encrypted = cipher.doFinal(string.getBytes());
        return encrypted.toString();
    }

    public static String decrypt(String key, String encryptedString, String algorithm) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
        Key aesKey = new SecretKeySpec(key.getBytes("UTF-8"), algorithm);
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.DECRYPT_MODE, aesKey);
        String decrypted = new String(cipher.doFinal(encryptedString.getBytes()));
        return decrypted;
    }
}

This is how I encrypted a string:

StringEncrypter.encrypt("0306868080306868", "ddd", "AES"); // [B@e19957c

When I attempt to decrypt the above encrypted string like this:

String decrypted = StringEncrypter.decrypt("0306868080306868", "[B@e19957c", "AES");

I get the illegalBlockSizeException.

What am I doing wrong above? How do I correctly decrypt an encrypted String?

crmepham
  • 4,676
  • 19
  • 80
  • 155
  • Note that you seem to be using ECB encryption, which is not secure. You're at least missing a (random) IV in your code. – Maarten Bodewes Dec 20 '15 at 14:19
  • Possible duplicate of [Java: Syntax and meaning behind "\[B@1ef9157"? Binary/Address?](http://stackoverflow.com/questions/1040868/java-syntax-and-meaning-behind-b1ef9157-binary-address) – Artjom B. Dec 20 '15 at 15:22
  • @ArtjomB. It explains how the output is generated, but replacing it with `new String(byte[])` would e.g. not resolve the issue. – Maarten Bodewes Dec 20 '15 at 15:24
  • @MaartenBodewes You're right, but encoding it as hex would – Artjom B. Dec 20 '15 at 15:24
  • Yeah, preferred: just binary, for debugging and displaying of keys/IV's: hex, and for binary encoding of larger sized arrays: base64. Specialized bases for when the compression rate becomes a real issue. Java still hasn't hex, so then base 64 becomes the preferred format. – Maarten Bodewes Dec 20 '15 at 15:26

2 Answers2

2

You need to perform base 64 encoding decoding for your key and your ciphertext. There is a new Base64 class for this in Java 8. You cannot just store any byte in a string, not all bytes represent printable or even valid characters, and the output of a cipher is indistinguishable from random.

Besides that, the byte array "class" (represented by [B in Java) doesn't implement the toString method, which means you just get the print out of Object.toString, i.e. the class name [B and a human readable identifier to the object instance instead of the actual ciphertext.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • Why do I need to perform base 64 encoding and decoding? Also is there a 1.7 variant - I can't use Java 8 unfortunately. – crmepham Dec 20 '15 at 14:27
  • 1
    Bouncy castle and the Apache Commons Codec library sport Base64 classes. You need to perform the base64 encoding (and, indeed, decoding) because not every binary string can be represented by a text string without encoding. You can also just keep the ciphertext / key as byte array of course, if you don't actually need a text string representation. – Maarten Bodewes Dec 20 '15 at 14:29
  • "As outlined in the Oracle JDK Support Roadmap, after April 2015, Oracle will not post further updates of Java SE 7 to its public download sites. Customers who need continued access to critical bug fixes and security fixes as well as general maintenance for Java SE 7 or older versions can get long term support through Oracle Java SE Support." ... so you're creating a security related application in Java 7. Are you sure you know what you are doing? – Maarten Bodewes Dec 20 '15 at 14:32
  • More information about using strings [here](http://stackoverflow.com/a/8828196/589259) – Maarten Bodewes Dec 20 '15 at 15:20
  • [DatatypeConverter](http://docs.oracle.com/javase/7/docs/api/javax/xml/bind/DatatypeConverter.html) contains base64 encoding and decoding methods and has been available since at least Java 1.6 – President James K. Polk Dec 20 '15 at 18:35
  • @JamesKPolk I'm never that happy to link in unrelated packages or modules, but you are right of course, it *is* in the JRE. – Maarten Bodewes Dec 20 '15 at 21:26
0

You cannot use bytes (binary) as a String. it is not equivalent

You should convert it . Several manners. Base64 or Hexa, for example You with base64, it gives this:

import javax.xml.bind.DatatypeConverter ;

byte[] bt= ... // what you get

// Conversion B64
String encodedb64=DatatypeConverter.printBase64Binary(bt);

// CONVERSION base 64 => byte 
// base 64 => byte
byte [] byteArrayreverse=DatatypeConverter.parseBase64Binary(encodedb64);