网络传输是存在风险的,因此对服服务端和客户端进行安全校验和传输信息的加密就显得非常的重要。
上面一句有点拗口,简单解释如下文:
当客户使用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
输入的主密码
(如果和 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 *@authordraem0507@gmail.com3 * @TODO java线程开发之四 SSL加密4 * 开发步骤5 * 1.生成服务端密钥6 * 2.导出服务端证书7 * 3.生成客户端密钥8 * 4.程序开发测试9 * 关于证书的生成请参考readme.txt10 * 参考资料:http://chrui.iteye.com/blog/1018778
11 *@version1.012 * @date 2013-5-7 23:22:4513 * @update 2013-5-8 10:22:4514 * @blgoshttp://www.cnblogs.com/draem0507
15 */
16
17 public classServerTest {18 privateServerSocket serverSocket;19 private final static char[] password="123456".toCharArray();20 privateSSLContext context;21 URL url = Thread.currentThread().getContextClassLoader().getResource("sslsocket.keystore");22 String path =url.toString();23 privateInputStream inputStream;24
25
26 publicServerTest() {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 newReceiveSocket(socket).start();38 }39 } catch(IOException e) {40 //TODO Auto-generated catch block
41 e.printStackTrace();42 }43
44 }45
46 //ssl 上下文对象的初始化
47 private voidinitContext() {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 voidmain(String[] args) {82 newServerTest();83
84 }85
86 private class ReceiveSocket extendsThread {87 privateSocket socket;88
89 publicReceiveSocket(Socket socket) {90 this.socket =socket;91 }92
93 privateObjectInputStream reader;94 privateObjectOutputStream writer;95
96 @Override97 public voidrun() {98
99 try{100 reader=new ObjectInputStream(newBufferedInputStream(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 classClientTest {2 private final static char[] password="123456".toCharArray();3 private staticSSLContext context;4 static InputStream inputStream=ClientTest.class.getResourceAsStream("/sslclient.keystore");5
6 public static void main(String[] args) throwsException {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=newObjectOutputStream(socket.getOutputStream());24
25
26 User user =newUser();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