如何在Android应用程序中启用TLS 1.2支持(在Android 4.1 JB上运行)

一万年来谁著史,三千里外欲封侯。这篇文章主要讲述如何在Android应用程序中启用TLS 1.2支持(在Android 4.1 JB上运行)相关的知识,希望能为你提供帮助。
根据android中针对SSLSocketSSLContext的文档,API级别16+支持TLS v1.1和v1.2协议,但默认情况下不启用。 http://developer.android.com/reference/javax/net/ssl/SSLSocket.html http://developer.android.com/reference/javax/net/ssl/SSLContext.html
如何在运行Android 4.1或更高版本(但低于5.0)的设备上启用它?
我尝试创建一个自定义的SSLSocketFactory,它在创建Socket时启用所有支持的协议,然后使用我的自定义实现:

【如何在Android应用程序中启用TLS 1.2支持(在Android 4.1 JB上运行)】HttpsURLConnection.setDefaultSSLSocketFactory(new MySSLSocketFactory());
public class MySSLSocketFactory extends SSLSocketFactory {private SSLContext sc; private SSLSocketFactory ssf; public MySSLSocketFactory() { try { sc = SSLContext.getInstance("TLS"); sc.init(null, null, null); ssf = sc.getSocketFactory(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } }@Override public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { SSLSocket ss = (SSLSocket) ssf.createSocket(s, host, port, autoClose); ss.setEnabledProtocols(ss.getSupportedProtocols()); ss.setEnabledCipherSuites(ss.getSupportedCipherSuites()); return ss; }@Override public String[] getDefaultCipherSuites() { return ssf.getDefaultCipherSuites(); }@Override public String[] getSupportedCipherSuites() { return ssf.getSupportedCipherSuites(); }@Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { SSLSocket ss = (SSLSocket) ssf.createSocket(host, port); ss.setEnabledProtocols(ss.getSupportedProtocols()); ss.setEnabledCipherSuites(ss.getSupportedCipherSuites()); return ss; }@Override public Socket createSocket(InetAddress host, int port) throws IOException { SSLSocket ss = (SSLSocket) ssf.createSocket(host, port); ss.setEnabledProtocols(ss.getSupportedProtocols()); ss.setEnabledCipherSuites(ss.getSupportedCipherSuites()); return ss; }@Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { SSLSocket ss = (SSLSocket) ssf.createSocket(host, port, localHost, localPort); ss.setEnabledProtocols(ss.getSupportedProtocols()); ss.setEnabledCipherSuites(ss.getSupportedCipherSuites()); return ss; }@Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { SSLSocket ss = (SSLSocket) ssf.createSocket(address, port, localAddress, localPort); ss.setEnabledProtocols(ss.getSupportedProtocols()); ss.setEnabledCipherSuites(ss.getSupportedCipherSuites()); return ss; } }

但是在尝试与启用了仅TLS 1.2的服务器建立连接时,它仍会出现异常。
这是我得到的例外:
03-09 09:21:38.427:W / System.err(2496):javax.net.ssl.SSLHandshakeException:javax.net.ssl.SSLProtocolException:SSL握手中止:ssl = 0xb7fa0620:SSL库失败,通常是协议错误
03-09 09:21:38.427:W / System.err(2496):错误:14077410:SSL例程:SSL23_GET_SERVER_HELLO:sslv3警报握手失败(外部/ openssl / ssl / s23_clnt.c:741 0xa90e6990:0x00000000)
答案2种启用TLSv1.1和TLSv1.2的方法:
  1. 使用此指南:http://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/
  2. 使用这个类https://github.com/erickok/transdroid/blob/master/app/src/main/java/org/transdroid/daemon/util/TlsSniSocketFactory.java schemeRegistry.register(new Scheme("https", new TlsSniSocketFactory(), port));
另一答案我按照文章http://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/中提供的指示解决了这个问题,几乎没有变化。
SSLContext context = SSLContext.getInstance("TLS"); context.init(null, null, null); SSLSocketFactory noSSLv3Factory = null; if (Build.VERSION.SDK_INT < = Build.VERSION_CODES.KITKAT) { noSSLv3Factory = new TLSSocketFactory(sslContext.getSocketFactory()); } else { noSSLv3Factory = sslContext.getSocketFactory(); } connection.setSSLSocketFactory(noSSLv3Factory);

这是自定义TLSSocketFactory的代码:
public static class TLSSocketFactory extends SSLSocketFactory {private SSLSocketFactory internalSSLSocketFactory; public TLSSocketFactory(SSLSocketFactory delegate) throws KeyManagementException, NoSuchAlgorithmException { internalSSLSocketFactory = delegate; }@Override public String[] getDefaultCipherSuites() { return internalSSLSocketFactory.getDefaultCipherSuites(); }@Override public String[] getSupportedCipherSuites() { return internalSSLSocketFactory.getSupportedCipherSuites(); }@Override public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose)); }@Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port)); }@Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort)); }@Override public Socket createSocket(InetAddress host, int port) throws IOException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port)); }@Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort)); }/* * Utility methods */private static Socket enableTLSOnSocket(Socket socket) { if (socket != null & & (socket instanceof SSLSocket) & & isTLSServerEnabled((SSLSocket) socket)) { // skip the fix if server doesn't provide there TLS version ((SSLSocket) socket).setEnabledProtocols(new String[]{TLS_v1_1, TLS_v1_2}); } return socket; }private static boolean isTLSServerEnabled(SSLSocket sslSocket) { System.out.println("__prova__ :: " + sslSocket.getSupportedProtocols().toString()); for (String protocol : sslSocket.getSupportedProtocols()) { if (protocol.equals(TLS_v1_1) || protocol.equals(TLS_v1_2)) { return true; } } return false; } }

编辑:感谢ademar111190的kotlin实现(link)
class TLSSocketFactory constructor( private val internalSSLSocketFactory: SSLSocketFactory ) : SSLSocketFactory() {private val protocols = arrayOf("TLSv1.2", "TLSv1.1")override fun getDefaultCipherSuites(): Array< String> = internalSSLSocketFactory.defaultCipherSuitesoverride fun getSupportedCipherSuites(): Array< String> = internalSSLSocketFactory.supportedCipherSuitesoverride fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean) = enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose))override fun createSocket(host: String, port: Int) = enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port))override fun createSocket(host: String, port: Int, localHost: InetAddress, localPort: Int) = enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort))override fun createSocket(host: InetAddress, port: Int) = enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port))override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int) = enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort))private fun enableTLSOnSocket(socket: Socket?) = socket?.apply { if (this is SSLSocket & & isTLSServerEnabled(this)) { enabledProtocols = protocols } }private fun isTLSServerEnabled(sslSocket: SSLSocket) = sslSocket.supportedProtocols.any { it in protocols }}

