一万年来谁著史,三千里外欲封侯。这篇文章主要讲述如何在Android应用程序中启用TLS 1.2支持(在Android 4.1 JB上运行)相关的知识,希望能为你提供帮助。
根据android中针对SSLSocket
和SSLContext
的文档,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库失败,通常是协议错误答案2种启用TLSv1.1和TLSv1.2的方法:
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)
- 使用此指南:http://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-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));
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
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 为什么Android测试运行器报告“空测试套件”()
- Android游戏(Canvas还是OpenGL())
- “画布(Android Studio中试图绘制太大的位图”问题)
- 使用Google Apps脚本搜索无结果
- 试图将Google Pay集成到我的Android应用中
- 身份验证Apollo Graphql for android
- [android 8.0中的android套接字连接
- java.lang.IllegalStateException(找不到方法-初学者的Android编程书ERROR [duplicate])
- Android-如何在ActionBar中实现“赞”按钮