Smack4.1 + OkHttp3 在Android上开启SSL

10 篇文章 0 订阅

1.准备工作
1.1 下载Openfire.
[http://download.igniterealtime.org/openfire/openfire_4_0_2.exe]
1.2 安装Openfire
建议安装在非C盘。 配置过程自行百度。
1.3 openfire配置SSL
配置完毕启动Openfire管理台,添加或更改以下属性

按照图中所示,保存设置后会添加属性xmpp.socket.ssl.keystore、xmpp.socket.ssl.keypass、xmpp.socket.ssl.truststore、xmpp.socket.ssl.trustpass

• xmpp.socket.ssl.active — 设置为“true”激活SSL
• xmpp.socket.ssl.keystore –您的Openfire安装根目录相对的keystore文件的位置。您可以离开此属性为空,使用默认密钥库。
• xmpp.socket.ssl.keypass –密钥库/密钥的密码 默认密码是changeit
• xmpp.socket.ssl.truststore –不使用信任库中则留空白,否则设置您的Openfire安装根目录相对的truststore文件的位置。
• xmpp.socket.ssl.trustpass — 改变的信任库/密钥密码默认密码是changeit

1.4 修改初始密码
进入path\resources\security有keystore和truststore2个文件,初始密码是changit。
修改初始密码,命令:

keytool -storepasswd -keystore keystore -storepass changeit -new 12344321
keytool -storepasswd -keystore truststore -storepass changeit -new 12344321
keytool -storepasswd -keystore client.truststore -storepass changeit -new 12344321

2.准备证书
2.1 导出默认证书
keystore中有2个签名证书,home_rsa,home_dsa, 其中home是opefire自定义服务器域名。使用以下命令将其导出。

keytool -exportcert -aliashome_rsa -file home_rsa.cer -keystore keystore -storepass 12344321
keytool -exportcert -alias home_dsa -file home_dsa.cer -keystore keystore -storepass 12344321
把证书导入客户端信任证书库,truststore, client.truststore

keytool -importcert -alias home_rsa -file home_rsa.cer -keystore truststore -storepass 12344321

keytool -importcert -alias home_dsa -file home_dsa.cer -keystore truststore -storepass 12344321

keytool -importcert -alias home_dsa -file home_dsa.cer -keystore client.truststore -storepass 12344321

keytool -importcert -alias home_rsa -file home_rsa.cer -keystore client.truststore -storepass 12344321

2.2 安装java第三方加密jar包
下载bcprov-ext-jdk15on-154.jar
https://downloads.bouncycastle.org/java/bcprov-ext-jdk15on-154.jar
拷贝到 jdkpath\jre\lib\ext下。
2.3 生成Android使用的client.bks
使用导出的证书home_dsa.cer生成client.bks
keytool -importcert -keystore client.bks -storepass 12344321 -file home_dsa.cer -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider

3 Android配置SSLContext
3.1 创建SSLContext
将client.bks拷贝至项目raw文件夹中,使用它来创建SSLContext.

private SSLContext createSSLContext(Context context) throws Exception {
SSLContext sslContext = SSLContext.getInstance(“TLS”);
MyX509TrustManager myX509TrustManager = new MyX509TrustManager(context.getResources().openRawResource(R.raw.client), “12344321”);
sslContext.init(null, new TrustManager[]{myX509TrustManager},
new SecureRandom());
return sslContext;
}

3.2 客户端创建MyX509TrustManager.
注意:Android需要使用BKS格式签名文件。

public class MyX509TrustManager implements X509TrustManager{

/*
* The default PKIX X509TrustManager9. Decisions are delegated
* to it, and a fall back to the logic in this class is performed
* if the default X509TrustManager does not trust it.
*/
X509TrustManager pkixTrustManager;

public MyX509TrustManager(InputStream ksfileStream, String kspass) throws Exception {
    // create a "default" JSSE X509TrustManager.

    KeyStore ks = KeyStore.getInstance("BKS");
    ks.load(ksfileStream, kspass.toCharArray());

    TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
    tmf.init(ks);

    TrustManager tms [] = tmf.getTrustManagers();

    /*
     * Iterate over the returned trust managers, looking
     * for an instance of X509TrustManager.  If found,
     * use that as the default trust manager.
     */
    for (int i = 0; i < tms.length; i++) {
        if (tms[i] instanceof X509TrustManager) {
            pkixTrustManager = (X509TrustManager) tms[i];
            return;
        }
    }

    /*
     * Find some other way to initialize, or else the
     * constructor fails.
     */
    throw new Exception("Couldn't initialize");
}

public MyX509TrustManager(String ksfile, String kspass) throws Exception {
    // create a "default" JSSE X509TrustManager.

    KeyStore ks = KeyStore.getInstance("BKS");
    ks.load(new FileInputStream(ksfile), kspass.toCharArray());

    TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
    tmf.init(ks);

    TrustManager tms [] = tmf.getTrustManagers();

    /*
     * Iterate over the returned trust managers, looking
     * for an instance of X509TrustManager.  If found,
     * use that as the default trust manager.
     */
    for (int i = 0; i < tms.length; i++) {
        if (tms[i] instanceof X509TrustManager) {
            pkixTrustManager = (X509TrustManager) tms[i];
            return;
        }
    }

    /*
     * Find some other way to initialize, or else the
     * constructor fails.
     */
    throw new Exception("Couldn't initialize");
}

/*
 * Delegate to the default trust manager.
 */
public void checkClientTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
    try {
        pkixTrustManager.checkClientTrusted(chain, authType);
    } catch (CertificateException excep) {
        // do any special handling here, or rethrow exception.
    }
}

/*
 * Delegate to the default trust manager.
 */
public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
    try {
        pkixTrustManager.checkServerTrusted(chain, authType);
    } catch (CertificateException excep) {
        /*
         * Possibly pop up a dialog box asking whether to trust the
         * cert chain.
         */
    }
}

