【发布时间】:2015-12-21 10:39:50
【问题描述】:
我正在尝试处理与自制服务器和客户端的安全连接。 首先,客户端连接到服务器并为每个 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);
}}
我认为这更多是对象流的问题,每次我尝试在套接字上使用对象流时都会遇到类似的问题。 有人知道发生了什么吗?
【问题讨论】:
-
旁注:你知道最近发现的反序列化 Java 错误吗?邪恶的客户可能会欺骗
readObject做几乎任何事情。 -
第 13 行客户端应用程序中的 readObject() 方法是阻塞的。
-
客户端等待读取对象时服务器在做什么?
-
服务器等待从客户端发送的对象为客户端提供请求的信息。这发生在 while 循环和最后的 switch 中。
-
对于客户端服务器应用程序是否通常不推荐使用对象流,或者有没有办法让它更安全?
标签: java sockets serversocket encryption-symmetric encryption-asymmetric