Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ssl/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 第二个循环中的SSLEngine握手库存_Java_Ssl_Sslengine - Fatal编程技术网

Java 第二个循环中的SSLEngine握手库存

Java 第二个循环中的SSLEngine握手库存,java,ssl,sslengine,Java,Ssl,Sslengine,我正在尝试使用SSLEngine实现SSL握手,作为服务器和客户端,我都需要这样做,但是我被卡住了,我不知道为什么 握手开始正确,问候语被交换,钥匙被交换,但是我进入了需要打开的状态 以下是我使用的握手代码: protected boolean doHandshake(InputStream inputStream, OutputStream outputStream, SSLEngine engine, Socket socket) throws IOException {

我正在尝试使用SSLEngine实现SSL握手,作为服务器和客户端,我都需要这样做,但是我被卡住了,我不知道为什么

握手开始正确,问候语被交换,钥匙被交换,但是我进入了需要打开的状态

以下是我使用的握手代码:

    protected boolean doHandshake(InputStream inputStream, OutputStream outputStream, SSLEngine engine, Socket socket) throws IOException {

    Log.d(TAG,"About to do handshake...");
    Log.d(TAG,engine.getHandshakeStatus().toString());
    int dataSize;
    SSLEngineResult result;
    Log.d(TAG,"Line 1");
    HandshakeStatus handshakeStatus;
    Log.d(TAG,"Line 2");
    // NioSslPeer's fields myAppData and peerAppData are supposed to be large enough to hold all message data the peer
    // will send and expects to receive from the other peer respectively. Since the messages to be exchanged will usually be less
    // than 16KB long the capacity of these fields should also be smaller. Here we initialize these two local buffers
    // to be used for the handshake, while keeping client's buffers at the same size.

    if (socket!=null)
    {
        inputStream=socket.getInputStream();
        outputStream=socket.getOutputStream();
    }
    Log.d(TAG,"Line 3");
    int appBufferSize = engine.getSession().getApplicationBufferSize();
    Log.d(TAG,"Line 4");
    ByteBuffer myAppData = ByteBuffer.allocate(appBufferSize);
    Log.d(TAG,"Line 5");
    ByteBuffer peerAppData = ByteBuffer.allocate(appBufferSize);
    Log.d(TAG,"Line 6");
    try {
        myNetData.clear();
        peerNetData.clear();
    }
    catch (Exception e){Log.e(TAG,e.getMessage());}
    Log.d(TAG,"Line 7");

    Log.d(TAG,"Line 8");
    handshakeStatus = engine.getHandshakeStatus();
    Log.d(TAG,"Line 9");
    Log.d(TAG,"Before the while: " + (handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED && handshakeStatus != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING));

    byte[] buffer=new byte[16384];
    while (handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED && handshakeStatus != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
        Log.d(TAG,handshakeStatus.toString());
        switch (handshakeStatus) {
        case NEED_UNWRAP:
            Log.d(TAG,"Got here...");
            buffer=new byte[16384];
            peerAppData.clear();
            int readdata=inputStream.read(buffer);
            Log.d(TAG,"Read data amount: " + readdata);
            if ( readdata < 0) {
                Log.d(TAG,"No data....");
                if (engine.isInboundDone() && engine.isOutboundDone()) {
                    return false;
                }
                try {
                    engine.closeInbound();
                } catch (SSLException e) {
                    Log.e(TAG,"This engine was forced to close inbound, without having received the proper SSL/TLS close notification message from the peer, due to end of stream.");
                }
                engine.closeOutbound();
                // After closeOutbound the engine will be set to WRAP state, in order to try to send a close message to the client.
                handshakeStatus = engine.getHandshakeStatus();
                break;
            }
           HackerService.bytesToHex(buffer);

            peerNetData.put(buffer,6,readdata-6);
            Log.d(TAG,"before data flipped...");
            peerNetData.flip();
            Log.d(TAG,"data flipped...");
            try {
                result = engine.unwrap(peerNetData, peerAppData);
                Log.d(TAG,"data unwrapped...");
                peerNetData.compact();

                Log.d(TAG,"data compacted...");
                handshakeStatus = result.getHandshakeStatus();
                Log.d(TAG,"Handshake status: " + handshakeStatus);
            } catch (SSLException sslException) {
                Log.e(TAG,"A problem was encountered while processing the data that caused the SSLEngine to abort. Will try to properly close connection..." + sslException.getMessage());
                engine.closeOutbound();
                handshakeStatus = engine.getHandshakeStatus();
                break;
            }
            switch (result.getStatus()) {
            case OK:
                break;
            case BUFFER_OVERFLOW:
                // Will occur when peerAppData's capacity is smaller than the data derived from peerNetData's unwrap.
                peerAppData = enlargeApplicationBuffer(engine, peerAppData);
                break;
            case BUFFER_UNDERFLOW:
                // Will occur either when no data was read from the peer or when the peerNetData buffer was too small to hold all peer's data.
                peerNetData = handleBufferUnderflow(engine, peerNetData);
                break;
            case CLOSED:
                if (engine.isOutboundDone()) {
                    return false;
                } else {
                    engine.closeOutbound();
                    handshakeStatus = engine.getHandshakeStatus();
                    break;
                }
            default:
                throw new IllegalStateException("Invalid SSL status: " + result.getStatus());
            }
            break;
        case NEED_WRAP:
            myNetData.clear();
            Log.d(TAG,"Enetering need wrap");
            try {
                result = engine.wrap(myAppData, myNetData);
                Log.d(TAG,"Got a result" + myAppData.toString());
                handshakeStatus = result.getHandshakeStatus();
                Log.d(TAG,"Handskes is: " + handshakeStatus.toString());

            } catch (SSLException sslException) {
                Log.e(TAG,"A problem was encountered while processing the data that caused the SSLEngine to abort. Will try to properly close connection...");
                engine.closeOutbound();
                handshakeStatus = engine.getHandshakeStatus();
                break;
            }
            switch (result.getStatus()) {
            case OK :
                Log.d(TAG,"Case WRAP, OK");
                myNetData.flip();

             //  while (myNetData.hasRemaining()) {
                    byte[] arr = new byte[myNetData.remaining()+6];
                    myNetData.get(arr,6,myNetData.remaining());
                    arr[0]=0;
                    arr[1]=3;
                    arr[2]=(byte) ((arr.length-4)/256);
                    arr[3]=(byte) ((arr.length-4)%256);
                    arr[4]=buffer[4];
                    arr[5]=buffer[5];
                    HackerService.bytesToHex(arr);
                    outputStream.write(arr);
               // }
                break;
            case BUFFER_OVERFLOW:
                Log.d(TAG,"Case WRAP,OverFlow");
                // Will occur if there is not enough space in myNetData buffer to write all the data that would be generated by the method wrap.
                // Since myNetData is set to session's packet size we should not get to this point because SSLEngine is supposed
                // to produce messages smaller or equal to that, but a general handling would be the following:
                myNetData = enlargePacketBuffer(engine, myNetData);
                break;
            case BUFFER_UNDERFLOW:
                throw new SSLException("Buffer underflow occured after a wrap. I don't think we should ever get here.");
            case CLOSED:
                try {
                    Log.d(TAG,"Before WRAP FLIP");
                    myNetData.flip();
                    Log.d(TAG,"After WRAP FLIP");
                    while (myNetData.hasRemaining()) {
                        Log.d(TAG,myNetData.toString());
                         arr = new byte[myNetData.remaining()];
                        myNetData.get(arr);
                        outputStream.write(arr);
                    }
                    // At this point the handshake status will probably be NEED_UNWRAP so we make sure that peerNetData is clear to read.
                    peerNetData.clear();
                } catch (Exception e) {
                    Log.e(TAG,"Failed to send server's CLOSE message due to socket channel's failure.");
                    handshakeStatus = engine.getHandshakeStatus();
                }
                break;
            default:
                throw new IllegalStateException("Invalid SSL status: " + result.getStatus());
            }
            break;
        case NEED_TASK:
            Log.d(TAG,"Need task");
            Runnable task;
            while ((task = engine.getDelegatedTask()) != null) {
                executor.execute(task);
            }
            handshakeStatus = engine.getHandshakeStatus();
            break;
        case FINISHED:
            break;
        case NOT_HANDSHAKING:
            break;
        default:
            throw new IllegalStateException("Invalid SSL status: " + handshakeStatus);
        }
    }
    Log.d(TAG,"Handshake completed");
    return true;

}
当我作为客户尝试握手时。正如您从日志中看到的,我从需要包装开始,将数据发送到服务器,状态到达需要展开(这是正确的)服务器响应,我解析答案没有任何错误,但我没有前进到需要包装,而是陷入需要展开

About to do handshake...
NEED_WRAP
Line 1
Line 2
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
Before the while: true
NEED_WRAP
Enetering need wrap
Got a resultjava.nio.HeapByteBuffer[pos=0 lim=16384 cap=16384]
Handskes is: NEED_UNWRAP
Case WRAP, OK
ByteTohex: 00030088000316030100810100007D03030E62BFCFF988.......
NEED_UNWRAP
Got here...
Read data amount: 2296   (THIS MATCHES THE NUMBER OF BYTES SENT BY THE SERVER!!!!)
ByteTohex: 000308F40003160303005B0200005703035B203DA285349B7C88A76CA6AA3.....
before data flipped...
data flipped...
data unwrapped...
data compacted...
Handshake status: NEED_UNWRAP
NEED_UNWRAP
Got here...
如果我尝试作为服务器进行握手,日志如下所示。从日志中可以看出,第一次读取很好,我响应客户机,从客户机获取第二位数据,而不是需要包装并能够进行握手,我收到了一条需要展开的消息,但当然没有更多的数据要从客户机读取

    About to do handshake...
    NEED_UNWRAP
    Line 1
    Line 2
    Line 3
    Line 4
    Line 5
    Line 6
    Line 7
    Line 8
    Line 9
    Before the while: true
    NEED_UNWRAP
    Got here...
06-12 23:42:14.017 7523-7620/uk.co.borconi,emil.myapp D/MyApp: Read data amount: 297
06-12 23:42:14.020 7523-7620/uk.co.borconi,emil.myapp D/MyApp: ByteTohex: 00030125000316....
    before data flipped...
    data flipped...
06-12 23:42:14.029 7523-7620/uk.co.borconi,emil.myapp D/MyApp: data unwrapped...
    data compacted...
    Handshake status: NEED_WRAP
    NEED_WRAP
    Enetering need wrap
    Got a resultjava.nio.HeapByteBuffer[pos=0 lim=16384 cap=16384]
    Handskes is: NEED_UNWRAP
    Case WRAP, OK
06-12 23:42:14.030 7523-7620/uk.co.borconi,emil.myapp D/MyApp: ByteTohex: 00030881000316.....
    NEED_UNWRAP
    Got here...
06-12 23:42:14.038 7523-7620/uk.co.borconi,emil.myapp D/MyApp: Read data amount: 132
06-12 23:42:14.039 7523-7620/uk.co.borconi,emil.myapp D/MyApp: ByteTohex: 00030080000316....
    before data flipped...
    data flipped...
06-12 23:42:14.040 7523-7620/uk.co.borconi,emil.myapp D/MyApp: data unwrapped...
    data compacted...
    Handshake status: NEED_UNWRAP
    NEED_UNWRAP
    Got here...

在发布之前,我确实看了一些关于StackOverflow的类似问题,但它们主要是关于订单错误,我想我在这个案例中是对的。。。我很确定我忽略了明显的问题,但我似乎无法理解它……

在追踪我自己的故事两天后,我终于找到了如下所述的问题:

我发现SSLEngine周围基于流的包装器不可读 当没有新的传入数据时,所有来自SSLEngine的传入数据 来自网络的数据,因此应用程序无法等待 传入数据。经过一番调试后,我发现这与内蒂的 openssl SSLEngine unwrap似乎以较小的格式生成纯文本数据 块(可能是单个TLS帧)并保持对其余帧的缓冲 这些数据是内部的。src缓冲区已完全使用,但正在调用 使用空src缓冲区再次展开仍将生成更多数据。 这与JDK SSLEngine有两点不同:

  • JDK SSLEngine一次性消耗和生成尽可能多的数据,而openssl one在一次调用中生成的输出更少
  • JDK SSLEngine不会在调用展开之间内部缓冲加密数据,而是“将它们放回”src缓冲区
所以,即使我的代码是“正确的”,我也需要执行多个循环,所以现在我的展开代码看起来像这样:

peerNetData.put(buffer,6,readdata-6);
                Log.d(TAG,"before data flipped...");
                peerNetData.flip();
                Log.d(TAG,"data flipped...");
                try {
                    do {
                    result = engine.unwrap(peerNetData, peerAppData);
                    Log.d(TAG,"data unwrapped...");
                    Log.d(TAG,"Handskes is: " + result.getHandshakeStatus().toString() +" Current Status: " +result.getStatus() + " Bytes consumed: " + result.bytesConsumed() + " bytes produce: " + result.bytesProduced());
                    } while (peerNetData.hasRemaining() || result.bytesProduced()>0);
                    peerNetData.compact();


                    Log.d(TAG,"data compacted...");
                    handshakeStatus = result.getHandshakeStatus();
                    Log.d(TAG,"Handshake status: " + handshakeStatus);
                    .....................................................

你太想当然了。“需要展开”表示您应该执行
UNWRAP()
。如果这导致缓冲区下溢,请执行读取。类似地,需要WRAP
WRAP()
,缓冲区溢出和'write()。@EJP-谢谢,但这让我更加困惑。在我完成任务后,各州都陷入了困境。我根本没有达到溢出状态,如果我不写,另一方将如何获得数据?同样对于展开,你会做什么呢?我当然会尝试,但我不确定我是否遵循逻辑。另外,阅读“需要展开”文档时,明确表示需要从输入中读取数据。@EJP-在没有数据的情况下展开会导致TLS解析错误,我也永远不会遇到溢出情况。同样在看Oracle文档时,他们还说我们应该进行读入unwrp()和写入wrap(),进行
unwrap()
,而不使用数据导致缓冲区下溢,然后进行读取,如我所说,然后当然重复展开。但是如果你使用的是一辆小车
SSLEngine
所有的赌注都没有了。所以这是Netty中的一个bug。他们究竟为什么提供自己的
SSLEngine
?受虐狂?注意:Java
SSLEngine
没有“把它们放回去”,只是没有打开它们。我很高兴我终于找到了问题的症结所在。现在,这确实提出了一个问题:我是否需要对握手后收到的每个数据包执行类似的操作?如果是这样的话,那么将代码从jni+openssl移植到纯java以减少在java和c之间传递数据时的开销的好处可能就不复存在了。也有可能只是在安卓系统中坏了,我还没有在安卓系统之外测试过。
peerNetData.put(buffer,6,readdata-6);
                Log.d(TAG,"before data flipped...");
                peerNetData.flip();
                Log.d(TAG,"data flipped...");
                try {
                    do {
                    result = engine.unwrap(peerNetData, peerAppData);
                    Log.d(TAG,"data unwrapped...");
                    Log.d(TAG,"Handskes is: " + result.getHandshakeStatus().toString() +" Current Status: " +result.getStatus() + " Bytes consumed: " + result.bytesConsumed() + " bytes produce: " + result.bytesProduced());
                    } while (peerNetData.hasRemaining() || result.bytesProduced()>0);
                    peerNetData.compact();


                    Log.d(TAG,"data compacted...");
                    handshakeStatus = result.getHandshakeStatus();
                    Log.d(TAG,"Handshake status: " + handshakeStatus);
                    .....................................................