AES解密方法出错

时间:2015-08-22 12:55:32

标签: java encryption encoding aes

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

我的问题出现在登录方法中,其中显示: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: Given final block not properly padded
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
    at javax.crypto.Cipher.doFinal(Cipher.java:2087)
    at IronFortress.intro.login(intro.java:327)
    at IronFortress.intro.actionPerformed(intro.java:482)
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
    at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
    at java.awt.Component.processMouseEvent(Unknown Source)
    at javax.swing.JComponent.processMouseEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    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)
    at java.awt.EventQueue.access$200(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    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)

1 个答案:

答案 0 :(得分:0)

主要问题是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。