java线程之四 SSL加密传输

网络传输是存在风险的,因此对服服务端和客户端进行安全校验和传输信息的加密就显得非常的重要。

上面一句有点拗口,简单解释如下文:

  当客户使用SSL向站点服务器发送请求时,服务器向客户端发送一个证书,客户使用已安装的证书,验证服务器身份,然后检查IP地址(主机名)与客户端连接的主机是否匹配。客户生成可以用来对话的私钥(称为会话密钥),然后用服务者的公钥对它进行加密并将它发送到服务者。服务者用自己的私钥解密,然后用该信息和客户端一样的私有会话密钥。通常在这个阶段使用RSA算法。 
随后,客户端和服务器端使用私有会话密钥和私钥算法(通常是RC4)进行通信。使用另一个密钥的消息认证码来确保消息的完整性。

接下来,就一一介绍下如何进行SSL加密的socket通信开发

一、创建服务端密钥

命令行执行

keytool.exe -genkeypair -v -alias sslsocket -keyalg RSA -keystore e:\sslsocket.keystore 

出现提示输入密码

输入keystore密码:
        再次输入新密码:
        您的名字与姓氏是什么?
          [Unknown]:  lwx
        您的组织单位名称是什么?
          [Unknown]:  newland
        您的组织名称是什么?
          [Unknown]:  bomc
        您所在的城市或区域名称是什么?
          [Unknown]:  fz
        您所在的州或省份名称是什么?
          [Unknown]:  fj
        该单位的两字母国家代码是什么
          [Unknown]:  zh
        CN=lwx, OU=newland, O=bomc, L=fz, ST=fj, C=zh 正确吗?
          [否]:  y

上述信息只是为了帮助客户端校验服务端证书的信息,测试的时候只需要注意最后提示是否正确的时候 输入y 即可。

接着出现下面信息

正在为以下对象生成 1,024 位 RSA 密钥对和自签名证书 (SHA1withRSA)(有效期为 90 天
        ):
                 CN=lwx, OU=newland, O=bomc, L=fz, ST=fj, C=zh
        输入<sslsocket>的主密码
                (如果和 keystore 密码相同,按回车):
        [正在存储 e:\sslsocket.keystore]

生成密钥sslsocket.keystore后,可以通过下面的命令来查看

keytool -list  -v -keystore e:\sslsocket.keystore -storepass 123456    

看到的信息就是之前我们输入的内容了 

Keystore 类型: JKS
        Keystore 提供者: SUN
        
        您的 keystore 包含 1 输入
        
        别名名称: sslsocket
        创建日期: 2013-5-8
        项类型: PrivateKeyEntry
        认证链长度: 1
        认证 [1]:
        所有者:CN=lwx, OU=newland, O=bomc, L=fz, ST=fj, C=zh
        签发人:CN=lwx, OU=newland, O=bomc, L=fz, ST=fj, C=zh
        序列号:5189a30d
        有效期: Wed May 08 08:57:49 CST 2013 至Tue Aug 06 08:57:49 CST 2013
        证书指纹:
                 MD5:51:5E:1A:57:1B:B9:18:3A:9B:05:F7:13:E5:06:AB:F0
                 SHA1:11:0E:C8:8B:46:1F:27:FA:12:95:95:4E:1E:29:E7:27:50:2E:E9:48
                 签名算法名称:SHA1withRSA
                 版本: 3
        

二、生成服务端证书

keytool.exe -exportcert -v -alias sslsocket -file e:\sslsocket.cer -keystore e:\sslsocket.keystore
e:\sslsocket.cer 即我们服务端的证书,到这里应该就比较熟悉了
查看证书信息的命令
keytool.exe -printcert -v -file e:\sslsocket.cer

出现的结果如下

    所有者:CN=lwx, OU=newland, O=bomc, L=fz, ST=fj, C=zh
        签发人:CN=lwx, OU=newland, O=bomc, L=fz, ST=fj, C=zh
        序列号:5189a30d
        有效期: Wed May 08 08:57:49 CST 2013 至Tue Aug 06 08:57:49 CST 2013
        证书指纹:
                 MD5:51:5E:1A:57:1B:B9:18:3A:9B:05:F7:13:E5:06:AB:F0
                 SHA1:11:0E:C8:8B:46:1F:27:FA:12:95:95:4E:1E:29:E7:27:50:2E:E9:48
                 签名算法名称:SHA1withRSA
                 版本: 3

三、生成客户端密钥

有了服务端证书之后,自然就是通过密码来生成客户端的密钥了,命令如下

keytool.exe -importcert -v -alias sslsocketcer -file e:\sslsocket.cer -keystore e:\sslclient.keystore
e:\sslclient.keystore 就是客户端的密钥了。

关于keytool的更多信息可以参考这里:http://blog.chinaunix.net/uid-17102734-id-2830223.html

四、开发程序

为了测试 我将服务端和客户端的证书放到工程目录下

