2017-04-07 47 views
0

我想实现一个基本的Diffie-Hellman协议,并且代码成功达到需要使用DES解密发送值的时间点。我已经看了很多示例,其中的关键字不匹配,但我在连接的两端都打印了它们的值,它们都完全相同。我也尝试了多种填充方案以及更改密钥的生成方式。如何确保DES加密中的正确填充?

我最后一次尝试是将参数IvParameterSpec添加到密码初始化,但只解决了其中一个错误。

我在套接字通过本地主机连接的单台机器上运行此操作,并且我一直在检查任何发送的数据与接收的数据不完全匹配的问题,但在发送过程中没有任何更改。然而,我注意到,当打印每个字节数组在插座的任何一边时,客户端比看起来是填充(?)的服务器长得多(?)

我得到的错误是说最终块被错误地填充等解密失败

我的服务器代码(未如预期运行侧):

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(); 
    } 

} 

任何能够帮助我完成这项工作的东西都会受到极大的欢迎,因为我一直在单独研究这个错误很长一段时间。

+0

你能比“不按预期工作”更具体吗?什么是实际错误/意外结果? – slipperyseal

+0

调整了说明。这是一个badpaddingexception,说最后的块填充不正确 – KM529

+1

您正在客户端编写一个长度未知且长度可变的字节数组。在服务器端,你总是读128字节。这种不匹配可能是错误的根源。还有很明显的其他错误,例如客户端上的base64编码,但不在服务器端解码。 –

回答

0

我设法找出解决方法(虽然我怀疑它效率非常低)。这个问题是由于服务器端的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); 
      }