java SSL加密傳輸
阿新 • • 發佈:2019-01-01
網路傳輸是存在風險的,因此對服服務端和客戶端進行安全校驗和傳輸資訊的加密就顯得非常的重要。
上面一句有點拗口,簡單解釋如下文:
當客戶使用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 [email protected] 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