javax.crypto.BadPaddingException

我正在研究AES算法,我有这个我无法解决的exception。

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*..) 

例外情况发生在解密部分。 我在与解密算法不同的地方初始化密钥

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

然后我把它从文件中读取的密文传递给下面的方法

  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 

编辑这里的加密方法。

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

这是asHex方法

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

这是我从文件中读取密文的地方

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

有人可以帮忙吗?

好吧,问题是您正在将加密的字节转换为hex字符串(使用asHex方法),但是没有正确地将hex字符串转换回字节数组以进行解密。 你不能使用getBytes

您可以使用以下方法将hex字符串转换为字节数组:

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

然后更改您的解密方法以使用:

 original = cipher.doFinal(fromHexString(message)); 

我确实有一个Bad Padding Exception并且无法在互联网上找到我的问题的解决方案。 自从我在一些艰苦的工作时间后发现它,我在这里给它。

我的问题是,我正在读取硬盘上的文件,并通过缓冲区加密,始终调用doFinal()方法而不是update()方法。 所以在解密时,我有填充错误

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

并且在解密时,使用相同的方法,但使用带有DECRYPT_MODE的Cipher init

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

编写代码后,我不再有任何BadPaddingException。

我可能确切地说,只有当原始清除文件长度(通过file.length()获得)大于缓冲区时才会出现此exception。 否则,我们不需要在while结构中多次传递,并且我们可以通过doFinal()调用在一次传递中加密。 这certificate了在您尝试加密的文件大小之后的exception的随机特性。

我希望你读得好!

我猜表达式message.trim().getBytes()不会返回加密消息时生成的相同字节。 特别是trim()方法可以删除在加密消息中添加为填充的字节。

validation加密期间返回的doFinal()方法数组和返回的message.trim().getBytes()数组:

  1. 得到相同的字节数(数组长度)
  2. 在数组中得到相同的字节
 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)); 

这是一个解决方案,我能够使用带有RSA加密的jks密钥库拼凑在一起

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