20172321 2017-2018-2 《程序設計與數據結構》實驗五報告
20172321 2017-2018-2 《程序設計與數據結構》實驗五報告
課程:《程序設計與數據結構》
班級: 1723
姓名: 吳恒佚
學號:20172321
實驗教師:王誌強
實驗日期:2018年6月13日~2018年6月18日
必修/選修: 必修
一、實驗內容
1、網絡編程與安全-1
- 兩人一組結對編程:
- a. 參考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA
- b. 結對實現中綴表達式轉後綴表達式的功能 MyBC.java
- c. 結對實現從上面功能中獲取的表達式中實現後綴表達式求值的功能,調用MyDC.java
- d. 上傳測試代碼運行結果截圖和碼雲鏈接
2、網絡編程與安全-2
- 結對編程:1人負責客戶端,一人負責服務器
- a. 註意責任歸宿,要會通過測試證明自己沒有問題
- b. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
- c. 客戶端讓用戶輸入中綴表達式,然後把中綴表達式調用MyBC.java的功能轉化為後綴表達式,把後綴表達式通過網絡發送給服務器
- d. 服務器接收到後綴表達式,調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
- e. 客戶端顯示服務器發送過來的結果
- f. 上傳測試結果截圖和碼雲鏈接
3、網絡編程與安全-3
- 加密結對編程:1人負責客戶端,一人負責服務器
- a. 註意責任歸宿,要會通過測試證明自己沒有問題
- b. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
- c. 客戶端讓用戶輸入中綴表達式,然後把中綴表達式調用MyBC.java的功能轉化為後綴表達式,把後綴表達式用3DES或AES算法加密後通過網絡把密文發送給服務器
- d. 服務器接收到後綴表達式表達式後,進行解密(和客戶端協商密鑰,可以用數組保存),然後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
- e. 客戶端顯示服務器發送過來的結果
- f. 上傳測試結果截圖和碼雲鏈接
4、網絡編程與安全-4
- 密鑰分發結對編程:1人負責客戶端,一人負責服務器
- a. 註意責任歸宿,要會通過測試證明自己沒有問題
- b. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
- c. 客戶端讓用戶輸入中綴表達式,然後把中綴表達式調用MyBC.java的功能轉化為後綴表達式,把後綴表達式用3DES或AES算法加密通過網絡把密文發送給服務器
- d. 客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
- e. 服務器接收到後綴表達式表達式後,進行解密,然後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
- f. 客戶端顯示服務器發送過來的結果
- g. 上傳測試結果截圖和碼雲鏈接
5、網絡編程與安全-5
- 完整性校驗結對編程:1人負責客戶端,一人負責服務器
- a. 註意責任歸宿,要會通過測試證明自己沒有問題
- b. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
- c. 客戶端讓用戶輸入中綴表達式,然後把中綴表達式調用MyBC.java的功能轉化為後綴表達式,把後綴表達式用3DES或AES算法加密通過網絡把密文和明文的MD5値發送給服務器
- d. 客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
- e. 服務器接收到後綴表達式表達式後,進行解密,解密後計算明文的MD5值,和客戶端傳來的MD5進行比較,一致則調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
- f. 客戶端顯示服務器發送過來的結果
- g. 上傳測試結果截圖和碼雲鏈接
二、實驗過程及結果
1、網絡編程與安全-1
- 首先,第一個節點是讓我們實現之前已經實現的四則運算裏面的轉後綴式以及計算一個後綴式的值,雖然在婁老師的博客裏面給了兩個方法進行對於一個中綴表達式轉化成一個後綴表達式,但是據說這兩個代碼不是完全體,所以我們還是決定去使用了自己之前已經寫好的代碼進行對於實驗目標的實現。
- 因為這個步驟基本上只是重復一遍四則運算的步驟,所以不多做敘述。
- 結果
2、網絡編程與安全-2
- 因為是第一次學習並且使用Java Socket實現客戶端/服務器功能,傳輸方式用TCP進行實驗,因此一開始老師給我們兩個客戶端和服務器的示意代碼,所以這一個實驗與其說是進行代碼編寫不如說是進行代碼的補充和修改。首先這一個實驗任務就是先構建一個服務器和客戶端的連接,然後客戶端將一個已經轉為後綴式的中綴表達式傳給服務器,然後服務器接收到這個中綴表達式,進行計算,通過網絡編程與安全-1的實驗代碼進行計算的實現。
- 因為服務器和客戶端的示範代碼已經給我們了,這一步也只是稍做修改,再補充上中綴表達式的轉換和計算功能,再讓後綴表達式和答案可以在服務器和客戶端上交流就可以了。
- 客戶端
首先,把這個地方改成自己要鏈接的服務器地址
//1.建立客戶端Socket連接,指定服務器位置和端口 //Socket socket = new Socket("localhost",8080); Socket socket = new Socket("192.168.1.113", 8800);
然後加上輸入中綴表達式的代碼和之前已有的轉換為後綴的方法
String infix; System.out.println("輸入你想計算的中綴表達式(不需要輸入空格,enter鍵結束輸入):"); Scanner scan = new Scanner(System.in); infix = scan.nextLine(); String postfix, buzhou; MyBC theTrans = new MyBC(infix); postfix = theTrans.doTrans();
- 最後傳輸和接收的代碼是示範代碼自帶的
- 服務器
- 接收和回傳的代碼也是已有的
把後綴表達式計算出來就可以了
String expressions; MyDC evaluator = new MyDC(); expressions = info; result = evaluator.evaluate(expressions);
- 結果
3、網絡編程與安全-3
- 在這一個實驗中,我們必須需要用到之前已經學習過的Java與密碼學的練習那一個實驗的相關知識,
我們不得不去溫習一下加密算法有哪些類型,在之前我們粗略的了解過的有這樣幾種:3DES、AES、RSA,MD5以及一個DH密鑰交換協議的學習,在接下來的實驗中,我們要依次運用到以上的相關知識。 - 這次試驗的目的是客戶端需要輸入一個中綴表達式,將它轉換成一個後綴表達式並且進行加密,然後傳遞給服務器,服務器將其進行解密,然後將解出來的後綴式進行計算並回傳。
要用到之前實驗的兩個類
public class Skey_DES{ public static void main(String args[]) throws Exception{ KeyGenerator kg=KeyGenerator.getInstance("DESede"); kg.init(168); SecretKey k=kg.generateKey( ); FileOutputStream f=new FileOutputStream("key1.dat"); ObjectOutputStream b=new ObjectOutputStream(f); b.writeObject(k); } }
public class Skey_kb{ public static void main(String args[]) throws Exception{ FileInputStream f=new FileInputStream("key1.dat"); ObjectInputStream b=new ObjectInputStream(f); Key k=(Key)b.readObject( ); byte[ ] kb=k.getEncoded( ); FileOutputStream f2=new FileOutputStream("keykb1.dat"); f2.write(kb); // 打印密鑰編碼中的內容 for(int i=0;i<kb.length;i++){ System.out.print(kb[i]+","); } } }
客戶端進行加密
```
FileInputStream f = new FileInputStream("key1.dat");
ObjectInputStream b = new ObjectInputStream(f);
Key k = (Key) b.readObject();
Cipher cp = Cipher.getInstance("DESede");
cp.init(Cipher.ENCRYPT_MODE, k);
byte ptext[] = postfix.getBytes("UTF8");
System.out.print("加密後綴表達式:");
for (int i = 0; i < ptext.length; i++) {
System.out.print(ptext[i] + ",");
}
System.out.println("");
byte ctext[] = cp.doFinal(ptext);//進行加密。
String aa = "";
for (int i = 0; i < ctext.length; i++) {
aa += ctext[i] + ",";
}
String info3 = aa;String info = new String(info3.getBytes("GBK"), "utf-8"); ```
服務器解密
FileInputStream f3 = new FileInputStream("keykb1.dat"); int num2 = f3.available(); byte[] keykb = new byte[num2]; f3.read(keykb); SecretKeySpec k = new SecretKeySpec(keykb, "DESede"); // 解密 Cipher cp = Cipher.getInstance("DESede"); cp.init(Cipher.DECRYPT_MODE, k); byte[] ptext = cp.doFinal(ab); // 顯示明文 String p = new String(ptext, "UTF8"); System.out.println("解密的後綴表達式:" + p);
結果
4、網絡編程與安全-4
這一部分的實驗要求我們需要生成新的密鑰從而進行加密和解密的過程,而這個產生新密鑰的過程就是需要用到我們之前學到的DH交換密鑰協議,這裏先說一下我對於DH算法的理解:
由於DH算法需要A和B二人各自生成DH公鑰和私鑰,因此在這兩個人都在自己的目錄下都拷貝編譯後文件Key_DH。
首先由A創建自己的公鑰和私鑰,即A進行“java Key_DH Apub.dat Apri.dat”運行程序,這時在目錄下將產生文件Apub.dat和Apri.dat,前者保存著A的公鑰,後者保存著A的私鑰。
然後由B創建自己的公鑰和私鑰,即B進行“java Key_DH Bpub.dat Bpri.dat”運行程序,這時在目錄B下將產生文件Bpub.dat和Bpri.dat,前者保存著B的公鑰,後者保存著B的私鑰。
最後發布公鑰,將Apub.dat拷貝到B的目錄,將Bpub.dat拷貝到A的目錄。
這樣,A、B雙方的DH公鑰和私鑰已經創建並部署完畢。
需要用到這兩個類
import javax.crypto.KeyAgreement; import javax.crypto.spec.SecretKeySpec; import java.io.FileInputStream; import java.io.ObjectInputStream; import java.security.PrivateKey; import java.security.PublicKey; public class KeyAgree { public static void main(String args[]) throws Exception { // 讀取對方的DH公鑰 FileInputStream f1 = new FileInputStream(args[0]); ObjectInputStream b1 = new ObjectInputStream(f1); PublicKey pbk = (PublicKey) b1.readObject(); //讀取自己的DH私鑰 FileInputStream f2 = new FileInputStream(args[1]); ObjectInputStream b2 = new ObjectInputStream(f2); PrivateKey prk = (PrivateKey) b2.readObject(); // 執行密鑰協定 KeyAgreement ka = KeyAgreement.getInstance("DH"); ka.init(prk); ka.doPhase(pbk, true); //生成共享信息 byte[] sb = ka.generateSecret(); for (int i = 0; i < sb.length; i++) { System.out.print(sb[i] + ","); } SecretKeySpec k = new SecretKeySpec(sb, "DESede"); } }
import javax.crypto.spec.DHParameterSpec; import java.io.FileOutputStream; import java.io.ObjectOutputStream; import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; public class Key_DH { //三個靜態變量的定義從 // C:\j2sdk-1_4_0-doc\docs\guide\security\jce\JCERefGuide.html // 拷貝而來 // The 1024 bit Diffie-Hellman modulus values used by SKIP private static final byte skip1024ModulusBytes[] = { (byte) 0xF4, (byte) 0x88, (byte) 0xFD, (byte) 0x58, (byte) 0x4E, (byte) 0x49, (byte) 0xDB, (byte) 0xCD, (byte) 0x20, (byte) 0xB4, (byte) 0x9D, (byte) 0xE4, (byte) 0x91, (byte) 0x07, (byte) 0x36, (byte) 0x6B, (byte) 0x33, (byte) 0x6C, (byte) 0x38, (byte) 0x0D, (byte) 0x45, (byte) 0x1D, (byte) 0x0F, (byte) 0x7C, (byte) 0x88, (byte) 0xB3, (byte) 0x1C, (byte) 0x7C, (byte) 0x5B, (byte) 0x2D, (byte) 0x8E, (byte) 0xF6, (byte) 0xF3, (byte) 0xC9, (byte) 0x23, (byte) 0xC0, (byte) 0x43, (byte) 0xF0, (byte) 0xA5, (byte) 0x5B, (byte) 0x18, (byte) 0x8D, (byte) 0x8E, (byte) 0xBB, (byte) 0x55, (byte) 0x8C, (byte) 0xB8, (byte) 0x5D, (byte) 0x38, (byte) 0xD3, (byte) 0x34, (byte) 0xFD, (byte) 0x7C, (byte) 0x17, (byte) 0x57, (byte) 0x43, (byte) 0xA3, (byte) 0x1D, (byte) 0x18, (byte) 0x6C, (byte) 0xDE, (byte) 0x33, (byte) 0x21, (byte) 0x2C, (byte) 0xB5, (byte) 0x2A, (byte) 0xFF, (byte) 0x3C, (byte) 0xE1, (byte) 0xB1, (byte) 0x29, (byte) 0x40, (byte) 0x18, (byte) 0x11, (byte) 0x8D, (byte) 0x7C, (byte) 0x84, (byte) 0xA7, (byte) 0x0A, (byte) 0x72, (byte) 0xD6, (byte) 0x86, (byte) 0xC4, (byte) 0x03, (byte) 0x19, (byte) 0xC8, (byte) 0x07, (byte) 0x29, (byte) 0x7A, (byte) 0xCA, (byte) 0x95, (byte) 0x0C, (byte) 0xD9, (byte) 0x96, (byte) 0x9F, (byte) 0xAB, (byte) 0xD0, (byte) 0x0A, (byte) 0x50, (byte) 0x9B, (byte) 0x02, (byte) 0x46, (byte) 0xD3, (byte) 0x08, (byte) 0x3D, (byte) 0x66, (byte) 0xA4, (byte) 0x5D, (byte) 0x41, (byte) 0x9F, (byte) 0x9C, (byte) 0x7C, (byte) 0xBD, (byte) 0x89, (byte) 0x4B, (byte) 0x22, (byte) 0x19, (byte) 0x26, (byte) 0xBA, (byte) 0xAB, (byte) 0xA2, (byte) 0x5E, (byte) 0xC3, (byte) 0x55, (byte) 0xE9, (byte) 0x2F, (byte) 0x78, (byte) 0xC7 }; // The SKIP 1024 bit modulus private static final BigInteger skip1024Modulus = new BigInteger(1, skip1024ModulusBytes); // The base used with the SKIP 1024 bit modulus private static final BigInteger skip1024Base = BigInteger.valueOf(2); public static void main(String args[]) throws Exception { DHParameterSpec DHP = new DHParameterSpec(skip1024Modulus, skip1024Base); KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH"); kpg.initialize(DHP); KeyPair kp = kpg.genKeyPair(); PublicKey pbk = kp.getPublic(); PrivateKey prk = kp.getPrivate(); // 保存公鑰 FileOutputStream f1 = new FileOutputStream(args[0]); ObjectOutputStream b1 = new ObjectOutputStream(f1); b1.writeObject(pbk); // 保存私鑰 FileOutputStream f2 = new FileOutputStream(args[1]); ObjectOutputStream b2 = new ObjectOutputStream(f2); b2.writeObject(prk); } }
結果
5、網絡編程與安全-5
- 第五個實驗是關於MD5關於Java的摘要算法
計算明文的MD5值
public String Diget(String x) throws UnsupportedEncodingException, NoSuchAlgorithmException { MessageDigest m=MessageDigest.getInstance("MD5"); m.update(x.getBytes("UTF8")); byte s[ ]=m.digest( ); String result=""; for (int i=0; i<s.length; i++){ result+=Integer.toHexString((0x000000ff & s[i]) | 0xffffff00).substring(6); } return result; }
進行對比,如果一樣,則計算,不一樣則拋出異常
DigestPass ooo=new DigestPass(); String reply; if (ww.equals(ooo.Diget(p))) { reply= String.valueOf(a.suanshu(ls)); } else { reply="返回的MD5值不同"; }
結果
三、實驗過程中遇到的問題和解決過程
- 在進行實驗5-3的時候,我先在自己的電腦上進行了實驗,加完密之後總顯示找不到文件,後來我試著調了一下,然後就找不到主類了,但是我沒有放棄,繼續堅持調試,終於所有程序運行的結果都是亂碼了。
- 於是我決定尋找幫助,學長先試著看了一下我的設置,覺得沒什麽問題,最後他開始百度了,發現應該這樣:打開IntelliJ IDEA 14.0安裝路徑,小編的安裝路徑為:D:\Program Files\JetBrains\IntelliJ IDEA 14.0\bin 找到idea.exe.vmoptions 文件,用記事本打開,在最後一行填加:“-Dfile.encoding=UTF-8”,如圖所示,保存。終於解決了問題,嘿嘿嘿。
- 在進行實驗5-4的時候,我和我親愛的隊友在各自的電腦上同時研究服務器和客戶端,我們自己向自己進行傳輸回傳都很順利,但是我們倆相互傳輸就會出錯,後來發現我們當時沒有註意到我們自己進行是是建立兩個目錄A和B,模擬需要秘密通信的A、B雙方,我們兩個沒有用對方的公鑰生成密匙,所以不能解密。
- 我們在創建共享密鑰的時候思路比較混亂,還出來錯誤,然後正好學長註意到了我們,幫我們調試了一番,不過因此我們互換了服務器和客戶端的位置,還出了一個小插曲,後來發現是因為我自己修改了後綴表達式的類,但是她沒改,就有一些不匹配了。
四、其他(感悟、思考等)
光陰似箭、歲月如梭,時間如白馬過隙一去不返,細碎的時光從我們敲打鍵盤的之間流過。。。簡而言之,這一學期就要結束了,世界杯也開始了,但是,我們絕對不能放棄學習Java,一定要堅持,差不多就醬。
五、參考資料
- 藍墨雲班課
- Java 密碼學算法
- 解決IDEA控制臺亂碼
20172321 2017-2018-2 《程序設計與數據結構》實驗五報告