Reputation: 2608
I'm trying to implement Diffie-Hellman's handshake for Java. I have a small problem, the Diffie-Hellman is done using DataInputStream and DataOutputStream with the client's Socket, but in order to use the secret it returns, I need to use a CipherStream. So I'm using a CipherStream and a DataStream over the socket.
public byte[] DHHandshake(Socket s){
byte[] secret = null;
try (DataOutputStream out = new DataOutputStream(s.getOutputStream())){
try(DataInputStream in = new DataInputStream(s.getInputStream())){
//Crear llave pública y privada en el cliente.
KeyPairGenerator kpg = KeyPairGenerator.getInstance(PROTOCOL);
kpg.initialize(Skip.sDHparameterSpec);
KeyPair keyPair = kpg.generateKeyPair();
//Envía llave pública del cliente al servidor
byte[] keyBytes = keyPair.getPublic().getEncoded();
out.writeInt(keyBytes.length);
out.write(keyBytes);
//Recibe llave pública del servidor
keyBytes = new byte[in.readInt()];
in.readFully(keyBytes);
KeyFactory kf = KeyFactory.getInstance(PROTOCOL);
X509EncodedKeySpec x509Spec = new X509EncodedKeySpec(keyBytes);
PublicKey theirPublicKey = kf.generatePublic(x509Spec);
//Llave pública servidor + llave privada cliente = llave compartida.
KeyAgreement ka = KeyAgreement.getInstance(PROTOCOL) ;
ka.init(keyPair.getPrivate());
ka.doPhase(theirPublicKey, true);
secret = ka.generateSecret();
}
}catch(Exception e) {
e.printStackTrace();
}
return secret;
}
The try-with-resources closes the Data Streams BUT ALSO closes the Socket. So when I try to send the file with a CipherStream using the secret returned in DiffieHellman, it throws an Exception saying the socket is closed:
private void receiveFile(Socket s, byte[] secret){
try(FileOutputStream fileWriter = new FileOutputStream(FILE)){
Cipher cipher = Cipher.getInstance(ALGORITHM + "/ECB/PKCS5PADDING");
SecretKeySpec keySpec = new SecretKeySpec(secret, ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, keySpec);
try(CipherInputStream cipherIn = new CipherInputStream(s.getInputStream(), cipher)){
byte[] fileBuffer = new byte[1024];
int len;
while ((len = cipherIn.read(fileBuffer)) >= 0)
fileWriter.write(fileBuffer, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
}
//TODO checkMD5
}
So here are my questions:
If I don't close the DataStream then is it possible to re-use the SocketStream to send data. Wouldn't this damage the SocketStream because the DataStream and CipherStream are using it at the same time?
Is there a way to close the DataStream without closeing the SocketStream?
Upvotes: 0
Views: 40
Reputation: 310980
The simple answer to all of this is to wrap the cipher streams around the respective data streams.
Upvotes: 1