有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何确保DES加密中的填充正确?

我正在尝试实现一个基本的Diffie-Hellman协议,代码成功到需要使用DES解密发送的值为止。我看过很多例子,其中关键点不匹配,但我在连接的两端打印它们的值,它们都完全相同。我还尝试了多种填充方案,并更改了键的生成方式

我最后一次尝试是将参数IvParameterSpec添加到cipher init,但这只解决了其中一个错误

我在一台机器上运行这个程序,其中socket通过本地主机连接,我一直在检查发送数据与接收数据不完全匹配的任何一方是否存在任何问题,但发送过程中没有任何更改。然而,我确实注意到,当在socket的任一侧打印每个字节数组时,客户端比服务器端长得多,似乎是在填充(?)

我得到的错误是,最后一个块填充错误,因此解密失败

我的服务器代码(未按预期工作的一方):

public static void main(String[] args) {
    ServerSocket welcomeSocket = null;

    // Creates a connectable socket on port 6789
    try {
        welcomeSocket = new ServerSocket(6789);
    } catch (IOException e) {
        e.printStackTrace();
    }
    while(true){
        try{
            double k2, B, A;
            double n = 13;
            double g = 61;
            long y = 7;
            B = (Math.pow(g, y))%n;

            System.out.println("Accepting connections");
            // Accept an incoming connection on the socket server
            Socket connectionSocket = welcomeSocket.accept();
            // Creates a read and write stream for that client
            DataInputStream inFromClient = new DataInputStream(connectionSocket.getInputStream());
            DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());

            // Sends the double to the client
            outToClient.writeDouble(B);
            System.out.println("Sent " + B);
            // Reads the number sent by the Client
            A = inFromClient.readDouble();
            System.out.println("Received " + A);

            // Modifies the number
            k2 = (Math.pow(A, y))%n;
            System.out.println("DES key seed = " + k2);
            byte[] deskeydata = toByteArray(k2);

            // Turns the bytes of the modified number into a DES key spec
            DESKeySpec deskeyspec = new DESKeySpec(deskeydata);

            // Makes a secret key (DES)
            SecretKeyFactory keyF = SecretKeyFactory.getInstance("DES");
            SecretKey keystuff = keyF.generateSecret(deskeyspec);
            System.out.println(keystuff.toString());

            // Gets an incoming string from the client and turns it into binary
            byte[] incomingBytes = new byte[128];
            try{
                inFromClient.readFully(incomingBytes);
            } catch(EOFException eof){
                System.out.println("Finished reading");
            }
            System.out.println(new String(incomingBytes));
            Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");

            // Decrypts the string using the shared secret key
            c.init(Cipher.DECRYPT_MODE, keystuff, new IvParameterSpec(new byte[8]));
            byte[] ct2 = c.doFinal(incomingBytes);

            // Decode it from base 64
            //byte[] decodedBytes = Base64.getDecoder().decode(ct2);

            // Prints the received string
            System.out.println("Received: " + new String(ct2));

            inFromClient.close();
            outToClient.close();

        } catch(Exception e){
            e.printStackTrace();
        }
    }
}

我的客户代码:

public static void main(String[] args) {

    // Creates a socket to the local host on port 6789
    Socket clientSocket = null;
    try {
        clientSocket = new Socket("localhost", 6789);
    } catch (IOException e1) {
        e1.printStackTrace();
    }
    try{
        double k1, B, A;
        double n = 13;
        double g = 61;
        long x = 3;

        // Sends an unencrypted number to the server
        A = (Math.pow(g, x))%n;
        DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
        DataInputStream inFromServer = new DataInputStream(clientSocket.getInputStream());  

        // Transforms A into a byte array and sends it over
        outToServer.writeDouble(A);
        outToServer.flush();
        System.out.println("Sending " + A);

        // Reads the incoming data from the server
        B = inFromServer.readDouble();
        System.out.println("Recieved " + B);

        // Modifies the data to create the number for des key
        k1 = (Math.pow(B, x))%n;
        System.out.println("DES key seed = " + k1);
        byte[] deskeydata = toByteArray(k1);

        // Turns the bytes of the modified number into a DES key spec
        DESKeySpec deskeyspec = new DESKeySpec(deskeydata);

        // Makes a secret key (DES)
        SecretKeyFactory keyF = SecretKeyFactory.getInstance("DES");
        SecretKey keystuff = keyF.generateSecret(deskeyspec);
        System.out.println(keystuff.toString());

        // Takes in input from the user and turns it into binary
        BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("Enter a message:");

        String sentence = inFromUser.readLine();
        byte[] str2 = sentence.getBytes();
        byte[] encodedMessage = Base64.getEncoder().encode(str2);

        Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");

        // Encrypts the user's input with the secret key
        c.init(Cipher.ENCRYPT_MODE, keystuff, new IvParameterSpec(new byte[8]));
        byte[] ct2 = c.doFinal(encodedMessage);
        System.out.println("Initted the cipher and moving forward with " + new String(ct2));

        // Writes the encrypted message to the user
        outToServer.write(ct2);
        outToServer.flush();


        inFromServer.close();
        outToServer.close();
    } catch(Exception e){
        e.printStackTrace();
    }

}

任何能帮助我解决这个问题的方法都是非常受欢迎的,因为我已经独自处理这个错误很长一段时间了


共 (1) 个答案

  1. # 1 楼答案

    我设法找到了解决这个问题的方法(尽管我怀疑它效率很低)。问题是由于服务器端的readFully方法。我正在将答案读入一个128字节的数组,解密函数将字节数组中的空插槽视为某种东西,而不是什么都没有

    为了解决这个问题,我将输入部分替换为以下内容:读取每个字节,并创建一个字节数组,其中包含传入消息的确切长度

                ArrayList<Byte> totalBytes = new ArrayList<Byte>();
                while(true){
                    try{
                        byte in = inFromClient.readByte();
                        totalBytes.add(in);
                    } catch(EOFException eof){
                        System.out.println("Finished reading");
                        break;
                    }
                }
                int incomingSize = totalBytes.size();
                byte[] receivedBytes = new byte[incomingSize];
                for(int i = 0; i < incomingSize; i++){
                    receivedBytes[i] = totalBytes.get(i);
                }