/*
 * Merely pass this through.
 */
public X509Certificate[] getAcceptedIssuers() {
    return pkixTrustManager.getAcceptedIssuers();
}

}

3.3 创建XMPPTCPConnectionConfiguration
端口使用5222, 5223是过时的加密端口,5223不支持SSL/TSL。 添加CustomSSLContext,将setSocketFactory注释掉,SecurityMode设置为required。
connectionConfig = XMPPTCPConnectionConfiguration.builder()
.setServiceName(serviceName)
.setHost(host)
.setPort(port)
.setCustomSSLContext(sslContext)
// .setSocketFactory(sslContext.getSocketFactory())
.setDebuggerEnabled(false)
.setCompressionEnabled(false)
.setResource(XMPP_RESOURCE_NAME)
.setSecurityMode(ConnectionConfiguration.SecurityMode.required)
.setSendPresence(true)
.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
})
.build();

  1. 自签名证书生成
    4.1生成别名为jxjc的证书server.jks
    keytool -genkeypair -alias server -keypass 12344321 -keyalg RSA -keysize 1024 -validity 365 -keystore server.jks -storepass 12344321 -dname “CN=*.home, OU=, O=, L=, ST=, C=”

4.2导出别名为server的证书保存到sercer.cer

keytool -exportcert -alias server -file server.cer -keystore server.jks -storepass 12344321

4.3 导出信任库
如需将自签名证书导入到openfire中,重复1,2步骤。

5.OkHttp3使用SSL加密连接
1.单向验证
1.获取包含公钥的证书
可使用sercer.cer 密码是12344321

2.设置证书。
将证书关联到SSLContext,并为okhttpClient设置SSLContextFactory

public void setCertificates(InputStream... certificates)
{
   try
   {
      CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
      KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
      keyStore.load(null);
      int index = 0;
      for (InputStream certificate : certificates)
      {
         String certificateAlias = Integer.toString(index++);
         keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));

         try
         {
            if (certificate != null)
               certificate.close();
         } catch (IOException e)
         {
         }
      }

      SSLContext sslContext = SSLContext.getInstance("TLS");

      TrustManagerFactory trustManagerFactory =
            TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

      trustManagerFactory.init(keyStore);
      sslContext.init
            (
                  null,
                  trustManagerFactory.getTrustManagers(),
                  new SecureRandom()
            );
      mOkHttpClient.setSslSocketFactory(sslContext.getSocketFactory());


   } catch (Exception e)
   {
      e.printStackTrace();
   }
}

代码流程解析:
1.构造CertificateFactory对象,通过它的generateCertificate(is)方法得到Certificate。
2. 然后讲得到的Certificate放入到keyStore中。
3. 接下来利用keyStore去初始化我们的TrustManagerFactory
4.由trustManagerFactory.getTrustManagers获得TrustManager[]初始化我们的SSLContext
5.最后,设置我们mOkHttpClient.setSslSocketFactory即可。

2.双向验证
1.证书准备
首先对于双向证书验证,也就是说,客户端也会有个“jks文件”,服务器那边会同时有个“cer文件”与之对应。我们已经生成了server.jks和server.cer,按照相同的步骤再生成client.jks和client.cer。生成完毕后,将client.cer导入到server.jks中。
keytool -import -alias client -file client.cer -keystore server.jks
2.Android端配置
需要修改setCertificates方法,添加KeyStoreManager注册到SSLContext
代码如下

public void setCertificates(InputStream... certificates)
{
   try
   {
      CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
      KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
      keyStore.load(null);
      int index = 0;
      for (InputStream certificate : certificates)
      {
         String certificateAlias = Integer.toString(index++);
         keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));

         try
         {
            if (certificate != null)
               certificate.close();
         } catch (IOException e)
         {
         }
      }

      SSLContext sslContext = SSLContext.getInstance("TLS");
      TrustManagerFactory trustManagerFactory = TrustManagerFactory.
            getInstance(TrustManagerFactory.getDefaultAlgorithm());
      trustManagerFactory.init(keyStore);

      //初始化keystore
      KeyStore clientKeyStore = KeyStore.getInstance("BKS");
      clientKeyStore.load(mContext.getAssets().open("jxjcclient.bks"), "12344321".toCharArray());

      KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
      keyManagerFactory.init(clientKeyStore, "12344321".toCharArray());

      sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
      mOkHttpClient.setSslSocketFactory(sslContext.getSocketFactory());


   } catch (Exception e)
   {
      e.printStackTrace();
   }
}

注:client.bks生成方法参考上文

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值