28

I am working on AES algorithm, and I have this exception which I couldn't solve.

javax.crypto.BadPaddingException: Given final block not properly padded
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*..)

the exception happens in the decryption part. I initialize the key in a different place from where the decryption algorithm is

KeyGenerator kgen = KeyGenerator.getInstance("AES");//key generation for AES
kgen.init(128); // 192 and 256 bits may not be available

then I pass it with the cipher text which I read from file to the following method

 public String decrypt(String message, SecretKey skey) {

    byte[] raw = skey.getEncoded();
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    // Instantiate the cipher
    Cipher cipher;

    byte[] original = null;
    try {
        cipher = Cipher.getInstance("AES");

        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        System.out.println("Original string: "
                + message);
        original = cipher.doFinal(message.trim().getBytes());  //here where I got the exception
        String originalString = new String(original);
       }
 //catches

EDIT here's the encryption method.

public String encrypt(String message, SecretKey skey) {
    byte[] raw = skey.getEncoded();
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");

    // Instantiate the cipher

    Cipher cipher;
    byte[] encrypted = null;
    try {
        cipher = Cipher.getInstance("AES");

        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);

        encrypted = cipher.doFinal(message.getBytes());
        System.out.println("raw is " + encrypted);

    } catches
    return asHex(encrypted);
}

and here's the asHex method

  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();
}

Here's where I read the cipher text form the file

static public String readFile(String filePath) {
    StringBuilder file = new StringBuilder();
    String line = null;
    try {
        FileReader reader = new FileReader(filePath);
        BufferedReader br = new BufferedReader(reader);
        if (br != null) {
            line = br.readLine();
            while (line != null) {
                file.append(line);
                //      System.out.println("line is " + line);
                line = br.readLine();

            }
        }
        br.close();
        reader.close();
    } catch (IOException ex) {
        Logger.getLogger(FileManagement.class.getName()).log(Level.SEVERE, null, ex);
    }
    System.out.println("line is " + file.toString());
    return String.valueOf(file);

}

can someone help?

Kyle Falconer
  • 8,302
  • 6
  • 48
  • 68
palAlaa
  • 9,500
  • 33
  • 107
  • 166
  • I don't have an explecit IV, I am not building AES form scratch. – palAlaa Jan 02 '11 at 23:26
  • It would help to see the encryption code as well and how you call the decrypt method. – dogbane Jan 02 '11 at 23:46
  • You might want to be more specific. Use "AES/ECB/PKCS5Padding" instead of just "AES" as an arg to Cipher.getInstance(). Also you might want to use "CBC" instead of "ECB" - look it up if you want to know why ;) – ed22 Mar 09 '18 at 07:32

5 Answers5

18

Ok, so the problem is that you are converting the encrypted bytes to a hex string (using the asHex method) but are not converting the hex string back to a byte array correctly for decryption. You can't use getBytes.

You can use the following method to convert a hex string to a byte array:

public static byte[] fromHexString(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                             + Character.digit(s.charAt(i+1), 16));
    }
    return data;
}

and then change your decrypt method to use:

original = cipher.doFinal(fromHexString(message));
Community
  • 1
  • 1
dogbane
  • 266,786
  • 75
  • 396
  • 414
  • @dogbane, I make as u mention and padd the reuturn value manully ,and the size of cipher msg is 128 but still have the same exception. – palAlaa Jan 03 '11 at 00:07
  • @Alaa I have updated my answer. I didn't know you were converting to hex. – dogbane Jan 03 '11 at 00:31
  • @dogbane,I did but the same error. I wonder if it has any related to read or write to files, since I store the cipher in a file then read it to decrypt , I am using BufferedReader to read the file and return the content in StringBilder. – palAlaa Jan 03 '11 at 00:42
  • @Alaa are you using the SAME secret key for both encryption and decryption? Are you sure you are not generating a different key? – dogbane Jan 03 '11 at 00:51
  • 1
    @dogbane, that's the point i was generating new key for encryption and decryption :S, Sooooooooooooooooooooooooooooooooooo many thanx for ur help :) – palAlaa Jan 03 '11 at 01:02
6

I did have a Bad Padding Exception and have not been able to find on the internet a solution to my problem. Since I found it after some hard-working hours, I give it here.

My problem was, I was reading a file on my hard drive, and encrypting it through a buffer, always calling the doFinal() method instead of update() method. So when decrypting it, I had padding errors

    input = new FileInputStream(file);
    output = new FileOutputStream(newFile);

    Cipher cipher = Cipher.getInstance("DES");
    cipher.init(Cipher.ENCRYPT_MODE, mySecretKey);

    byte[] buf = new byte[1024];

    count = input.read(buf);
    while (count >= 0) {
        output.write(cipher.update(buf, 0, count)); // HERE I WAS DOING doFinal() method
        count = input.read(buf);
    }
    output.write(cipher.doFinal()); // AND I DID NOT HAD THIS LINE BEFORE
    output.flush();

