开发者

javax.crypto.BadPaddingException

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开发者_如何学C();
    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?


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


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!


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


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


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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