美文网首页程序员Android开发
android +j2ee实现JSSE的通信

android +j2ee实现JSSE的通信

作者: Rhett_S | 来源:发表于2017-05-27 14:49 被阅读0次

    JSSE(JAVA安全套接字扩展,JAVA Secure Socket Extension)是SSL和TLS的纯Java实现,,通过它可以透明地提供数据加密、服务器认证、信息完整性等功能,就像使用普通的套接字一样使用安全套接字。

    开始前的准备

    密钥格式

    SSL/TLS协议通信就必须涉及到密钥和数字证书。
    在Java支持JKS,JCEKS和PKCS#12格式的密钥。但是android不支持JKS,如果入到JKS文件,我们可以把他转换为BKS文件。

    JKS文件(通常为.jks或.keystore,扩展名无关)可以通过Java原生工具——KeyTool生成;
    JCKES文件也是JAVA中常用的密钥格式。JKS的Provider是SUN,在每个版本的JDK中都有,JCEKS的Provider是SUNJCE,1.4后我们都能够直接使用它。
    PKCS#12文件(通常为.p12或.pfx,意味个人信息交换文件),可以通过OpenSSL工具产生。
    BKS文件是android单独支持的文件。可以和JKS文件转换。

    文件之间的关系


    .cer格式文件俗称证书,但这个证书中没有私钥,只包含了公钥;
    .pfx格式文件不仅包含了公钥,还包含了私钥,当然这个私钥是加密的,不输入密码是解不了密的;
    .jks格式文件表示java密钥存储器(javakey store),它可以同时容纳N个公钥跟私钥,是一个密钥库;
    .keystore格式文件其实跟.jks基本是一样的;
    .truststore格式文件表示信任证书存储库,它和.keystore是一样的。仅仅包含了通信对方的公钥,当然你可以直接把通信对方的jks作为信任库。

    使用SSL/TLS协议通信,如果是双向认证的话,则需要客户端和服务端各自有一组自己的密钥(keyStore)以及信任文件(trustStore),当然可以使用keyStore代替trustStore免去证书相互导入的麻烦。java中的类图如下(这里的keyStore是JDK中的keyStore。android内部也有一个keyStore,这里不去管它)

    UML

    • 通信核心类——SSLSocket和SSLServerSocket。对于使用过socket进行通信开发的朋友比较好理解,它们对应的就是Socket与ServerSocket,只是表示实现了SSL协议的Socket和ServerSocket,同时它们也是Socket与ServerSocket的子类。SSLSocket负责的事情包括设置加密套件、管理SSL会话、处理握手结束时间、设置客户端模式或服务器模式。
    • 客户端与服务器端Socket工厂——SSLSocketFactory和SSLServerSocketFactory。在设计模式中工厂模式是专门用于生产出需要的实例,这里也是把SSLSocket、SSLServerSocket对象创建的工作交给这两个工厂类。
    • SSL会话——SSLSession。安全通信握手过程需要一个会话,为了提高通信的效率,SSL协议允许多个SSLSocket共享同一个SSL会话,在同一个会话中,只有第一个打开的SSLSocket需要进行SSL握手,负责生成密钥及交换密钥,其余SSLSocket都共享密钥信息。
    • SSL上下文——SSLContext。它是对整个SSL/TLS协议的封装,表示了安全套接字协议的实现。主要负责设置安全通信过程中的各种信息,例如跟证书相关的信息。并且负责构建SSLSocketFactory、SSLServerSocketFactory和SSLEngine等工厂类。
    • SSL非阻塞引擎——SSLEngine。假如你要进行NIO通信,那么将使用这个类,它让通过过程支持非阻塞的安全通信。
    • 密钥管理器——KeyManager。此接口负责选择用于证实自己身份的安全证书,发给通信另一方。KeyManager对象由KeyManagerFactory工厂类生成。
    • 信任管理器——TrustManager。此接口负责判断决定是否信任对方的安全证书,TrustManager对象由TrustManagerFactory工厂类生成。

    证书

    • 生成服务器证书库
      这里的地址需要改为服务器的ip,否则容易出错
    keytool -validity 365 -genkey -v -alias server -keyalg RSA -keystore E:\test1\T1\server.keystore -dname "CN=192.168.0.036,OU=rongyiwang,O=rongyiwang,L=Shanghai,ST=Shanghai,c=cn" -storepass 123456 -keypass 123456
    
    • 生成客户端证书库
    keytool -validity 365 -genkeypair -v -alias client -keyalg RSA -storetype PKCS12 -keystore E:\test1\T1\client.p12 -dname "CN=client,OU=rongyiwang,O=rongyiwang,L=Shanghai,ST=Shanghai,c=cn" -storepass 123456 -keypass 123456
    
    • 从客户端证书库中导出客户端证书
    keytool -export -v -alias client -keystore E:\test1\T1\client.p12 -storetype PKCS12 -storepass 123456 -rfc -file E:\test1\T1\client.cer
    
    • 从服务器证书库中导出服务器证书
    keytool -export -v -alias server -keystore E:\test1\T1\server.keystore -storepass 123456 -rfc -file E:\test1\T1\server.cer
    
    • 生成客户端信任证书库(由服务端证书生成的证书库)
      这里我直接生产的bks类型的文件
    keytool -import -v -alias server -file E:\test1\T1\server.cer -keystore E:\test1\T1\client.truststore -storepass 123456 -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
    
    • 将客户端证书导入到服务器证书库(使得服务器信任客户端证书)
    keytool -import -v -alias client -file E:\test1\T1\client.cer -keystore E:\test1\T1\serverytrust.keystore -storepass 123456
    
    • 查看证书库中的全部证书
    keytool -list -keystore E:\test1\T1\server.keystore -storepass 123456
    

    服务端

    首先加载自己的密钥和信任密钥
    1.keyStore

    
               KeyStore serverKeyStore = KeyStore.getInstance("JKS");  
               serverKeyStore.load(new FileInputStream(serverKeyStoreFile), serverKeyStorePwd.toCharArray());  
    

    2.trustStore

    
               KeyStore serverTrustKeyStore = KeyStore.getInstance("JKS");  
               serverTrustKeyStore.load(new FileInputStream(serverTrustKeyStoreFile), serverTrustKeyStorePwd.toCharArray());  
    

    3.建立SSLServerSocket

               KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());  
               kmf.init(serverKeyStore, catServerKeyPwd.toCharArray());  
         
               TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());  
               tmf.init(serverTrustKeyStore);  
         
               SSLContext sslContext = SSLContext.getInstance("TLSv1.2");  
               sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);  
         
               SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory();  
               SSLServerSocket sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(18080);  
               sslServerSocket.setNeedClientAuth(true);  
    

    4.到了这里基本就和不同Socket编程差不多了,监听SSLServerSocket即可

     while (true){
            SSLSocket s = (SSLSocket) sslServerSocket.accept();
             if(s!=null){
                // do something
             }
    }
    

    客户端

    相关文章

      网友评论

        本文标题:android +j2ee实现JSSE的通信

        本文链接:https://www.haomeiwen.com/subject/uucwzttx.html