2016-04-01 14 views
1

Ich habe viel geforscht und kann keine Lösung für dieses Problem finden. Ich habe Stunden damit verbracht, und ich kann es nicht herausfinden, also hoffe ich, dass jemand hier, der erfahrener ist als ich, helfen kann. Dieses Programm ist vielleicht nicht die beste Praxis, aber es ist für eine Aufgabe.Empfangen von Diffie-Hellman-Schlüssel über Sockets Fehler

Ich sende öffentliche Schlüssel mit RSA, aber noch wichtiger, ich versuche Diffie Hellman Parameter von Bob (der Server) zu Alice (der Client) zu übertragen. Ich erhalte die folgende Fehlermeldung, wenn das Programm ausgeführt wird:

Exception in thread "main" java.security.spec.InvalidKeySpecException: Unangemessen Schlüsselspezifikation bei com.sun.crypto.provider.DHKeyFactory.engineGeneratePublic (DHKeyFactory .java: 85) bei java.security.KeyFactory.generatePublic (KeyFactory.java:334) um client.Client.main (Client.java:114) Erstellt von: java.security.InvalidKeyException: Fehler bei der Schlüsselcodierung bei com.sun.crypto.provider.DHPublicKey. (DHPublicKey.java:178) um ​​ com.sun.crypto.provider.DHKeyFactory.engineGeneratePublic (DHKeyFactory.java:78) ... 2 mehr verursacht von: java.io.IOException: DerInputStream.getLength(): lengthTag = 127, too big. um sun.security.util.DerInputStream.getLength (DerInputStream.java:561) bei sun.security.util.DerValue.init (DerValue.java:365) um sun.security.util.DerValue. (DerValue.java : 320 com.sun.crypto.provider.DHPublicKey at) (DHPublicKey.java:125) ... 3 weitere

Hier ist der Code:. Client.java:

package client; 
import java.io.*; 
import java.security.*; 
import javax.crypto.*; 
import java.util.*; 
import java.net.*; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import javax.crypto.spec.DHParameterSpec; 
import java.security.spec.*; 


class Client{ 
    private static PublicKey publicKey = null; 
    private static PrivateKey privateKey = null; 
    private static PublicKey rsaBobPub = null; 
    private static SecretKey SecretSharedKeyCipher = null; 
    private static SecretKey SecretSharedKeyIntgSend = null; 
    private static SecretKey SecretSharedKeyIntRecv = null; 
    private static KeyAgreement aKeyAgreement = null; 


    public static void main(String args[]) throws ClassNotFoundException, `IOException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidParameterSpecException, InvalidKeySpecException{` 
     Client client = new Client(); 
     KeyPairGenerator keyGen; 
     byte[] alicePub; 
     Cipher cipher2; 
     byte[] encryptedDH = null; 
     byte[] bobEncryptedDH = null; 
     OutputStream dh; 
     InputStream bobDHConn; 

      Socket connection = new Socket("localhost", 4129); 

      //Generate Keys & then send to Bob 
       keyGen = KeyPairGenerator.getInstance("RSA"); 
       keyGen.initialize(2048); 
       KeyPair keyPair = keyGen.genKeyPair(); 
       publicKey = keyPair.getPublic(); 
       privateKey = keyPair.getPrivate(); 

      //Send Public Key to Bob 
       ObjectOutputStream toBob = new ObjectOutputStream(connection.getOutputStream()); 
       toBob.writeObject(publicKey); 

      //Receive Bob's Public Key 
       ObjectInputStream fromBob; 
       fromBob = new ObjectInputStream(connection.getInputStream()); 
       rsaBobPub = (PublicKey) fromBob.readObject(); 

