从 SSL 输入流中读取 (Java)

Reading from an SSL input stream (Java)

我正在尝试使用经过身份验证的 SSL 连接和下面 class 中定义的一些控制消息在客户端和服务器之间编写一个简单的协议:

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);
         }

服务器端的循环在KeyExchangeProtcolMsgs.reqStr/#REQ_KM发送后立即退出,但不等待实际的随机数和结束消息KeyExchangeProtcolMsgs.nonceStr/#NONCE_END.

为什么在客户端发送最后一条消息之前服务器端 while 循环退出?

因为一旦requestStr包含KeyExchangeProtcolMsgs.reqStrrequestStr.contains(KeyExchangeProtcolMsgs.reqStr)就变成了true,所以requestStr.contains(KeyExchangeProtcolMsgs.reqStr) == false就变成了true == false,也就是false,所以while循环中的整个测试变成false,所以执行退出while循环。

有几种方法可以解决这个问题,最简单的方法是使用两个 while 循环。第一个循环直到 requestStrKeyExchangeProtcolMsgs.reqStr,第二个循环累积随机数直到它以 KeyExchangeProtcolMsgs.nonceStr 结束。像这样:

        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);

尚未测试,但应该接近。

您可以通过保留某种状态指示器来使用单个 while 循环来完成此操作,以便您知道何时累积 reqStr 以及何时累积 nonceStr,但我认为像这样拆分它更干净。