AES解密方法出错

我有解密的真正问题,不知道如何解决这个’java.crypto.BadPaddingException’。 我有一个类似的以前的系统工作得很好,现在我已经停止了上周。 我已经阅读了很多stackoverflow线程,但没有一个能真正解决我的问题…除非当然,我根本就不理解它。

我的问题出现在login方法中,它说: byte[] decrypted = cipher.doFinal(p.getBytes());

 public void register() { // ENCRYPT PASSWORD try { String key = username; // 128bit key (16*8) String text = password; // CREATE KEY AND CIPHER Key aesKey = new SecretKeySpec(key.getBytes(), "AES"); Cipher cipher = Cipher.getInstance("AES"); // ENCRYPT THE TEXT cipher.init(Cipher.ENCRYPT_MODE, aesKey); byte[] encrypted = cipher.doFinal(text.getBytes()); System.out.println("Encrypted: " + new String(encrypted)); // SET VARIABLE FOR SAVING p = new String(new String(encrypted)); System.out.println("p: " + new String(p)); System.out.println("p: " + password); } catch (Exception e){ e.printStackTrace(); } // ENCRYPT QUESTION try { String key = username; // 128bit key (16*8) String text = question; // CREATE KEY AND CIPHER Key aesKey = new SecretKeySpec(key.getBytes(), "AES"); Cipher cipher = Cipher.getInstance("AES"); // ENCRYPT THE TEXT cipher.init(Cipher.ENCRYPT_MODE, aesKey); byte[] encrypted = cipher.doFinal(text.getBytes()); System.out.println("Encrypted: " + new String(encrypted)); // SET VARIABLE FOR SAVING q = new String(new String(encrypted)); System.out.println("q: " + new String(q)); System.out.println("q: " + question); } catch (Exception e){ e.printStackTrace(); } // ENCRYPT ANSWER try { String key = username; // 128bit key (16*8) String text = answer; // CREATE KEY AND CIPHER Key aesKey = new SecretKeySpec(key.getBytes(), "AES"); Cipher cipher = Cipher.getInstance("AES"); // ENCRYPT THE TEXT cipher.init(Cipher.ENCRYPT_MODE, aesKey); byte[] encrypted = cipher.doFinal(text.getBytes()); System.out.println("Encrypted: " + new String(encrypted)); // SET VARIABLE FOR SAVING an = new String(new String(encrypted)); System.out.println("an: " + new String(an)); System.out.println("an: " + answer); } catch (Exception e){ e.printStackTrace(); } // SAVE DATA IN LICENSE FILE try { File file = new File("C://Welcome/License.txt"); file.getParentFile().mkdirs(); FileWriter fw = new FileWriter(file); BufferedWriter bw = new BufferedWriter(fw); //bw.write(new String(u)); //bw.newLine(); bw.write(new String(p)); bw.newLine(); bw.write(new String(q)); bw.newLine(); bw.write(new String(an)); bw.close(); } catch(FileNotFoundException ex){ ex.printStackTrace(); } catch(IOException ex){ ex.printStackTrace(); } // CREATE A FOLDER FOR FILES try { File dir = new File("C://IronFortress/Files"); dir.mkdir(); } catch(Exception e){ e.printStackTrace(); } } public void login() { // LOAD PASSWORD, QUESTION AND ANSWER HASHES String fileName = "C:/Welcome/License.txt"; String line0 = null; String line1 = null; String line2 = null; try { FileReader fr = new FileReader(fileName); BufferedReader br = new BufferedReader(fr); if((line0 = br.readLine()) != null){ p = (line0); } if((line1 = br.readLine()) != null){ q = (line1); } if((line2 = br.readLine()) != null){ an = (line2); } br.close(); } catch(FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } // DECRYPT STORED PASSWORD try { String key = username; // 128bit key (16*8) String text = p; // CREATE KEY AND CIPHER Key aesKey = new SecretKeySpec(key.getBytes(), "AES"); Cipher cipher = Cipher.getInstance("AES"); // DECRYPT THE TEXT cipher.init(Cipher.DECRYPT_MODE, aesKey); byte[] decrypted = cipher.doFinal(p.getBytes()); System.out.println("Decrypted Pass: " + new String(decrypted)); // COMPARE VALUES if (password.equals(new String(decrypted))){ //if (tf2.getText().equals(new String(decrypted))){ welcome.setVisible(true); bg.setVisible(false); l.setVisible(false); tf1.setVisible(false); tf2.setVisible(false); b3.setVisible(false); b4.setVisible(false); } } catch (Exception e){ e.printStackTrace(); } } 
 javax.crypto.BadPaddingException:给定最终块未正确填充
    在com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
    在com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
    在com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
    在javax.crypto.Cipher.doFinal(Cipher.java:2087)
    在IronFortress.intro.login(intro.java:327)
    在IronFortress.intro.actionPerformed(intro.java:482)
    在javax.swing.AbstractButton.fireActionPerformed(未知来源)
     at javax.swing.AbstractButton $ Handler.actionPerformed(Unknown Source)
    在javax.swing.DefaultButtonModel.fireActionPerformed(未知来源)
    在javax.swing.DefaultButtonModel.setPressed(未知来源)
    在javax.swing.plaf.basic.BasicButtonListener.mouseReleased(未知来源)
     at java.awt.Component.processMouseEvent(Unknown Source)
    在javax.swing.JComponent.processMouseEvent(未知来源)
    在java.awt.Component.processEvent(未知来源)
     at java.awt.Container.processEvent(Unknown Source)
     at java.awt.Component.dispatchEventImpl(Unknown Source)
     at java.awt.Container.dispatchEventImpl(Unknown Source)
     at java.awt.Component.dispatchEvent(Unknown Source)
     at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
     at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
     at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
     at java.awt.Container.dispatchEventImpl(Unknown Source)
     at java.awt.Window.dispatchEventImpl(Unknown Source)
     at java.awt.Component.dispatchEvent(Unknown Source)
     at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    在java.awt.EventQueue.access $ 200(未知来源)
    在java.awt.EventQueue $ 3.run(未知来源)
    在java.awt.EventQueue $ 3.run(未知来源)
     at java.security.AccessController.doPrivileged(Native Method)
     at java.security.ProtectionDomain $ 1.doIntersectionPrivilege(Unknown Source)
     at java.security.ProtectionDomain $ 1.doIntersectionPrivilege(Unknown Source)
    在java.awt.EventQueue $ 4.run(未知来源)
    在java.awt.EventQueue $ 4.run(未知来源)
     at java.security.AccessController.doPrivileged(Native Method)
     at java.security.ProtectionDomain $ 1.doIntersectionPrivilege(Unknown Source)
     at java.awt.EventQueue.dispatchEvent(Unknown Source)
     at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
     at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
     at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
     at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
     at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
     at java.awt.EventDispatchThread.run(Unknown Source)

主要问题是new String(encrypted) 。 密文由任意字节组成。 其中一些字节是不可打印的。 使用默认系统编码直接从这些字节创建字符串将默默地丢弃一些字节。 因此,您的密文将被破坏,明文无法恢复。

为了加密任意长度的明文,在加密之前(自动)应用填充。 解密运行时,它将尝试删除先前应用的填充。 如果以某种方式改变密文(取决于操作模式),则可以通过检查填充是否有效(它具有非常特定的格式)来检测该操作。 如果填充无效且无法删除,您将收到BadPaddingException。

如果要生成文本密文输出,则需要对密文进行正确编码,例如使用Base64或Hex。 然后你会在解密前解码它。


其他问题:

  • Cipher.getInstance("AES")不是完全限定的。 您需要使用完全限定的字符串来防止更改系统时出现意外情况。 例如Cipher.getInstance("AES/CBC/PKCS5Padding") 。 您当前的密码字符串可能默认为ECB模式…
  • 不要使用ECB模式! 使用随机IV的CBC模式。 IV不必是秘密的,因此您可以将其添加到密文中。
  • 始终指定您使用的编码: new String(bytes, "UTF-8")string.getBytes("UTF-8") 。 否则,您将无法在具有不同系统编码的另一个系统上解密您的密文。
  • new String(new String(encrypted)); 不会使它比new String(encrypted)更多的字符串。
  • 您无需将密文编码为Base64或Hex。 您可以继续使用byte[]并从FileWriter切换到FileOutputStream。