2016-04-01 6 views
1

Я занимаюсь многими исследованиями и не могу найти решение этой проблемы. Я провел несколько часов, и я не могу понять это, поэтому я надеюсь, что кто-то здесь, кто более опытен, чем я, может помочь. Эта программа может быть не лучшей практикой, но она предназначена для задания.Получение Diffie-Hellman Key Over Sockets Error

Я передаю открытые ключи, используя RSA, но что более важно, я пытаюсь передать параметры Диффи Хелмана от Боба (сервера) Алисе (клиенту). Я получаю следующее сообщение об ошибке при запуске программы:

Исключения в потоке «главный» java.security.spec.InvalidKeySpecException: недопустимого ключ спецификации на com.sun.crypto.provider.DHKeyFactory.engineGeneratePublic (DHKeyFactory .java: 85) at java.security.KeyFactory.generatePublic (KeyFactory.java:334) at client.Client.main (Client.java:114) Вызвано: java.security.InvalidKeyException: ошибка синтаксического анализа ключа в com.sun.crypto.provider.DHPublicKey. (DHPublicKey.java:178) по адресу com.sun.crypto.provider.DHKeyFactory.engineGeneratePublic (DHKeyFactory.java:78) ... 2 more Причиняется: java.io.IOException: DerInputStream.getLength(): lengthTag = 127, слишком большой. на sun.security.util.DerInputStream.getLength (DerInputStream.java:561) at sun.security.util.DerValue.init (DerValue.java:365) в sun.security.util.DerValue. (DerValue.java : 320) на com.sun.crypto.provider.DHPublicKey (DHPublicKey.java:125) ... 3 подробнее

Вот код:. 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 он работает, если вы берете сокеты из уравнения? Другими словами, если вы пишете одну программу, которая генерирует оба набора ключей DH и выполняет обмен все внутри себя, работает ли она? – QuantumMechanic

ответ

2

Ваш способ чтения из InputStream ошибочен. Во-первых, вы никогда не захотите использовать метод . Он не возвращает то, что, по вашему мнению, возвращает, и то, что оно возвращает, не полезно для вас.

Когда вы пишете массивы байтов в OutputStream и хотите, чтобы другая сторона восстановила один и тот же массив байтов, вам нужно каким-то образом указать другой стороне, как долго будет массив байтов. Самый простой способ - префикс его длины.

В вашем случае у вас уже есть ObjectOutputStream и ObjectInputStream, которые обернуты вашими исходными и входными потоками. Просто используйте их. Байт-массивы также являются объектами, поэтому вы можете позвонить writeObject и readObject, чтобы перенести их.

В клиенте:

toBob.writeObject(alicePub); 

И на сервере:

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

(Примечание: вы должны переименовать alicePk к чему-то вроде fromAlice, если вы используете его для различных целей)