1

I need help with this error: Given final block not properly padded. As you can see from the title, I am working with AES.

Here is the code of line where is error:

 byte[] decrypted = cipher.doFinal(bytes);

Here is the full code:

public class AESCrypt {
private final Cipher cipher;
private final SecretKeySpec key;
private String encryptedText, decryptedText;

public AESCrypt(String password) throws Exception {
    // hash password with SHA-256 and crop the output to 128-bit for key
    MessageDigest digest = MessageDigest.getInstance("SHA-256");
    digest.update(password.getBytes("UTF-8"));
    byte[] keyBytes = new byte[16];
    System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);

    cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    key = new SecretKeySpec(keyBytes, "AES");
}

public String encrypt(String plainText) throws Exception {
    byte[] iv = new byte[cipher.getBlockSize()];
    new SecureRandom().nextBytes(iv);
    AlgorithmParameterSpec spec = new IvParameterSpec(iv);
    cipher.init(Cipher.ENCRYPT_MODE, key, spec);
    byte[] encrypted = cipher.doFinal(plainText.getBytes());
    encryptedText = asHex(encrypted);
    return encryptedText;
}

public String decrypt(String cryptedText) throws Exception {
    byte[] iv = new byte[cipher.getBlockSize()];
    AlgorithmParameterSpec spec = new IvParameterSpec(iv);
    cipher.init(Cipher.DECRYPT_MODE, key, spec);
    // decrypt the message
    byte[] bytes = cryptedText.getBytes("UTF-8");
    byte[] decrypted = cipher.doFinal(bytes);
    decryptedText = asHex(decrypted);
    System.out.println("Desifrovani tekst: " + decryptedText + "\n");

    return decryptedText;
}