And when decrypting, with the same method, but with a Cipher init with DECRYPT_MODE

    input = new FileInputStream(file);
    output = new FileOutputStream(newFile);

    Cipher cipher = Cipher.getInstance("DES");
    cipher.init(Cipher.DECRYPT_MODE, mySecretKey);

    byte[] buf = new byte[1024];

    count = input.read(buf);

    while (count >= 0) {
        output.write(cipher.update(buf, 0, count)); // HERE I WAS DOING doFinal() method

        //AND HERE WAS THE BadPaddingExceotion -- the first pass in the while structure

        count = input.read(buf);
    }
    output.write(cipher.doFinal()); // AND I DID NOT HAD THIS LINE BEFORE
    output.flush();

With the code written, I no longer have any BadPaddingException.

I may precise that this exception only appears when the original clear file length (obtained through file.length()) is bigger than the buffer. Else, we do not need to pass several times in the while structure, and we can encrypt in one pass with a doFinal() call. That justify the random character of the exception following the size of the file you try to encrypt.

I hope you had a good reading!

Mav3656
  • 254
  • 3
  • 5
2

I guess the expression message.trim().getBytes() does not return the same bytes which are generated when you encrypted the message. Specially the trim() method could delete the bytes which were added as padding in the encrypted message.

Verify that both the returned array of the doFinal() method during the encryption and the returned array of message.trim().getBytes():

  1. got the same number of bytes (array length)
  2. got the same bytes in the array
Progman
  • 16,827
  • 6
  • 33
  • 48
  • The length if message.getBytes() is 128 but the exception happen in doFinal() method so I can't know the size of the return value . – palAlaa Jan 02 '11 at 23:23
  • @Alaa: I mean the returned byte array at the *encryption*, where you generated the encrypted message. That the length of `message.getBytes()` is 128 looks good, but you are using `message.trim().getBytes()`. So check the returned array of the *encryption* doFinal() call and the returned array of the expression `message.trim().getBytes()`, they must be the same. – Progman Jan 02 '11 at 23:26
  • why doesn't getBytes() have a charset parameter? – free_easy Jan 02 '11 at 23:32
  • both are the same size 128 and that sensible, since i pass the cipher value to be decrypted. – palAlaa Jan 02 '11 at 23:37
  • @free_easy, how can charset help me? – palAlaa Jan 02 '11 at 23:39
-1
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(512);
KeyPair rsaKeyPair = kpg.genKeyPair();
byte[] txt = "This is a secret message.".getBytes();
System.out.println("Original clear message: " + new String(txt));

// encrypt
Cipher cipher;
try
{
    cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.ENCRYPT_MODE, rsaKeyPair.getPublic());
    txt = cipher.doFinal(txt);
}
catch (Throwable e)
{
    e.printStackTrace();
    return;
}
System.out.println("Encrypted message: " + new String(txt));

// decrypt
try
{
    cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.DECRYPT_MODE, rsaKeyPair.getPrivate());
    txt = cipher.doFinal(txt);
}
catch (Throwable e)
{
    e.printStackTrace();
    return;
}
System.out.println("Decrypted message: " + new String(txt));
Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Jaya shree
  • 15
  • 2
-2

Here is a solution I was able to piece together using a jks keystore with RSA encryption

import javax.crypto.Cipher;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.cert.Certificate;

public class Main {

    public static void main(String[] args) {

        byte[] txt = "This is a secret message for your own eyes only".getBytes();
        byte[] encText;
        try{

            // Load the keystore
            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
            char[] password = "keystorePassword".toCharArray();
            java.io.FileInputStream fis = new java.io.FileInputStream("/path/to/keystore/myKeyStore.jks");
            ks.load(fis, password);
            fis.close();

            Key rsakey = ks.getKey("mykeyalias", password);
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

            // Encrypt
            Certificate cert = ks.getCertificate("mykeyalias");
            try
            {
                cipher.init(Cipher.ENCRYPT_MODE, cert.getPublicKey());
                encText = cipher.doFinal(txt);
                System.out.println(encText.toString());
            }
            catch (Throwable e)
            {
                e.printStackTrace();
                return;
            }

            // Decrypt
            cipher.init(Cipher.DECRYPT_MODE, rsakey);
            String decrypted = new String(cipher.doFinal(encText));
            System.out.println(decrypted);


        } catch (Exception e) {
            System.out.println("error" + e);
        }
}
Jon
  • 7,848
  • 1
  • 40
  • 41
  • 2
    What does this have to do with the question: "BadPaddingException" and "AES algorithm"? – zaph Jun 27 '16 at 20:53
  • This answer does not relate to the question asked. The question asks about the AES Algorithm. Your answer is on a totally different tangent. – George Aug 05 '19 at 15:01