ObjectInputStream 在 readObject() 期间永远阻塞

ObjectInputStream blocks forever during readObject()

我正在尝试处理与自制服务器和客户端的安全连接。 首先,客户端连接到服务器并向每个 ObjectOutputStream 发送一个 PublicKey 对象到服务器。 服务器使用加密的 AES 密钥进行应答,然后双方都建立一个 AES 加密的输入和输出流。

但是客户端在接收AES密钥的过程中一直阻塞

那是我的客户端代码:

private void createServerConnection(String serverAddress) throws IOException {
    connection = new Socket(serverAddress, 5555);
    InputStream is = connection.getInputStream();
    OutputStream os = connection.getOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(os);
    ObjectInputStream ois = new ObjectInputStream(is);
    try {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        KeyPair kp = kpg.genKeyPair();
        oos.writeObject(kp.getPublic());
        Cipher ci = Cipher.getInstance("RSA");
        ci.init(Cipher.DECRYPT_MODE, kp.getPrivate());
        byte[] aesKey = (byte[]) ois.readObject();
        aesKey = ci.doFinal(aesKey);
        SecretKey originalKey = new SecretKeySpec(aesKey, 0, aesKey.length, "AES");

        Cipher aesCipherD = Cipher.getInstance("AES");
        aesCipherD.init(Cipher.DECRYPT_MODE, originalKey);

        Cipher aesCipherE = Cipher.getInstance("AES");
        aesCipherE.init(Cipher.ENCRYPT_MODE, originalKey);

        this.oos = new ObjectOutputStream(new CipherOutputStream(os, aesCipherE));
        this.ois = new ObjectInputStream(new CipherInputStream(is, aesCipherD));

    } catch(NoSuchAlgorithmException nsae) {

    } catch(ClassNotFoundException cnfe) {

    } catch(NoSuchPaddingException nspe) {

    } catch(InvalidKeyException ike) {

    } catch(IllegalBlockSizeException ibse) {

    } catch(BadPaddingException bpe) {

    }
}

那是我的服务器:

   public void run() {
    try {
        //Verbindung Aufbauen
        Socket s = server.accept();
        System.out.println("Eingehede Verbindung von " + s.getInetAddress().toString());
        new JSecSocket(server).start();
        OutputStream os = s.getOutputStream();
        InputStream is = s.getInputStream();
        ObjectOutputStream oos = new ObjectOutputStream(os);
        ObjectInputStream ois = new ObjectInputStream(is);
        System.out.println("Verbindung aufgebaut!");

        //PublicKey vom Client entgegennehmen
        System.out.println("Öffentlicher Schlüssel wird empfangen.");
        PublicKey clientPublicKey = (PublicKey) ois.readObject();

        //AES Key verschlüsseln und zum Client übertragen
        System.out.println("AES Schlüssel wird gesendet.");
        Cipher keyCipher = Cipher.getInstance("RSA");
        keyCipher.init(Cipher.ENCRYPT_MODE, clientPublicKey);
        byte[] encryptetKey = keyCipher.doFinal(this.aesSk.getEncoded());
        oos.write(encryptetKey);

        System.out.println("Verschlüsselte Verbindung wird aufgebaut!");
        Cipher encryptCipher = Cipher.getInstance("AES");
        encryptCipher.init(Cipher.ENCRYPT_MODE, aesSk);

        Cipher decryptCipher = Cipher.getInstance("AES");
        decryptCipher.init(Cipher.DECRYPT_MODE, aesSk);

        //Verschlüsselte Datenströme werden geöffnet
        oos = new ObjectOutputStream(new CipherOutputStream(os, encryptCipher));
        ois = new ObjectInputStream(new CipherInputStream(is, decryptCipher));
        System.out.println("Verbindung bereit!");
        while (!this.isInterrupted()) {
            NetworkStatus ns = (NetworkStatus) ois.readObject();
            JSecDatabase database = new JSecDatabase("localhost", "root", "", "database");
            switch (ns.getAction()) {
                case "lookup":
                    System.out.println("Lookup von" + s.getInetAddress().toString());
                    String target = (String) ns.getValue();
                    try {
                        oos.writeObject(new NetworkStatus("lookupOk", database.lookup(target)));
                    } catch (Exception e) {
                        oos.writeObject(new NetworkStatus("lookupError", e));
                    }
                    break;
                case "create":
                    System.out.println("User wird erstellt von " + s.getInetAddress().toString());
                    oos.writeObject(new NetworkStatus("createOk", database.create()));
                    break;
                case "update":
                    System.out.println("User wird geupdated von" + s.getInetAddress().toString());
                    String[] updateTarget = (String[]) ns.getValue();
                    if (database.update(updateTarget[0], updateTarget[1], s.getInetAddress().toString())) {
                        oos.writeObject(new NetworkStatus("updateOk", s.getInetAddress().toString()));
                    } else {
                        oos.writeObject(new NetworkStatus("updateError", null));
                    }
                    break;
                case "delete":

                    break;
                default:
                case "close":
                    System.out.println("Verbindung zu " + s.getInetAddress().toString() + " wird getrennt!");
                    oos.close();
                    ois.close();
                    os.close();
                    is.close();
            }
        }

    } catch (IOException ioe) {
        System.err.println("Es gab einen IO Error.\n" + ioe.getMessage());
    } catch (ClassNotFoundException cnfe) {
        System.err.println(cnfe.getMessage());
    } catch (NoSuchAlgorithmException nsae) {
        System.err.println(nsae.getMessage());
    } catch (NoSuchPaddingException nspe) {
        System.err.println(nspe.getMessage());
    } catch (InvalidKeyException ike) {
        System.err.println(ike.getMessage());
    } catch (IllegalBlockSizeException ibse) {
        System.err.println(ibse.getMessage());
    } catch (BadPaddingException bpe) {
        System.err.println(bpe.getMessage());
    }
    sockets.remove(this);
}}

我认为更多的是对象流的问题,每次我尝试在套接字上使用对象流时都会遇到类似的问题。 有人知道发生了什么事吗?

一般情况下,您不能在同一个套接字上使用多个流。在某些特定情况下它可以工作,但一般来说你会遇到未知的缓冲,这会让你的同伴很快失去同步。在每一端重做一个 ObjectOutputStreamObjectInputStream。如果您只需要加密流的某些部分,请查看 SealedObject.