“javax.crypto.BadPaddingException: Data must start

2019-01-25 01:12发布

I encountered the abovementioned exception while I was decrypting a string.

Below is my code:

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;

public class EncryptAndDecrypt {

    public static Cipher createCipher () throws Exception{

            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

            return cipher;
    }
    public static KeyPair generateKey () throws  NoSuchAlgorithmException{

            KeyPairGenerator keyGen = KeyPairGenerator.getInstance ("RSA");
            keyGen.initialize(1024);
            KeyPair key = keyGen.generateKeyPair();

            return key;
    }
    public static byte [] encrypt (String  str, Cipher cip, KeyPair key) {

        byte [] cipherText = null;
        try {

            byte [] plainText = str.getBytes("UTF8");
            cip.init(Cipher.ENCRYPT_MODE, key.getPublic());
            cipherText = cip.doFinal(plainText);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cipherText;
    }
    public static String decrypt (byte [] c, Cipher cip, KeyPair key) throws Exception {

        cip.init(Cipher.DECRYPT_MODE, key.getPrivate());

        byte [] decryptedPlainText = cip.doFinal (c);// exception occurred here
        String decryptedPlainStr = new String (decryptedPlainText);

        return decryptedPlainStr;
    }
}


//separate class below to use the encrypt method

public class EncryptionApp {

    public static void main (String [] args) {

        getEncrypted();
    }
    public static byte [] getEncrypted () {

        byte [] encyptedByte = null;
        try {
            String plainText = "der";
            Cipher cip = Safety.createCipher();
            KeyPair key = Safety.generateKey();
            encyptedByte = Safety.useRSA(plainText, cip, key);
        }
        catch (Exception e) {
            e.printStackTrace();
        }

         return encyptedByte;
    }
}

// Another class to use the decrypt method 

public class DecryptionApp {

    public static void main(String[] args) {
        System.out.println (useDecrypted () );
    }
    public static byte[] useDecrypted () {

        byte [] decryptedText = null;
        try {
            Cipher cip = EncryptAndDecrypt.createCipher();
            KeyPair key = EncryptAndDecrypt.generateKey();
            decryptedText = EncryptAndDecrypt.decrypt(EncryptionApp.getEncrypted(),cip,key);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    return decryptedText;
    }
}

标签: java rsa
4条回答
聊天终结者
2楼-- · 2019-01-25 01:38

I was getting this error and it turned out in my case to be that the base 64 string I was sending as a parameter contained some characters that were being altered because of being in a URL. The solution turned out to be URL encoding the parameter.

查看更多
爱情/是我丢掉的垃圾
3楼-- · 2019-01-25 01:40

Have you googled? A lot of people have this problem when the key to encrypt is not the same as the key to decrypt. It seems like you generate new keys all the time instead of using the same key to decrypt that you used for encryption.

查看更多
混吃等死
4楼-- · 2019-01-25 01:50

You already asked the same question in "javax.crypto.BadPaddingException: Data must start with zero" exception, and I gave you an answer: you're using two different keypairs : one to encrypt, and another one to decrypt. That can't work. I even gave you a code sample showing that everything ran fine if you used the same keypair.

KeyPairGenerator.generateKeyPair() generates a keypair. Calling this method twice will get you two different keypairs: it uses a random number generator internally to generate always different keypairs.

You must generate a keypair once, store it in a variable, and use this variable to encrypt and decrypt.

You should read the documentation of the classes and methods you are using. The documentation of generateKeyPair says:

This will generate a new key pair every time it is called.

查看更多
聊天终结者
5楼-- · 2019-01-25 01:50

Add this main method to EncryptAndDecrypt, and execute it. You'll see that evrything works fine.

public static void main(String[] args) throws Exception {
    String s = "hello";
    Cipher cipher = createCipher();
    KeyPair keyPair = generateKey();
    byte[] b = encrypt(s, cipher, keyPair);
    String s2 = decrypt(b, cipher, keyPair);
    System.out.println(s2);
}

The problem lies in the way you're using this class. The useDecrypted method does the following:

Cipher cip = EncryptAndDecrypt.createCipher(); // create a Cipher object using EncryptAndDecrypt
KeyPair key = EncryptAndDecrypt.generateKey(); // generate a KeyPair using EncryptAndDecrypt

// call EncryptionApp.getEncrypted() to get an encrypted text, then decrypt this encrypted text
// using the keypair created above.
decryptedVote = EncryptAndDecrypt.decrypt(EncryptionApp.getEncrypted(), cip, key);

And the getEncrypted method does the following:

String plainText = "der"; // create some plain text
// create a Cipher instance. Is it the same algorithm as the one in useDecrypted?
// we don't know, because it uses another, unknown, Safety class
Cipher cip = Safety.createCipher(); 
// create a new KeyPair instance. Is it the same KeyPair as the one in useDecrypted?
// No : another keypair is generated. There is no way something encrypted using a keypair
// will decrypt correctly with another keypair.
KeyPair key = Safety.generateKey();
encyptedByte = Safety.useRSA(plainText, cip, key);

So, in short, you use two different keypairs : one to encrypt and the other to decrypt. That can't work.

Also, note that in encrypt, you transform your string into a byte array using the UTF8 encoding, whereas in decrypt, you transform the byte array into a String using the default platform encoding. You should use UTF8 for both, and thus use the following code in decrypt :

String decryptedPlainStr = new String (decryptedPlainText, "UTF8");
查看更多
登录 后发表回答