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);
}}
我认为更多的是对象流的问题,每次我尝试在套接字上使用对象流时都会遇到类似的问题。
有人知道发生了什么事吗?
一般情况下,您不能在同一个套接字上使用多个流。在某些特定情况下它可以工作,但一般来说你会遇到未知的缓冲,这会让你的同伴很快失去同步。在每一端重做一个 ObjectOutputStream
和 ObjectInputStream
。如果您只需要加密流的某些部分,请查看 SealedObject
.
我正在尝试处理与自制服务器和客户端的安全连接。 首先,客户端连接到服务器并向每个 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);
}}
我认为更多的是对象流的问题,每次我尝试在套接字上使用对象流时都会遇到类似的问题。 有人知道发生了什么事吗?
一般情况下,您不能在同一个套接字上使用多个流。在某些特定情况下它可以工作,但一般来说你会遇到未知的缓冲,这会让你的同伴很快失去同步。在每一端重做一个 ObjectOutputStream
和 ObjectInputStream
。如果您只需要加密流的某些部分,请查看 SealedObject
.