如今基於上面製做的SocketClient能夠進行各類Socket協議的收發操做。可是要注意,緩衝區大小有可能會形成的粘包問題。html
咱們開始鏈接服務器的ssh服務java
ClientSocket client = new ClientSocket(socket); client.setClientListener(listener); client.start(); ssh = new SSH(client.getName());
能夠看到咱們這裏已經實現了一個ClientListener的接口回調,這裏面會長期與服務器進行打交道。算法
static ClientListener listener = new ClientListener() { @Override public void onSendData(ClientSocket client, byte[] data) { System.out.println("發送數據"); } @Override public void onReceiveData(ClientSocket client, byte[] data) { System.out.println("收到數據:" + client.getName()); System.out.println("" + new String(data)); ClientSocket.outHexByteArgs(data); switch (index) { case 0:// 協商協議版本 String version = new String(data); String serverVersion = ssh.version(version); client.send(data); System.out.println("ServerVersion:" + serverVersion + "|發送協商協議版本請求"); index++; break; case 1:// 協商加密算法 client.send(data); System.out.println("發送協商加密算法"); index++; break; case 2: } } @Override public void onConnect(ClientSocket client) { System.out.println("鏈接成功"); } @Override public void onClose(ClientSocket client) { System.out.println("關閉"); } };
這裏我已經實現了前兩個握手;安全
在整個通信過程當中,爲實現 SSH的安全鏈接,服務器端與客戶端要經歷以下五個階段:服務器
* 版本號協商階段,SSH目前包括 SSH1和SSH2兩個版本, 雙方經過版本協商肯定使用的版本ssh
* 密鑰和算法協商階段,SSH支持多種加密算法, 雙方根據本端和對端支持的算法,協商出最終使用的算法socket
* 認證階段,SSH客戶端向服務器端發起認證請求, 服務器端對客戶端進行認證ide
* 會話請求階段, 認證經過後,客戶端向服務器端發送會話請求加密
* 交互會話階段 ,會話請求經過後,服務器端和客戶端進行信息的交互spa
1 . 版本號協商階段
1. 服務器打開端口 22,等待客戶端鏈接。
2. 客戶端向服務器端發起 TCP初始鏈接請求,TCP鏈接創建後,服務器向客戶端發送第一個報文,包括版本標誌字符串,格式爲「SSH-<主協議版本號>.<次協議版本號>-<軟件版本號>」,協議版本號由主版本號和次版本號組成,軟件版本號主要是爲調試使用。
3. 客戶端收到報文後,解析該數據包,若是服務器端的協議版本號比本身的低,且客戶端能支持服務器端的低版本,就使用服務器端的低版本協議號,不然使用本身的協議版本號。
4. 客戶端迴應服務器一個報文,包含了客戶端決定使用的協議版本號。服務器比較客戶端發來的版本號,決定是否能同客戶端一塊兒工做。
5. 若是協商成功,則進入密鑰和算法協商階段,不然服務器端斷開 TCP鏈接。
Note: 版本號協商階段報文都是採用明文方式傳輸的。
2. 密鑰和算法協商階段
1. 服務器端和客戶端分別發送算法協商報文給對端,報文中包含本身支持的公鑰算法列表、加密算法列表、MAC(Message Authentication Code,消息驗證碼)算法列表、壓縮算法列表等;
2. 服務器端和客戶端根據對端和本端支持的算法列表得出最終使用的算法。
3. 服務器端和客戶端利用 DH交換(Diffie-Hellman Exchange)算法、主機密鑰對等參數,生成會話密鑰和會話 ID。
經過以上步驟,服務器端和客戶端就取得了相同的會話密鑰和會話ID。
* 對於後續傳輸的數據,兩端都會使用會話密鑰進行加密和解密,保證了數據傳送的安全
* 在認證階段,兩端會使用會話 ID用於認證過程。
Note:
在協商階段以前,服務器端已經生成 RSA或 DSA密鑰對,他們主要用於參與會話密鑰的生成。
3. 認證階段
1. 客戶端向服務器端發送認證請求,認證請求中包含用戶名、認證方法、與該認證方法相關的內容(如:password認證時,內容爲密碼)。
2. 服務器端對客戶端進行認證,若是認證失敗,則向客戶端發送認證失敗消息,其中包含能夠再次認證的方法列表。
3. 客戶端從認證方法列表中選取一種認證方法再次進行認證。
4. 該過程反覆進行, 直到認證成功或者認證次數達到上限, 服務器關閉鏈接爲止。
SSH提供兩種認證方式:
1. password認證:客戶端向服務器發出 password認證請求,將用戶名和密碼加密後發送給服務器;服務器將該信息解密後獲得用戶名和密碼的明文,與設備上保存的用戶名和密碼進行比較,並返回認證成功或失敗的消息。
2. publickey 認證:採用數字簽名的方法來認證客戶端。目前,設備上能夠利用RSA和 DSA兩種公共密鑰算法實現數字簽名。客戶端發送包含用戶名、公共密鑰和公共密鑰算法的 publickey 認證請求給服務器端。服務器對公鑰進行合法性檢查,若是不合法,則直接發送失敗消息;不然,服務器利用數字簽名對客戶端進行認證,並返回認證成功或失敗的消息
SSH2.0還提供了 password-publickey 認證和 any 認證:
1. password-publickey 認證:指定該用戶的認證方式爲 password 和 publickey認證同時知足。客戶端版本爲 SSH1的用戶只要經過其中一種認證便可登陸;客戶端版本爲 SSH2的用戶必須兩種認證都經過才能登陸。
2. any認證:指定該用戶的認證方式能夠是 password,也能夠是 publickey。
4.會話請求階段
1. 服務器等待客戶端的請求;
2. 認證經過後,客戶端向服務器發送會話請求;
3. 服務器處理客戶端的請求。請求被成功處理後, 服務器會向客戶端迴應 SSH_SMSG_SUCCESS包,SSH進入交互會話階段;不然迴應 SSH_SMSG_FAILURE包,表示服務器處理請求失敗或者不能識別請求。
5.交互會話階段
在這個模式下,數據被雙向傳送:
1. 客戶端將要執行的命令加密後傳給服務器;
2. 服務器接收到報文,解密後執行該命令,將執行的結果加密發還給客戶端;
3. 客戶端將接收到的結果解密後顯示到終端上.
全部資料都是本身找,好在有OpenSSH,後期找不到資料還能夠參閱源碼。
關於SSH的協議的描述請移步(感謝兩位發佈的博文,讓我找到些參考資料):