使用填充密码解密时,输入长度必须是 8 的倍数

Posted

技术标签:

【中文标题】使用填充密码解密时,输入长度必须是 8 的倍数【英文标题】:Input length must be multiple of 8 when decrypting with padded cipher 【发布时间】:2019-04-14 17:43:01 【问题描述】:

我有一个客户端/服务器应用程序,可以在客户端和服务器端加密或解密消息。但是在解密时,我不断从 StackTrace 收到以下错误

以下是来自 Server 和 Client 类的代码。 问题是我尝试使用 ("DES/CBC/PKCS5Padding")("UTF-8") 但仍然无法解决上述问题。 任何帮助将不胜感激谢谢?

public class ServerApp   

    public static byte[] encrypt(String input, Key k) 
        try 

            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.ENCRYPT_MODE, k);
            byte[] data = input.getBytes();
            byte[] result = cipher.doFinal(data);

            return result;
         catch (Exception ex) 
            return null;
        
    

    public static String decrypt(byte[] cipher, Key k) 
        try 

            Cipher cipher1 = Cipher.getInstance("DES");
            cipher1.init(Cipher.DECRYPT_MODE, k);
            byte[] original = cipher1.doFinal(cipher);
            return new String(original);

         catch (Exception ex) 
            return null;
            //Logger.getLogger(DES.class.getName()).log(Level.SEVERE, null, ex);
        
    

    public static void main(String[] args) throws NoSuchAlgorithmException 
        try 

              Key key=KeyGen.getSecretKey();
            ServerSocket ser = new ServerSocket(3333);
            System.out.println("Server Started");
            Socket client = ser.accept();
            DataInputStream in = new DataInputStream(client.getInputStream());
            DataOutputStream out = new DataOutputStream(client.getOutputStream());
            Scanner scan = new Scanner(System.in);
           // SecretSocket sc = new SecretSocket(client, KeyGen.getSecretKey());
            String serMsg, cliMsg, plain;
           // OutputStream sout = sc.getOutputStream();
          //  InputStream sin = sc.getInputStream();
            do 
                System.out.print("You say: ");
                serMsg = scan.nextLine();

             //   sout.write(serMsg.getBytes());
            //    System.out.println("cli server "+sin.read());

                byte[] ci = encrypt(serMsg, KeyGen.getSecretKey());
            System.out.println("encrypt " +ci.toString());
             out.writeUTF(ci.toString());
              plain = decrypt(ci, KeyGen.getSecretKey() );
              System.out.println("decrypt " + plain);
             while (!serMsg.equals("end"));
            client.close();
            ser.close();
         catch (IOException ex) 
            Logger.getLogger(ServerApp.class.getName()).log(Level.SEVERE, null, ex);
        
    


public class ClientApp  

        public static byte[] encrypt(String input, Key k) 
        try 

            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.ENCRYPT_MODE, k);
            byte[] data = input.getBytes();
            byte[] result = cipher.doFinal(data);

            return result;
         catch (Exception ex) 
            return null;
        
    

    public static String decrypt(byte[] cipher, Key k) 
        try 

            Cipher cipher1 = Cipher.getInstance("DES/CBC/PKCS5Padding");
            cipher1.init(Cipher.DECRYPT_MODE, k);
            byte[] original = cipher1.doFinal(cipher);
            return new String(original);

         catch (Exception ex) 
            return null;
            //Logger.getLogger(DES.class.getName()).log(Level.SEVERE, null, ex);
        
    

    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException 
        try 
            Socket s = new Socket("localhost", 3333);
            DataInputStream in = new DataInputStream(s.getInputStream());
            DataOutputStream out = new DataOutputStream(s.getOutputStream());
            Scanner scan = new Scanner(System.in);
            String serMsg, cliMsg, plain;

            do 

                System.out.println("server server "+in.readUTF());

                serMsg = in.readUTF();
                System.out.println("enc: " + serMsg);
                plain = decrypt(serMsg.getBytes("UTF-8"), KeyGen.getSecretKey());
                System.out.println("Server says: " + plain);

             while (!serMsg.equals("end"));
            s.close();
         catch (IOException ex) 
            Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE, null, ex);
        
    

【问题讨论】:

【参考方案1】:
        Cipher cipher = Cipher.getInstance("DES");
        cipher.init(Cipher.ENCRYPT_MODE, k);
        byte[] data = input.getBytes();
        byte[] result = cipher.doFinal(data);

    在没有 IV 的情况下使用 DES,您就是在隐式使用 DES/ECB/PKCS5Padding

    不要直接打印字节数组。 Java 将只输出可打印的字符。 打印时始终对字节数组进行编码和解码(Hex 或 Base64 是最常见的编码)

这是example project

Base64.getEncoder().encodeToString(byteArray) 
    我希望您知道 DES 目前被认为是一种弱密码,仅应用于向后兼容。

【讨论】:

嘿@RaghadMadwar 我还想提请您注意,上述答案中的解决方案仅在我进行加密时才对我有效。但是我在尝试解密时仍然遇到 BadPaddingException。然而,经过几次 DuckDuckGo 搜索后,我发现了用户 Naruto 的这个 *** 答案:- (***.com/questions/34121787/…),这似乎修复了引发的异常。 /*Encryption inside a try block of course*/ SecretKeySpec sks = new SecretKeySpec(key.getBytes(), "Blowfish"); Cipher cipher = Cipher.getInstance("Blowfish"); cipher.init(Cipher.ENCRYPT_MODE,sks); byte[] encrypted = cipher.doFinal(text.getBytes()); String encryptedText = new String(Base64.getEncoder().encodeToString(encrypted)); /*Decryption within a try block as well*/ SecretKeySpec sks = new SecretKeySpec(key.getBytes(),"Blowfish"); Cipher cipher = Cipher.getInstance("Blowfish"); cipher.init(Cipher.DECRYPT_MODE, sks); Base64.Decoder decoder = Base64.getDecoder(); byte[] decrypted = cipher.doFinal( Base64.getDecoder().decode(encryptedText)); String decryptedText = new String(decrypted);

以上是关于使用填充密码解密时,输入长度必须是 8 的倍数的主要内容,如果未能解决你的问题,请参考以下文章

AES 解密抛出 ValueError:输入字符串的长度必须是 16 的倍数

常用加密解密——非对称加密

密码输入字段长度 = 0 自动填充(android chrome)

JAVA使用DES加密解密

如何用Crypto++实现DES

什么是3DES对称加密算法?