實驗內容
1.用書上的TCP代碼,實現服務器與客戶端。
2.客戶端與服務器連接
3.客戶端中輸入明文,利用DES算法加密,DES的秘鑰用RSA公鑰密碼中服務器的公鑰加密,計算明文的Hash函數值,一起傳送給客戶端
4.客戶端用RSA公鑰密碼中服務器的私鑰解密DES的,秘鑰,用秘鑰對密文進行解密,得出明文。計算求得明文的Hash函數值,檢查是否與傳送過來的一致,如果一致,則表示匹配成功。
實驗步驟
結對實驗
•我和20145213祁瑋組隊進行實驗
•我負責服務器的部分,祁瑋負責客戶端部分
IP和端口
•尋找本機的IP地址也就是IPv4的地址可以通過命令行的ipconfig命令來查找。
匹配成功!
•有了IP地址計算機就可以找到對方,但是一個計算機設有多個端口來運行多個網絡程序,每個網絡程序占用不同的端口,所以就算找到了,要想連接起來,還需要知道端口,注意服務器和客戶端的端口必須要統一。
•在硬件上規定,端口的號碼必須位於0-65535之間,每個端口唯一的對應一個網絡程序,一個網絡程序可以使用多個端口。這樣一個網絡程序運行在一台計算上時,不管是客戶端還是服務器,都是至少占用一個端口進行網絡通訊。在接收數據時,首先發送給對應的計算機,然后計算機根據端口把數據轉發給對應的程序。
•有了IP地址和端口的概念以后,在進行網絡通訊交換時,就可以通過IP地址查找到該台計算機,然后通過端口標識這台計算機上的一個唯一的程序。這樣就可以進行網絡數據的交換了。
服務器端網絡操作步驟
•服務器屬於被動等待連接,所以首先要進行監聽端口,等待客戶端進行連接。
•在客戶端連接之后,服務器就獲得一個與客戶端之間的連接,二者就可以通過這個連接進行數據交換了。
•服務器接收到客戶端傳來的數據之后要進行處理,針對本次實驗來說,客戶端傳來的數據是加密過的,所以服務器需要進行解密的操作:
1.首先要使用服務器端RSA的私鑰對DES的密鑰進行解密
2.再將十六進制數據轉換成十進制
3.之后用解密得到的DES密鑰對DES進行解密
4.然后使用解密得到的DES對十進制進制密文數據進行解密
5.最后將得到的十進制明文用“UTF-8”轉碼成明文字符
•解密之后得到明文之后還需要驗證數據完整性,在這里使用Hash函數來檢測。
•檢測成功之后再向客戶端返回數據表示匹配成功或者失敗
服務器代碼
import java.net.*;
import java.io.*;
import java.security.*;
import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.crypto.interfaces.*;
import java.security.interfaces.*;
import java.math.*;
public class ComputeTCPServer{
public static void main(String srgs[]) throws Exception
{
ServerSocket sc = null;
Socket socket=null;
try
{
sc= new ServerSocket(10001);//創建服務器套接字
System.out.println("端口號:" + sc.getLocalPort());
System.out.println("服務器已經啟動...");
socket = sc.accept(); //等待客戶端連接
System.out.println("已經建立連接");//獲得網絡輸入流對象的引用
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));//獲得網絡輸出流對象的引用
PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
//使用服務器端RSA的私鑰對DES的密鑰進行解密
String aline2=in.readLine();
BigInteger c=new BigInteger(aline2);
FileInputStream f=new FileInputStream("Skey_RSA_priv.dat");
ObjectInputStream b=new ObjectInputStream(f);
RSAPrivateKey prk=(RSAPrivateKey)b.readObject( );
BigInteger d=prk.getPrivateExponent();
BigInteger n=prk.getModulus();
BigInteger m=c.modPow(d,n);
byte[] keykb=m.toByteArray();
//使用DES對密文進行解密
String aline=in.readLine();//讀取客戶端傳送來的數據
byte[] ctext=parseHexStr2Byte(aline);
Key k=new SecretKeySpec(keykb,"DESede");
Cipher cp=Cipher.getInstance("DESede");
cp.init(Cipher.DECRYPT_MODE, k);
byte []ptext=cp.doFinal(ctext);
String p=new String(ptext,"UTF8");
System.out.println("從客戶端接收到信息為:"+p); //通過網絡輸出流返回結果給客戶端
//使用Hash函數檢測明文完整性
String aline3=in.readLine();
String x=p;
MessageDigest m2=MessageDigest.getInstance("MD5");
m2.update(x.getBytes( ));
byte a[ ]=m2.digest( );
String result="";
for (int i=0; i<a.length; i++)
{
result+=Integer.toHexString((0x000000ff & a[i]) |
0xffffff00).substring(6);
}
System.out.println(result);
if(aline3.equals(result))
{
System.out.println("匹配成功");
}
out.println("匹配成功");
out.close();
in.close();
sc.close();
} catch (Exception e) {
System.out.println(e);
}
}
//十六進制和十進制轉換
public static byte[] parseHexStr2Byte(String hexStr)
{
if (hexStr.length() < 1)
return null;
byte[] result = new byte[hexStr.length()/2];
for (int i = 0;i< hexStr.length()/2; i++)
{
int high = Integer.parseInt(hexStr.substring(i*2, i*2+1 ), 16);
int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
}
結果截圖
實驗中遇到的問題
•這是因為我們調用了RSA算法,但是沒有將對應文件放入,只要將Skey_RSA_pub.dat和Skey_RSA_priv.dat兩個文件放在和src同級目錄下就可以了。
感悟
這次實驗也是需要兩人一起組隊完成,一人負責服務器,一人負責客戶端。讓我們學習到了JAVA網絡編程的基本知識和操作,老師給出了代碼,我們要做的就是將這些復雜的代碼重新組裝、整合,然后用這些代碼完成實驗。這次JAVA的實際應用,收獲了許多。
PSP時間
步驟 | 耗時 | 百分比 |
---|---|---|
需求設計 | 30min | 30% |
設計 | 30min | 30% |
代碼實現 | 15min | 15% |
測試 | 15min | 15% |
分析總結 | 10min | 10% |