code: @Override
      public ByteBuffer read(ByteBuffer receiveBuffer) throws IOException {
          if (!doHandshake(receiveBuffer))
              return null;
  
          if (!initialHSComplete)
              throw new IllegalStateException("The initial handshake is not complete.");
  
          if (log.isDebugEnabled()) {
              log.debug("session {} read data status -> {}, initialHSComplete -> {}", session.getSessionId(),
                      session.isOpen(), initialHSComplete);
          }
  
          merge(receiveBuffer);
          if (!receivedPacketBuf.hasRemaining()) {
              return null;
          }
  
          needIO:
          while (true) {
              SSLEngineResult result = unwrap();
  
              if (log.isDebugEnabled()) {
                  log.debug("Session {} read data result -> {}, receivedPacketBuf -> {}, appBufSize -> {}",
                          session.getSessionId(), result.toString().replace('\n', ' '),
                          receivedPacketBuf.remaining(), receivedAppBuf.remaining());
              }
  
              switch (result.getStatus()) {
                  case BUFFER_OVERFLOW: {
                      resizeAppBuffer();
                      // retry the operation.
                  }
                  break;
                  case BUFFER_UNDERFLOW: {
                      int packetBufferSize = sslEngine.getSession().getPacketBufferSize();
                      if (receivedPacketBuf.remaining() >= packetBufferSize) {
                          break; // retry the operation.
                      } else {
                          break needIO;
                      }
                  }
                  case OK: {
                      if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) {
                          doTasks();
                      }
                      if (receivedPacketBuf.hasRemaining()) {
                          break; // retry the operation.
                      } else {
                          break needIO;
                      }
                  }
  
                  case CLOSED: {
                      log.info("Session {} read data failure. SSLEngine will close inbound", session.getSessionId());
                      closeInbound();
                  }
                  break needIO;
  
                  default:
                      throw new SecureNetException(StringUtils.replace("Session {} SSLEngine read data exception. status -> {}",
                              session.getSessionId(), result.getStatus()));
              }
          }
  
          return getReceivedAppBuf();
      }
docs: This method is used to decrypt data, it implied do handshake
  
  @param receiveBuffer Encrypted message
  @return plaintext
  @throws IOException sslEngine error during data read