    //SET UP DIFFIE HELLMAN PROTOCOL 
    //For some reason, when receiving Bob's DH param, I am getting a lot of issues. 
      //Exchange DH info 
       DHParameterSpec paramSpec; 
       AlgorithmParameterGenerator paramGen = AlgorithmParameterGenerator.getInstance("DH"); 
       paramGen.init(512); 
       AlgorithmParameters parameters = paramGen.generateParameters(); 
       paramSpec = (DHParameterSpec) parameters.getParameterSpec(DHParameterSpec.class); 

      //Generate Key Pair 
       KeyPairGenerator aliceKpGen = KeyPairGenerator.getInstance("DH"); 
       aliceKpGen.initialize(paramSpec); 
       KeyPair aliceKp = aliceKpGen.generateKeyPair(); 
       aKeyAgreement = KeyAgreement.getInstance("DH"); 
       aKeyAgreement.init(aliceKp.getPrivate()); 
       alicePub = aliceKp.getPublic().getEncoded(); 
       //System.out.println(aliceKp.getPublic()) 
       //System.out.println(aliceKp.getPublic().getEncoded()) 
       //Send Alice's encrypted DH byte info to Bob 
       /*  cipher2 = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 
        cipher2.init(Cipher.ENCRYPT_MODE, rsaBobPub); 
        encryptedDH = cipher2.doFinal(alicePub); 
        System.out.print(encryptedDH); 
       */ 
        dh = connection.getOutputStream(); 
        dh.write(alicePub); 

      //Recieve Bob's DH Info 
       bobDHConn = connection.getInputStream(); 
       int length; 
       byte[] bobDH = null; 


       while((length = bobDHConn.available()) == 0){ 
        bobDH = new byte[length]; 
        int i = 0; 
        while(i < length){ 
         i+= bobDHConn.read(bobDH, i, length - i); 
        } 
       } 
      //NOT WORKING 
      KeyFactory clientKeyFac = KeyFactory.getInstance("DH"); 
      X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(bobDH); 
      PublicKey bobsDHPubKey = clientKeyFac.generatePublic(x509KeySpec); 
      aKeyAgreement.doPhase(bobsDHPubKey, true); 


     //Generate AES Secret Keys 
     SecretKey aesKeyGen = aKeyAgreement.generateSecret("AES"); 


    } 
} 

Server.java

package server; 
import java.io.*; 
import java.security.*; 
import javax.crypto.*; 
import java.util.*; 
import java.net.*; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.security.spec.InvalidKeySpecException; 
import java.security.spec.X509EncodedKeySpec; 
import javax.crypto.interfaces.DHPublicKey; 
import javax.crypto.spec.DHParameterSpec; 

public class Server{ 
    private static int port = 4129; 
    private static PublicKey publicKey = null; 
    private static PrivateKey privateKey = null; 
    private static PublicKey rsaAlicePub = null; 
    private static ServerSocket server = null; 
    private static SecretKey SecretSharedKeyCipher = null; 
    private static SecretKey SecretSharedKeyIntgSend = null; 
    private static SecretKey SecretSharedKeyIntRecv = null; 

