aes加密解密通过tcp.Input 长度必须是16的倍数,用padded cipher解密

aes encryption and decryption through tcp.Input length must be multiple of 16 when decrypting with padded cipher

我在 运行 程序

时看到这个 "Input length must be multiple of 16 when decrypting with padded cipher" 错误

RealEchoServer.java

import java.io.*;
import java.net.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class RealEchoServer {

public static void main(String[] args) {
    int i = 1;
    try {
        ServerSocket s = new ServerSocket(9003);

        for (;;) {
            Socket incoming = s.accept();
            System.out.println("Spawning " + i);
            new RealEchoHandler(incoming, i).start();
            i++;
        }
    } catch (Exception e) {
        System.out.println(e);
    }
 }
}

class RealEchoHandler extends Thread {

DataInputStream in;
DataOutputStream out;
private Socket incoming;
private int counter;

public RealEchoHandler(Socket i, int c) {
    incoming = i;
    counter = c;
}

public void run() {
    try {

        String key1 = "1234567812345678";
        byte[] key2 = key1.getBytes();
        SecretKeySpec secret = new SecretKeySpec(key2, "AES");
        String msg = "Singapore Malaysia Japan India Indonesia HongKong Taiwan China England";
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, secret);
        byte[] encrypted = cipher.doFinal(msg.getBytes());

        in = new DataInputStream(incoming.getInputStream());
        out = new DataOutputStream(incoming.getOutputStream());

        boolean done = false;
        String str = "";
        out.writeUTF("Connected!\n");
        out.flush();
        while (!done) {
            out.writeUTF(">");
            out.flush();
            str = in.readUTF();
            System.out.println(in + ":" + str);
            if (str == null) {
                done = true;
            } else {
                System.out.println("Sending Ciphertext : " + new String(encrypted));
                out.writeUTF(new String(encrypted));
                out.flush();
            }
        }
        incoming.close();
    } catch (Exception e) {
        System.out.println(e);
    }
 }
}

RealSocketTest.java

   import java.io.*;
   import java.net.*;
   import java.security.*;
   import javax.crypto.*;
   import javax.crypto.spec.*;
   import java.util.*;

 class RealSocketTest {
 public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {

    String str = "";
    String str2 = "";
    DataOutputStream out;
    DataInputStream in;

    try {
        Socket t = new Socket("127.0.0.1", 9003);
        in = new DataInputStream(t.getInputStream());
        out = new DataOutputStream(t.getOutputStream());
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        boolean more = true;
        System.out.println(in.readUTF());

        while (more) {
            str = in.readUTF();
            System.out.print(str);
            str2 = br.readLine();
            out.writeUTF(str2);
            out.flush();
            str = in.readUTF();

            System.out.println("Encrypted Info: " + str);

            try {

                String key1 = "1234567812345678";
                byte[] key2 = key1.getBytes();
                SecretKeySpec secret = new SecretKeySpec(key2, "AES");
                Cipher cipher = Cipher.getInstance("AES");
                cipher.init(Cipher.DECRYPT_MODE, secret);
                byte[] decrypted = cipher.doFinal(str.getBytes());
                System.out.println("Decrypted Info: " + new String(decrypted));
            } catch (BadPaddingException e) {
                System.out.println("Wrong Key!");
            } catch (InvalidKeyException f) {
                System.out.println("Invalid Key!");
            }
        }
    } catch (IOException e) {
        System.out.println("Error");
    }
  }
}

我在这里读到一个类似的问题Illegal Block Size Exception Input length must be multiple of 16 when decrypting with padded cipher,但我不明白如何改变我的,因为它看起来与我的很不一样。

那么 added/changed 应该怎样解密?

问题是密文可能包含所有可能的字节值。另一方面,许多字节值不可打印,因此不是有效的 UTF-8 编码。当你用它制作一个字符串时 new String(encrypted),它会悄悄地丢弃一些字节,你将无法成功解密密文。

两个可能的修复:

  • 将密文编码为 Base64 或 Hex,以用于基于文本的协议。
  • 使用DataOutputStream::write()方法使其成为不编码的二进制协议。

其他安全内容:

  • 始终为预期的密码实例指定完整的字符串。不同的提供者可能有不同的默认值,并且客户端和服务器可能不使用相同的方法。示例:AES/ECB/PKCS5Padding.

  • 切勿使用 ECB 模式。它在语义上不安全。至少使用带有随机 IV 的 CBC(在密文前面加上 IV 或按顺序将其写入流)。

  • 检查您的密文是否被操纵。通过使用像 GCM(AES/GCM/NoPaddingGCMParameters)这样的身份验证模式,这很容易做到。如果你不想要那样,那么至少尝试实现一个加密然后 MAC 方案,你 HMAC 密文(使用不同的密钥)并在解密之前检查它。