服务端代码

  1 /**
  2  * @author  draem0507@gmail.com
  3  * @TODO    java线程开发之四 SSL加密
  4  * 开发步骤
  5  * 1.生成服务端密钥
  6  * 2.导出服务端证书
  7  * 3.生成客户端密钥
  8  * 4.程序开发测试
  9  * 关于证书的生成请参考readme.txt
 10  * 参考资料:http://chrui.iteye.com/blog/1018778
 11  * @version 1.0
 12  * @date 2013-5-7 23:22:45    
 13  * @update 2013-5-8 10:22:45    
 14  * @blgos http://www.cnblogs.com/draem0507
 15  */
 16 
 17 public class ServerTest {
 18     private ServerSocket serverSocket;
 19     private final static char[] password="123456".toCharArray();
 20     private SSLContext context;
 21     URL url = Thread.currentThread().getContextClassLoader().getResource("sslsocket.keystore");
 22     String path = url.toString();
 23     private InputStream inputStream;
 24     
 25 
 26     public ServerTest() {
 27         inputStream=this.getClass().getResourceAsStream("/sslsocket.keystore");
 28         initContext();
 29         try {
 30             //直接运行会报 javax.net.ssl.SSLException:
 31             //ServerSocketFactory factory=     SSLServerSocketFactory.getDefault();
 32             ServerSocketFactory factory=     context.getServerSocketFactory();
 33 //            serverSocket = new ServerSocket(10000);
 34             serverSocket=factory.createServerSocket(10000);
 35             while (true) {
 36                 Socket socket = serverSocket.accept();
 37                 new ReceiveSocket(socket).start();
 38             }
 39         } catch (IOException e) {
 40             // TODO Auto-generated catch block
 41             e.printStackTrace();
 42         }
 43 
 44     }
 45     
 46     //ssl 上下文对象的初始化
 47     private void initContext() {
 48         try {
 49             KeyStore store=KeyStore.getInstance("JKS");
 50             store.load(inputStream, password);
 51             KeyManagerFactory factory=KeyManagerFactory.getInstance("SunX509");
 52             factory.init(store,password);
 53             KeyManager []keyManagers=factory.getKeyManagers();
 54             context=SSLContext.getInstance("SSL");
 55             context.init(keyManagers, null    , null);
 56         } catch (KeyStoreException e) {
 57             // TODO Auto-generated catch block
 58             e.printStackTrace();
 59         } catch (NoSuchAlgorithmException e) {
 60             // TODO Auto-generated catch block
 61             e.printStackTrace();
 62         } catch (CertificateException e) {
 63             // TODO Auto-generated catch block
 64             e.printStackTrace();
 65         } catch (FileNotFoundException e) {
 66             // TODO Auto-generated catch block
 67             e.printStackTrace();
 68         } catch (IOException e) {
 69             // TODO Auto-generated catch block
 70             e.printStackTrace();
 71         } catch (UnrecoverableKeyException e) {
 72             // TODO Auto-generated catch block
 73             e.printStackTrace();
 74         } catch (KeyManagementException e) {
 75             // TODO Auto-generated catch block
 76             e.printStackTrace();
 77         }
 78         
 79     }
 80 
 81     public static void main(String[] args) {
 82         new ServerTest();
 83 
 84     }
 85 
 86     private class ReceiveSocket extends Thread {
 87         private Socket socket;
 88 
 89         public ReceiveSocket(Socket socket) {
 90             this.socket = socket;
 91         }
 92 
 93         private ObjectInputStream reader;
 94         private ObjectOutputStream writer;
 95 
 96         @Override
 97         public void run() {
 98 
 99             try {
100                 reader=new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
101                 //writer=new ObjectOutputStream(socket.getOutputStream());
102                 // 开启无限循环 监控消息
103                 
104                     //java.io.EOFException
105                 Object obj=    reader.readObject();
106                     if(obj!=null)
107                     {
108                         User user =(User)obj;
109                         System.out.println("id=="+user.getId()+"\tname=="+user.getName());
110                     }
111                 //    while (true) {}
112 
113             } catch (IOException e) {
114                 // TODO Auto-generated catch block
115                 e.printStackTrace();
116             } catch (ClassNotFoundException e) {
117                 // TODO Auto-generated catch block
118                 e.printStackTrace();
119             } finally {
120                 if (null != reader) {
121                     try {
122                         reader.close();
123                     } catch (IOException e) {
124                         // TODO Auto-generated catch block
125                         e.printStackTrace();
126                     }
127                 }
128                 if (null != writer) {
129                     try {
130                         reader.close();
131                     } catch (IOException e) {
132                         // TODO Auto-generated catch block
133                         e.printStackTrace();
134                     }
135                 }
136                 try {
137                     socket.close();
138                 } catch (IOException e) {
139                     // TODO Auto-generated catch block
140                     e.printStackTrace();
141                 }
142             }
143 
144         }
145 
146     }
147 
148 }

客户端代码

 1 public class ClientTest {
 2     private final static char[] password="123456".toCharArray();
 3     private static SSLContext context;
 4     static InputStream inputStream=ClientTest.class.getResourceAsStream("/sslclient.keystore");
 5     
 6     public static void main(String[] args) throws Exception {
 7          
 8         KeyStore ts = KeyStore.getInstance("JKS");  
 9         ts.load(inputStream, password);  
10         TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");  
11         tmf.init(ts);  
12         TrustManager [] tm = tmf.getTrustManagers();  
13         context = SSLContext.getInstance("SSL");  
14         context.init(null, tm, null);  
15         
16         //SocketFactory factory=    SSLSocketFactory.getDefault();
17         //Socket socket =factory.createSocket("localhost", 10000);
18         SocketFactory factory=    context.getSocketFactory();
19         SSLSocket socket=(SSLSocket) factory.createSocket("localhost", 10000);
20         
21         
22         //ObjectInputStream in=new ObjectInputStream(socket.getInputStream());
23         ObjectOutputStream out=new ObjectOutputStream(socket.getOutputStream());
24         
25         
26                 User user =new User();
27                 user.setId(1);
28                 user.setName("lwx_"+1);
29                 out.writeObject(user);
30                 out.flush();
31     
32             
33         socket.close();
34         
35         
36     }
37 }

如果想要源码的话,可以到这里来下载 http://download.csdn.net/detail/draem0507/5343534

原文地址:https://www.cnblogs.com/draem0507/p/3067252.html