I'm trying to write a simple protocol between a client and a server using an authenticated SSL connection and a number of control messages defined in the class bellow:
public class KeyExchangeProtcolMsgs {
public static final String reqStr = "#REQ_KM";
public static final String nonceStr = "#NONCE_END";
public static final String ackStr = "#ACK_KM";
}
client.java
// Connect to the server
cSock = (SSLSocket) fact.createSocket(this.remoteHost, this.remotePort);
// Create the streams to send out data as well as read data
OutputStream out = cSock.getOutputStream();
InputStream in = cSock.getInputStream();
// Generate client nonce
byte[] clientNonceB = CryptographyUtils.generateRandomNumber();
// Send the nonce and the request for a key from the server
// First, send the keying material request to the server
System.out.println("[I] SSL client written " + KeyExchangeProtcolMsgs.reqStr);
out.write(CryptographyUtils.toByteArray(KeyExchangeProtcolMsgs.reqStr)); // <== Successfully written to the server
// Next, send the generated nonce (by the client)
System.out.println("[I] SSL client written nonce ");
System.out.println(new String(clientNonceB, "UTF-8"));
out.write(clientNonceB);
// Finally, send the ending string
System.out.println("[I] SSL client written " + KeyExchangeProtcolMsgs.nonceStr);
out.write(CryptographyUtils.toByteArray(KeyExchangeProtcolMsgs.nonceStr));
// Wait for the response from the server containing the key
int ch = 0;
String responseStr = "";
while ((responseStr.contains(KeyExchangeProtcolMsgs.ackStr) == false) && (responseStr.contains(KeyExchangeProtcolMsgs.nonceStr) == false)) {
ch = in.read();
responseStr = responseStr + (char) ch;
System.out.println("[I] SSL client read " + responseStr);
}
// Display read information from server
System.out.println("[I] SSL client read " + responseStr);
// Check if the server nonce contains the starting and end messages of the protocol
String serverNonceStr = responseStr.substring(KeyExchangeProtcolMsgs.ackStr.length(), responseStr.length() - KeyExchangeProtcolMsgs.nonceStr.length());
// Compute the key by xor-ing the client and server nonce and applying AES
// on the resulting string
clientKeyingMaterial = new SecretKeySpec(CryptographyUtils.xorStrings(clientNonceB, CryptographyUtils.toByteArray(serverNonceStr)), "AES");
return clientKeyingMaterial;
server.java
System.out.println("[I] SSL server listening");
SSLSocket sslSock = (SSLSocket) sSock.accept();
sslSock.startHandshake();
System.out.println("[I] SSL server starting handshake");
// Process if principal checks out
if (isEndEntity(sslSock.getSession())) {
// Create the streams to send out data as well as read data
OutputStream out = sslSock.getOutputStream();
InputStream in = sslSock.getInputStream();
// Wait and read the client's nonce
int ch = 0;
String requestStr = "";
while ((requestStr.contains(KeyExchangeProtcolMsgs.reqStr) == false) && (requestStr.contains(KeyExchangeProtcolMsgs.nonceStr) == false)) {
ch = in.read();
requestStr = requestStr + (char) ch;
System.out.println("[I] SSL server received " + requestStr);
}
System.out.println("[I] SSL server received " + requestStr);
}
The loop on the server side exits as soon as KeyExchangeProtcolMsgs.reqStr/#REQ_KM is sent but does not wait for the actual nonce and ending message KeyExchangeProtcolMsgs.nonceStr/#NONCE_END .
Why does the server side while loop exit before the last message is sent by the client?
Because as soon as requestStr
contains KeyExchangeProtcolMsgs.reqStr
, requestStr.contains(KeyExchangeProtcolMsgs.reqStr)
becomese true
, so requestStr.contains(KeyExchangeProtcolMsgs.reqStr) == false
becomes true == false
, which is false
, so the entire test in the while loop becomes false
, so execution drops out of the while loop.
There are a couple of ways to fix this, the easiest would be to have two while loops. The first just loops until requestStr
is KeyExchangeProtcolMsgs.reqStr
, and the second that accumulates the nonce until it ends with KeyExchangeProtcolMsgs.nonceStr
. Something like this:
String requestStr = "";
while (!requestStr.equals(KeyExchangeProtcolMsgs.reqStr)) {
ch = in.read();
requestStr = requestStr + (char) ch;
}
System.out.println("[I] SSL server received " + requestStr);
String nonceStr = "";
while (!requestStr.endsWith(KeyExchangeProtcolMsgs.nonceStr)) {
ch = in.read();
nonceStr = nonceStr + (char) ch;
}
// Whack #NONCE_END from the end to get just the nonce.
nonceStr = nonceStr.substring(0, nonceStr.length() - KeyExchangeProtcolMsgs.nonceStr.length());
System.out.println("[I] SSL server received " + nonceStr);
That's not tested but it should be close.
You could do it with a single while loop by keeping some sort of state indicator so you know when you're accumulating the reqStr
and when you're accumulating the nonceStr
, but I think splitting it like this is cleaner.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.