    public static void main(String args[]) throws ClassNotFoundException, NoSuchAlgorithmException, IOException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException, InvalidAlgorithmParameterException{ 
     //Declarations 
      Server serv = new Server(); 
      server = new ServerSocket(4129); 
      server.setReuseAddress(true); 
      KeyPairGenerator keyGen; 
      byte[] cipherText = null; 
      InputStream input = null; 
      byte[] data = null; 
      byte[] decryptedDH; 
      InputStream DH = null; 
      byte[] DHinfo = null; 
      int length; 
      byte[] aliceEncryptedDH = null;  
      SecretKey keyGenDH= null; 
      InputStream aliceDH = null; 
      Cipher cipher; 
      PublicKey bobDHPub = null; 
      OutputStream sendDH; 

      //String message = "bbbbbbbbbbbbbb"; 
      String message = "bbbbbbb"; 
      Socket client = server.accept(); 

      //Get Public Key froM Alice 
       ObjectInputStream alicePK; 
       alicePK = new ObjectInputStream(client.getInputStream()); 
       rsaAlicePub = (PublicKey)alicePK.readObject(); 

      //Generate Bob's keys 
       keyGen = KeyPairGenerator.getInstance("RSA"); 
       keyGen.initialize(2048); 
       KeyPair keyPair = keyGen.genKeyPair(); 
       privateKey = keyPair.getPrivate(); 
       publicKey = keyPair.getPublic(); 

      //Send Bob's public Key to Alice 
       ObjectOutputStream bobPK; 
       bobPK = new ObjectOutputStream(client.getOutputStream()); 
       bobPK.writeObject(publicKey); 

      //Exchange information for DH 
      //Decrypt received information using Bob PK 
      //You can assume that Bob selects the public parameters of Diffie‐Hellman protocol, and send them to Alice 

      DH = client.getInputStream(); 
      while((length = DH.available()) == 0); 
      int i = 0; 
      DHinfo = new byte[length]; 
      while (i < length) { 
       i += DH.read(DHinfo, i, length - i); 
      } 
/* 
      cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 
      cipher.init(Cipher.DECRYPT_MODE, privateKey); 
      decryptedDH = cipher.doFinal(DHinfo); 
      */ 
      KeyFactory clientKeyFac = KeyFactory.getInstance("DH"); 
      X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(DHinfo); 
      bobDHPub = clientKeyFac.generatePublic(x509KeySpec); 

      DHParameterSpec dhParamSpec = ((DHPublicKey) bobDHPub).getParams(); 

      //Create Bob DH Keys 
       KeyPairGenerator bobKpGen = KeyPairGenerator.getInstance("DH"); 
       bobKpGen.initialize(dhParamSpec); 
       KeyPair bobsKeys = bobKpGen.generateKeyPair(); 

       KeyAgreement bobKeyAgreement = KeyAgreement.getInstance("DH"); 
       bobKeyAgreement.init(bobsKeys.getPrivate()); 
       bobKeyAgreement.doPhase(bobDHPub, true); 

      //Send Bob's DH Parameters to Alice 
      //send bobsKeys.getPublic().getEncoded() 
        sendDH = client.getOutputStream(); 
        sendDH.write(bobsKeys.getPublic().getEncoded()); 

      //Encrypt message.getBytes(); 

    } 

    private void Server() throws IOException{ 
     server = new ServerSocket(port); 


    } 



} 
+0

Does es funktioniert, wenn Sie Sockets aus der Gleichung nehmen? Mit anderen Worten, wenn Sie ein einzelnes Programm schreiben, das beide Sätze von DH Schlüsseln erzeugt und den Austausch in sich selbst durchführt, funktioniert es? – QuantumMechanic

Antwort

2

Ihre Art, von einem InputStream zu lesen, ist falsch. Erstens, Sie möchten nie die verfügbare Methode verwenden. Es gibt nicht zurück, was Sie denken, dass es zurückgibt, und was es zurückgibt, ist für Sie nicht nützlich.

Wenn Sie Bytearrays in einen OutputStream schreiben und die andere Seite das gleiche Bytearray rekonstruieren soll, müssen Sie der anderen Seite irgendwie mitteilen, wie lang das Bytearray ist. Am einfachsten ist es, die Länge mit einem Präfix zu versehen.

In Ihrem Fall haben Sie bereits einen ObjectOutputStream und ObjectInputStream um Ihre Roh-Ausgabe- und -Eingabe-Streams gewickelt. Benutze sie einfach. Byte-Arrays sind ebenfalls Objekte, Sie können also writeObject und readObject aufrufen, um sie zu übertragen.

Im Client:

toBob.writeObject(alicePub); 

Und in dem Server:

DHinfo = (byte[]) alicePK.readObject(); 

(Hinweis: Sie alicePk um so etwas wie fromAlice umbenennen sollten, wenn Sie es für mehrere Zwecke verwenden)