【问题标题】:Reading from an SSL input stream (Java)从 SSL 输入流中读取 (Java)
【发布时间】:2015-11-10 18:50:26
【问题描述】:

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

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 后立即退出,但不等待实际的 nonce 和结束消息 KeyExchangeProtcolMsgs.nonceStr/#NONCE_END强>.

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

【问题讨论】:

  • 您正在通过 SSL 实现密钥交换协议?为什么?
  • 它是一个较大项目的一部分,其中需要交换数据的后向安全性,但交换数据的会话需要前向安全。在协议中交换的密钥用于为与不同数量的服务对象相关的 RPC 调用中的参数派生密钥。然后存储密钥以便以后解密(在这种情况下不是直接因为密钥需要从中派生(使用 HKMD))。

标签: java server client client-server


【解决方案1】:

因为只要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,但我认为像这样拆分它是清洁工。

【讨论】:

  • 它实际上是真的,因为此时 requestStr 确实包含协议消息。没有的时候是假的。我很困惑为什么如果不满足条件的第二部分,循环会停止。
  • @Sebi 抱歉,“第一条”是指requestStr.contains(KeyExchangeProtcolMsgs.reqStr) == false 部分。我将编辑我的答案以使其更清楚。
  • 代码背后的原因如下:你有一个初始消息,一个随机随机数和一个结束消息。我想从服务器端套接字读取,直到最后一个协议消息出现。
  • @Sebi 我编辑了我的答案,所以希望现在发生的事情更清楚。我将再次对其进行编辑以提出解决方案。
  • 那么在两个消息都出现在结果字符串中之前,读取字符的最佳方法应该是什么?
猜你喜欢
  • 2011-05-29
  • 2012-02-26
  • 2013-06-03
  • 2014-12-04
  • 2012-05-03
  • 2019-07-15
  • 2014-10-03
  • 2013-07-16
相关资源
最近更新 更多