TLS connection using SSLSocket is slow in Android OS

后端 未结 4 1049
感动是毒
感动是毒 2020-12-28 22:33

I\'m developing an Android app which uses SSLSocket to connect to a server. This is the code I\'m using:

// Connect
if (socket == null || socket.isClosed() |         


        
相关标签:
4条回答
  • 2020-12-28 23:11

    I have done something similar to this and it is slower than an unsecured connection. Granted my case was https vs http and it is a little different the SSL/TLS factor will add slowness to the deal.

    I have two identical apps that comunicate with the same protocol to the same server, one in android and one in iPhone, both using https. When I tested them both in http I would see more or less the same response time, in https iOS was slightly faster in my case, but not terribly.

    0 讨论(0)
  • 2020-12-28 23:18

    There was a bug on earlier versions of the Android SDK. Apparently, it's doing an unnecessary DNS reverse lookup. You need to prevent this from happening. Here's a workaround that worked for me. It used to take 15 seconds, now it takes 0-1 seconds. Hope it helps.

    Here's the link to the Google issue.

    boolean connected = false;
    if (socket == null || socket.isClosed() || !socket.isConnected()) {
        if (socket != null && !socket.isClosed()) {
            socket.close();
        }
    
        Log.i(getClass().toString(), "Connecting...");
        messages.getText().append("Connecting...");
        final KeyStore keyStore = KeyStore.getInstance("BKS");
        keyStore.load(getResources().openRawResource(R.raw.serverkey), null);
    
        final KeyManagerFactory keyManager = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManager.init(keyStore, null);
        //keyManager.init(null, null);
    
        final TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustFactory.init(keyStore);
    
        sslContext = SSLContext.getInstance("TLS");
        sslContext.init(keyManager.getKeyManagers(), trustFactory.getTrustManagers(), rnd);
        final SSLSocketFactory delegate = sslContext.getSocketFactory();
        SocketFactory factory = new SSLSocketFactory() {
            @Override
            public Socket createSocket(String host, int port)
                            throws IOException, UnknownHostException {
    
                InetAddress addr = InetAddress.getByName(host);
                injectHostname(addr, host);
                return delegate.createSocket(addr, port);
            }
            @Override
            public Socket createSocket(InetAddress host, int port)
                            throws IOException {
    
                return delegate.createSocket(host, port);
            }
            @Override
            public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
                            throws IOException, UnknownHostException {
    
                return delegate.createSocket(host, port, localHost, localPort);
            }
            @Override
            public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
                            throws IOException {
    
                return delegate.createSocket(address, port, localAddress, localPort);
            }
            private void injectHostname(InetAddress address, String host) {
                try {
                    Field field = InetAddress.class.getDeclaredField("hostName");
                    field.setAccessible(true);
                    field.set(address, host);
                } catch (Exception ignored) {
                }
            }
            @Override
            public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
    
                injectHostname(s.getInetAddress(), host);
                return delegate.createSocket(s, host, port, autoClose);
            }
            @Override
            public String[] getDefaultCipherSuites() {
                return delegate.getDefaultCipherSuites();
            }
            @Override
            public String[] getSupportedCipherSuites() {
                return delegate.getSupportedCipherSuites();
            }
        };
        socket = (SSLSocket)factory.createSocket("192.168.197.133", 9999);
        socket.setSoTimeout(20000);
        socket.setUseClientMode(true);
        connected = true;
        Log.i(getClass().toString(), "Connected.");
        messages.getText().append("Connected.");
    }
    
    // Secure
    if (connected) {
        Log.i(getClass().toString(), "Securing...");
        messages.getText().append("Securing...");
        SSLSession session = socket.getSession();
        boolean secured = session.isValid();
        if (secured) {
            Log.i(getClass().toString(), "Secured.");
            messages.getText().append("Secured.");
        }
    }
    
    0 讨论(0)
  • 2020-12-28 23:32

    The problem is most likely in the way the device validates server certificates. Validation can involve contacting third-party for CRLs and OCSP responses. If this happens, it takes time. iPhone probably just doesn't do this (at least by default) which is a security hole BTW.

    0 讨论(0)
  • 2020-12-28 23:35

    You are using a new SecureRandom per connection, instead of using a single static pre-initialized SecureRandom. Everytime you create a new SecureRandom(), you need to gather entropy for seeding (a slow process).

    SecureRandom does not self-seed until it is first used, which is why the delay does not occur until the call to getSession()

    0 讨论(0)
提交回复
热议问题