您的位置 首页 java

安卓下安全通信 使用BKS实现SSL/TLS安全协议

安卓下安全通信 使用BKS实现SSL/TLS安全协议

安卓系统BKS证书的使用

一、 概述

手机默认内置了主流的根证书,一般在使用OkHttp时,使用本地根证书进行校验,项目不需要内置CA根证书。

手机可以在设置停用某个根证书,这时与一些服务器通信,就会报 ssl 异常。用浏览器打开网页时,会提示 未授信的网站。

当使用自己制作的证书的时候,可以把证书放到项目里打包到APK中。

二、keytool支持BKS的设置

安卓通用使用的是BKS格式的证书。但JDK默认情况下不支持BKS证书格式,如果要使用BKS需要进行以下操作:

  1. 下载 org.bouncycastle.jce.provider.BouncyCastleProvider 包,网址:
  2. 把下载的 bcprov-ext-jdk15to18-166.jar , bcprov-jdk15to18-166.jar 放到 %JAVA_HOME%/ jre /lib/ext 下。(我也不知道为啥我下载有两个包)
  3. 修改%JAVA_HOME%/jre/lib/security/java.security文件
    我的配置是这样的:
 jdk. TLS .disabledAlgorithms=
security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=sun.security.ec.SunEC
security.provider.4= com .sun.net.ssl. internal .ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=com.sun.security.sasl.Provider
security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcard io .SunPCSC
security.provider.10=org.bouncycastle.jce.provider.BouncyCastleProvider  

三、cer转换为bks格式

1. 格式转换命令

 keytool -importcert -trustcacerts -keystore cNetty.bks -file cNetty.cer -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
# 按提示输入密钥库指令
keytool -importcert -trustcacerts -keystore sNetty.bks -file sNetty.cer -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
# 按提示输入密钥库指令  

2. 导入信任证书库

这时要把证书导入对方信任证书的仓库中,使用命令:

 keytool -import -alias securenettyclient_bks -file cNetty.cer -storepass 你的storepass密码 -keystore sNetty.bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
keytool -import -alias securenettyservice_bks -file sNetty.cer -storepass 你的storepass密码 -keystore cNetty.bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider  

3. 查看bks证书

 # 查看证书链
keytool -list -rfc -keystore cNetty.bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider -storepass 你的storepass证书
# 验证BKS
keytool -list -v -storetype BKS -keystore sNetty.bks  

四、java socket使用bks证书的核心客户端代码

以下代码客户端支持使用jks和bks两种格式、支持windows和android端使用,可以用在Netty框架:

 
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.nio. file .Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.CertificateException;

/**
 * 加密通讯,获取SSLContext的方法
 * @author Cade
 */
@Slf4j
public final class SecureNettySslContex tf actory {
	
	private static final String PROTOCOL = "TLS";
	private static final String FILE_JKS ="jks";
	private static final String KEYSTORE_BKS ="BKS";
	private static final String KEYSTORE_JKS ="JKS";
	/**
	 * 服务器安全上下文
	 */
	private static SSLContext SERVER_CONTEXT;
	/**
	 * 客户端安全上下文
	 */
    private static SSLContext CLIENT_CONTEXT;

	/**
	 *
	 * @param pkPath pkPath
	 * @param caPath caPath
	 * @param jksPass jksPass
	 * @param storePass storePass
	 * @return SSL上下文
	 */
	 public static SSLContext getClientContext(String pkPath,String caPath,String jksPass,String storePass){
		 if(CLIENT_CONTEXT!=null) {
			 return CLIENT_CONTEXT;
		 }

		 final String osAndroid="android";
		 KeyManagerFactory kmf;
		 TrustManagerFactory tf;
		 KeyStore ks;
		 KeyStore tks ;
		 try {
			 if(caPath.contains(FILE_JKS)) {
				 ks = KeyStore. getInstance (KEYSTORE_JKS);
				 tks = KeyStore.getInstance(KEYSTORE_JKS);
			 }else{
				 Security.addProvider(new BouncyCastleProvider());
				 ks = KeyStore.getInstance(KEYSTORE_BKS);
				 tks = KeyStore.getInstance(KEYSTORE_BKS);
			 }

			 // 如果是安卓系统,读取资源的方式有所不同
			 if (osAndroid.equals(Constants.OS)) {
				 try (InputStream in = Constants.class.getResourceAsStream(pkPath)) {
					 ks.load(in, jksPass.toCharArray());
				 }
				 try(InputStream in = Constants.class.getResourceAsStream(caPath)){
					 tks.load(in, jksPass.toCharArray());
				 }
			 } else {
				 try (InputStream stream = Files.newInputStream(Paths.get(pkPath))) {
					 ks.load(stream, jksPass.toCharArray());
				 }
				 try (InputStream stream = Files.newInputStream(Paths.get(caPath))) {
					 tks.load(stream, jksPass.toCharArray());
				 }
			 }
			 if( log .isInfoEnabled()) {
				 log.info(TrustManagerFactory.getDefaultAlgorithm());
			 }
			 kmf = KeyManagerFactory.getInstance("SunX509");
			 kmf.init(ks, storePass.toCharArray());
			 tf = TrustManagerFactory.getInstance("SunX509");
			 tf.init(tks);

			 CLIENT_CONTEXT = SSLContext.getInstance(PROTOCOL);
			 //初始化此上下文
			 //参数一:认证的密钥      参数二:对等信任认证  参数三:伪随机数生成器 。 由于单向认证,服务端不用验证客户端,所以第二个参数为null
			 CLIENT_CONTEXT.init(kmf.getKeyManagers(), tf.getTrustManagers(), null);

		 }catch (IOException | KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException | CertificateException | KeyManagementException e){
		 	if(log.isErrorEnabled()){
		 		log.error(e.toString());
			}
		 }
		 return CLIENT_CONTEXT;
	 }

}
  

代码里Constants类是自定义的常量类。

五、OKHttp使用证书

bks一般可以放在assets下。

 public class MyOkhttpClient {
    private static MyOkhttpClient singleton;
    public static OkHttpClient getInstance() {
        if (singleton == null) {
            synchronized (CBOkhttpClient.class) {
                if (singleton == null) {
                    OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
                    builder.connectTimeout(50000, TimeUnit.MILLISECONDS);
                    builder.writeTimeout(50000, TimeUnit.MILLISECONDS);
                    builder.readTimeout(50000, TimeUnit.MILLISECONDS);
                    try {
                        SSLContext sslContext = SSLContext.getInstance("TLS");
                        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                        KeyStore trustStore = KeyStore.getInstance("BKS");
                        InputStream ksinstream = CBFramework.getApplication().getResources().openRawResource(R.raw.cbframework_trustcerts);
                        trustStore.load(ksinstream, "".toCharArray());
                        ksinstream.close();
                        trustManagerFactory.init(trustStore);
                        sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
                        builder.sslSocketFactory(sslContext.getSocketFactory(), new X509TrustManager() {
                            @ Override 
                            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                            }

                            @Override
                            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                            }

                            @Override
                            public X509Certificate[] getAcceptedIssuers() {
                                return new X509Certificate[0];
                            }
                        });
                    } catch (Exception e) {
                        Log.e(e);
                    }
                    singleton = builder.build();
                }
            }
        }
        return singleton;
    }
}  

文章来源:智云一二三科技

文章标题:安卓下安全通信 使用BKS实现SSL/TLS安全协议

文章地址:https://www.zhihuclub.com/191618.shtml

关于作者: 智云科技

热门文章

网站地图