另一答案我对上面提到的答案有一些补充它实际上是来自okhttp的Jesse Wilson提到的hack,方形here。根据这个hack,我不得不将我的SSLSocketFactory变量重命名为
private SSLSocketFactory delegate;

这是我的TLSSocketFactory类
public class TLSSocketFactory extends SSLSocketFactory {private SSLSocketFactory delegate; public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException { SSLContext context = SSLContext.getInstance("TLS"); context.init(null, null, null); delegate = context.getSocketFactory(); }@Override public String[] getDefaultCipherSuites() { return delegate.getDefaultCipherSuites(); }@Override public String[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites(); }@Override public Socket createSocket() throws IOException { return enableTLSOnSocket(delegate.createSocket()); }@Override public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { return enableTLSOnSocket(delegate.createSocket(s, host, port, autoClose)); }@Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { return enableTLSOnSocket(delegate.createSocket(host, port)); }@Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { return enableTLSOnSocket(delegate.createSocket(host, port, localHost, localPort)); }@Override public Socket createSocket(InetAddress host, int port) throws IOException { return enableTLSOnSocket(delegate.createSocket(host, port)); }@Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { return enableTLSOnSocket(delegate.createSocket(address, port, localAddress, localPort)); }private Socket enableTLSOnSocket(Socket socket) { if(socket != null & & (socket instanceof SSLSocket)) { ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"}); } return socket; } }

这就是我用okhttp和改造它的方式
OkHttpClient client=new OkHttpClient(); try { client = new OkHttpC

    推荐阅读