1

For all haters, I READ MANY topics like this one, and non of them was helpful.

eg. here javax.crypto.BadPaddingException: Given final block not properly padded error while decryption or here Given final block not properly padded

I want to encrypt and then decrypt Strings. Read many topics about "Given final block not properly padded" exception, but non of these solutions worked.

My Class:

package aes;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.swing.JOptionPane;
import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

public class EncryptionExample {

private static SecretKeySpec    key;
private static IvParameterSpec  ivSpec;
private static Cipher           cipher; 
private static byte[]           keyBytes;
private static byte[]           ivBytes;
private static int              enc_len;

public static void generateKey() throws Exception
        {
        
            String complex = new String ("9#82jdkeo!2DcASg");
            keyBytes = complex.getBytes();
            key = new SecretKeySpec(keyBytes, "AES");

            complex = new String("@o9kjbhylK8(kJh7"); //just some randoms, for now
            ivBytes = complex.getBytes();
            ivSpec = new IvParameterSpec(ivBytes);

            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        }
        
        public static String encrypt(String packet) throws Exception
        {
            byte[] packet2 = packet.getBytes();
            cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
            byte[] encrypted = new byte[cipher.getOutputSize(packet2.length)];
            enc_len = cipher.update(packet2, 0, packet2.length, encrypted, 0);
            enc_len += cipher.doFinal(encrypted, enc_len);
            
            return packet = new String(encrypted);
        }
        
        public static String decrypt(String packet) throws Exception
        {
            byte[] packet2 = packet.getBytes();
            cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
            byte[] decrypted = new byte[cipher.getOutputSize(enc_len)];
            int dec_len = cipher.update(packet2, 0, enc_len, decrypted, 0);
HERE EXCEPTION>>>>> dec_len += cipher.doFinal(decrypted, dec_len);  <<<<<<<<<
            
            return packet = new String(decrypted);
        }
        
        
        // and display the results
    public static void main (String[] args) throws Exception 
    {
        
          // get the text to encrypt
        generateKey();
        String inputText = JOptionPane.showInputDialog("Input your message: ");
        
        String encrypted = encrypt(inputText);
        String decrypted = decrypt(encrypted);            
                
        JOptionPane.showMessageDialog(JOptionPane.getRootFrame(),
                    "Encrypted:  " + new String(encrypted) + "\n"
                      +  "Decrypted: : " + new String(decrypted));
          .exit(0);
    }
}

The thing is, when I decrypt strings (about 4/10 of shots), I get that exception:

Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:479)
at javax.crypto.Cipher.doFinal(Cipher.java:2068)
at aes.EncryptionExample.deszyfrujBez(EncryptionExample.java:HERE tag)
at aes.EncryptionExample.main(EncryptionExample.java:Main starting)

Does anybody know what to change here (key? *.doFinal() method?) to make it work?

@ for those curious - methods have to be static, as this is a part of something bigger ;)

Community
  • 1
  • 1
pawpaw
  • 145
  • 1
  • 2
  • 11
  • You can check here http://stackoverflow.com/questions/20297621/javax-crypto-badpaddingexception-given-final-block-not-properly-padded-error-wh or http://stackoverflow.com/questions/8049872/given-final-block-not-properly-padded – sumitsabhnani Jun 05 '14 at 17:53
  • read that two links before. none of them has got solution for this, so why -1? I wrote, that I READ MANY TOPICS LIKE THIS – pawpaw Jun 05 '14 at 18:03
  • upvote just because I hate haters – Marian Klühspies May 02 '15 at 18:43

2 Answers2

4

When you use byte[] packet2 = packet.getBytes() you are converting the string based on the default encoding, which could be UTF-8, for example. That's fine. But then you convert the ciphertext back to a string like this: return packet = new String(encrypted) and this can get you into trouble if this does not round-trip to the same byte array later in decrypt() with another byte[] packet2 = packet.getBytes().

Try this instead: return packet = new String(encrypted, "ISO-8859-1"), and byte[] packet2 = packet.getBytes("ISO-8859-1") -- it's not what I would prefer, but it should round-trip the byte arrays.

Jim Flood
  • 8,144
  • 3
  • 36
  • 48
0

The result of encryption is binary data. In most cases it cannot be interpreted as a valid string encoding. So the call to new String(encrypted) will most likely distort the encrypted bytes and after doing packet.getBytes() you end up with a byte array with different content.

The decryption now fails because the cypher text has been changed. The padding bytes are not correctly recovered and cannot be removed.

To fix that, don't convert the cypher text to a string, keep the byte array.

Henry
  • 42,982
  • 7
  • 68
  • 84
  • I can not keep the byte array, that is the whole point ;( and also string keeps that padded bytes. when I want to print it it will print something like this "printed_text_[][][][][][][]" where [] is a padding byte (just a square in console) – pawpaw Jun 05 '14 at 19:18
  • If you have to convert the byte array to a string use an encoding that can restore the binary content like base64. – Henry Jun 05 '14 at 19:35
  • Unfortunately base 64 doesnt support  signs etc. and AES uses them :( I should search for such encoding;) – pawpaw Jun 05 '14 at 21:17
  • 1
    Base64 does support 'Â'. If you Base64 encode extended ASCII 0xC2 'Â' you get "w4I=". You would encrypt a byte array of plaintext to a byte array of ciphertext, then Base64 encode the ciphertext to carry it around. Decode the ciphertext to decrypt a byte array of ciphertext to a byte array of plaintext. – Jim Flood Jun 05 '14 at 23:51