public static String asHex(byte buf[]) {
    StringBuilder strbuf = new StringBuilder(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 static void main(String[] args) throws Exception {

    System.out.print("....AES....\n");

    String message = "MESSAGE";
    String password = "PASSWORD";

    System.out.println("MSG:" + message);

    AESCrypt aes = new AESCrypt(password);
    String encryptedText = aes.encrypt(message).toString();
    System.out.println("SIFROVANA PORUKA: " + encryptedText);
    String decryptedText = aes.decrypt(encryptedText).toString();       
    System.out.print("DESIFROVANA PORUKA: " + decryptedText);
}

}

Zookey
  • 2,637
  • 13
  • 46
  • 80
  • I would suggest that you use the apache commons-codec [Hex](http://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/binary/Hex.html) class instead of rolling your own Hex encoder and decoder – Peter Elliott Mar 25 '13 at 21:25
  • I have seen a lot of examples over the Internet, where people use BASE64Decoder and BASE64Encoder? But it seems that I cant use that. – Zookey Mar 25 '13 at 21:51
  • it's not really a best practice to use those because they are in the sun namespace, and may not necessarily be there in all implementations of the JDK. If you want Base64 encoding and decoding without a library, and you're supporting Java 6+, use JAXB as outlined in [this answer](http://stackoverflow.com/a/2054226/1904979) – Peter Elliott Mar 25 '13 at 21:54
  • If you can write answer with improved code, and I will accept your answer, because you really deserve it. – Zookey Mar 25 '13 at 21:57
  • I am close to solve this problem with JAXB. But, I get all the time wrong output for decrypted text. Here is the code: http://pastebin.com/pmrsNsd4 – Zookey Mar 26 '13 at 12:16
  • You shouldn't use SHA-256 to generate your key from a password, use [PBKDF2](http://en.wikipedia.org/wiki/PBKDF2). – jbtule Mar 26 '13 at 13:37
  • 1
    SHA-256 isn't designed for deriving keys, your password keyspace is likely not as big as 128bits and with just a hash probably crackable, that and there already exist large tables of precomputed hashes for sha-256 that could be used to find the password from a ciphertext even faster. – jbtule Mar 26 '13 at 13:55
  • Thank you for the good answer. So, this my implementation isn't that secure. – Zookey Mar 26 '13 at 14:00

2 Answers2

3

Per your comment, you are pretty close to getting the crypto working.

You need to move the IV generation code from your encryption/decryption methods to somewhere else, like so

public AlgorithmParameterSpec getIV() {
AlgorithmParameterSpec ivspec;
byte[] iv = new byte[cipher.getBlockSize()];
new SecureRandom().nextBytes(iv);
ivspec = new IvParameterSpec(iv);
}

then pass that ivspec into both the encrypt and decrypt methods (making them look like encrypt(String,AlgorithmParameterSpec)), so that you have the same iv for both encryption and decryption.

Also, don't call printBase64Binary on the decryptedByteArray, instead call new String(decryptedByteArray, "UTF-8")

Peter Elliott
  • 3,273
  • 16
  • 30
  • 2
    Once you initialize this class, it's IV is fixed. This construction violates both rules for IV's per key with CBC, that the IV can't repeat, and that the IV can't be predicable. Thus it is not semantically secure. – jbtule Mar 26 '13 at 13:47
  • right, a better construction would be to pass in IV with the encrypt or decrypt methods, or pass out the IV either appended one place or the other. This also has the problem that two separate runs of the program will have two separate IVs, which would cause decrypt corruption. I've edited the question to reflect a better way to do it – Peter Elliott Mar 26 '13 at 13:57
  • Ive tried to implement something similar with this improved code, but I get again same error about given final block not properly padded. Here is the code: http://pastebin.com/YPZzvNqk – Zookey Mar 26 '13 at 14:29
  • 1
    your code will generate two different IVs ... you need to call it outside of `encrypt` and `decrypt`, and pass the IVParameterSpec into the methods as arguments, so you can ensure the same values are used – Peter Elliott Mar 26 '13 at 14:34
  • Thanks, again! You have helped me a lot, I appreciate it. Btw just one more question to you. Which is best way to test how secure is this my program? I mean is it enough secure to use it in real program? – Zookey Mar 26 '13 at 16:15
0

You have two problems, first you encode the output into a hex string but don't decode back from it in the decode method. Second you generate an random IV but don't use it again to decode.

public byte[] encrypt(String plainText) throws Exception {
   byte[] iv = new byte[cipher.getBlockSize()];    
   AlgorithmParameterSpec spec = new IvParameterSpec(iv);
   cipher.init(Cipher.ENCRYPT_MODE, key, spec);
   return cipher.doFinal(plainText.getBytes());
}

public String decrypt(byte[] cryptedText) throws Exception {
   byte[] iv = new byte[cipher.getBlockSize()];
   AlgorithmParameterSpec spec = new IvParameterSpec(iv);
   cipher.init(Cipher.DECRYPT_MODE, key, spec);
   // decrypt the message
   byte[] decrypted = cipher.doFinal(cryptedText);
   decryptedText = new String(decrypted, "UTF-8");
   return decryptedText;
}



String decryptedText = aes.decrypt(aes.encrypt(message)).toString();     
Leonard Brünings
  • 12,408
  • 1
  • 46
  • 66
  • the first problem (not decoding hex output) is the cause of the error in the question, but the second issue (the IV problems) will cause garbled plaintext output on the first block of decrypted plaintext. – Peter Elliott Mar 25 '13 at 21:24
  • 1
    That said, this code in this answer has two problems: 1, it uses an all-zero string for the IV, which is bad from a security perspective.2, it doesn't specify a string encoding when calling `getBytes()`, which can cause problems when decrypting the text on the other end – Peter Elliott Mar 25 '13 at 21:29
  • And when use this code, it gives all the time same output for encrypted text. – Zookey Mar 25 '13 at 21:45
  • @Peter yes all null IV is bad from an security point of view, my intention was to show working code. Of course you need a unique iv in production but then you have to keep track of it for decryption too. – Leonard Brünings Mar 26 '13 at 17:43
  • +1 for pointing out the problem with trying to decrypt the hex String directly – Ebbe M. Pedersen Mar 28 '13 at 11:18