20172329 2017-2018-2 《程序設計與數據結構》實驗五報告

這是這學期最後一次實驗了,也是學到了不少東西,但願本身能夠能夠有始有終,加油! 讓咱們開始這一篇博客吧!php

20172329 2017-2018-2 《程序設計與數據結構》實驗五報告

課程:《程序設計與數據結構》
班級: 1723
姓名: 王文彬
學號:20172329
實驗教師:王志強
實驗日期:2018年6月11日
必修/選修: 必修html

一.實驗內容

一、網絡編程與安全-1java

  • 兩人一組結對編程:
  • a. 參考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA
  • b. 結對實現中綴表達式轉後綴表達式的功能 MyBC.java
  • c. 結對實現從上面功能中獲取的表達式中實現後綴表達式求值的功能,調用MyDC.java
  • d. 上傳測試代碼運行結果截圖和碼雲連接

二、網絡編程與安全-2web

  • 結對編程:1人負責客戶端,一人負責服務器
  • a. 注意責任歸宿,要會經過測試證實本身沒有問題
  • b. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
  • c. 客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式經過網絡發送給服務器
  • d. 服務器接收到後綴表達式,調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
  • e. 客戶端顯示服務器發送過來的結果
  • f. 上傳測試結果截圖和碼雲連接

三、網絡編程與安全-3算法

  • 加密結對編程:1人負責客戶端,一人負責服務器
  • a. 注意責任歸宿,要會經過測試證實本身沒有問題
  • b. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
  • c. 客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密後經過網絡把密文發送給服務器
  • d. 服務器接收到後綴表達式表達式後,進行解密(和客戶端協商密鑰,能夠用數組保存),而後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
  • e. 客戶端顯示服務器發送過來的結果
  • f. 上傳測試結果截圖和碼雲連接

四、網絡編程與安全-4編程

  • 密鑰分發結對編程:1人負責客戶端,一人負責服務器
  • a. 注意責任歸宿,要會經過測試證實本身沒有問題
  • b. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
  • c. 客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密經過網絡把密文發送給服務器
  • d. 客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
  • e. 服務器接收到後綴表達式表達式後,進行解密,而後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
  • f. 客戶端顯示服務器發送過來的結果
  • g. 上傳測試結果截圖和碼雲連接

五、網絡編程與安全-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)首先咱們進行對於題目的閱讀,是讓咱們實現以前已經實現的四則運算裏面的轉後綴式以及計算一個後綴式的值,雖然在婁老師的博客裏面給了兩個方法進行對於一箇中綴表達式轉化成一個後綴表達式,可是由於當咱們複製粘貼之後發現有一些代碼須要咱們去本身寫的時候,就去選擇了本身以前已經寫好的代碼進行對於實驗目標的實現。PS:後期對於婁老師代碼的理解後,發現婁老師的博客和咱們的差別不是很大,並且本身的代碼已經寫好了,因此,就沒有再作更換。
  • (2)如今就來講一下具體實現的過程,雖然在以前的四則運算的結對編程裏面有所體現,可是在這裏仍是再作敘述。
  • first:這一步是將一箇中綴轉後綴的一個過程代碼
  • second:這一步是將一個後綴式計算出的代碼

結果:服務器

  • third:最後將其進行計算結果以及中綴轉後綴的測試

二、網絡編程與安全-2網絡

  • (1)首先由於是第一次學習而且運用Java Socket實現客戶端/服務器功能,傳輸方式用TCP進行實驗,所以一開始老師給咱們兩個客戶端和服務器的代碼示例,這一個實驗說是進行代碼編寫不如說是進行代碼的補充和修改。首先這一個實驗任務就是先構建一個服務器和客戶端的鏈接,而後客戶端將一個已經轉爲後綴式的中綴表達式傳給服務器,而後服務器接收到這個中綴表達式,進行計算,經過網絡編程與安全-1的實驗代碼進行計算的實現。
  • (2)接下來具體來說一講實驗的實現:

1、客戶端

  • first:經過這樣一段代碼,將創建與服務器的鏈接
//1.創建客戶端Socket鏈接,指定服務器位置和端口
         Socket socket = new Socket("127.0.0.1",8880);

        //2.獲得socket讀寫流
        OutputStream outputStream = socket.getOutputStream();
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
        //輸入流
        InputStream inputStream = socket.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
  • second:經過一系列中綴表達式轉爲後綴表達式
//3.利用流按照必定的操做,對socket進行讀寫操做
        Scanner scan = new Scanner(System.in);
        System.out.println("我輸入的中綴表達式爲: ");
        String a =scan.nextLine();
        Calculate p =new Calculate();
        String temp = "";
        for (int x = 0; x < p.parse(p.zb(a)).size(); ++x) {
            temp = temp + p.parse(p.zb(a)).get(x);
        }


        String info1 = temp;
        String info = new String(info1.getBytes("GBK"),"utf-8");


        outputStreamWriter.write(info);
        outputStreamWriter.flush();
        socket.shutdownOutput();
  • third:接受到服務器的信息
//接收服務器的響應
        String reply = null;
        while (!((reply = bufferedReader.readLine()) ==null)){
            System.out.println("接收服務器的信息爲:" + reply);
        }

2、服務器

  • first:這一步將創建一個服務器,而且準備接受來自客戶端的信息
//1.創建一個服務器Socket(ServerSocket)綁定指定端口
        ServerSocket serverSocket=new ServerSocket(8880);
        //2.使用accept()方法阻止等待監聽,得到新鏈接
        Socket socket=serverSocket.accept();
        //3.得到輸入流
        InputStream inputStream=socket.getInputStream();
        BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
        //得到輸出流
        OutputStream outputStream=socket.getOutputStream();
        PrintWriter printWriter=new PrintWriter(outputStream);
        //4.讀取用戶輸入信息
        String info=null;
        while(!((info = bufferedReader.readLine()) ==null)){
            System.out.println("我是服務器,用戶信息爲:" + info);
  • second:接下來開始對於接受到的信息進行處理,也就是要開始對於接收到的後綴表達式要開始計算,而且將計算出的答案傳給客戶端
//給客戶一個響應
        Calculate a = new Calculate();
        String str=info;
        String[] temp = str.split(" ");

        List<String> ls= Arrays.asList(temp);
        String reply=String.valueOf(a.suanshu(ls));
        printWriter.write(reply);
        printWriter.flush();}

結果:

  • 客戶端:
  • 服務器:

三、網絡編程與安全-3

  • (1)在這一個實驗中,咱們須要用到以前已經學習過的Java與密碼學的練習那一個實驗的相關知識,首先咱們須要去溫習一下加密算法有哪些類型,在以前咱們瞭解過的有這樣幾種:3DES、AES、RSA、凱撒密碼,MD5以及一個DH密鑰交換協議的學習,在接下來的實驗中,咱們要依次運用到以上的相關知識。此次試驗的目的是客戶端須要將一個已經造成好的後綴表達式進行加密,而後傳遞給服務器將其進行解密,而後將解出來的後綴式進行計算。
  • (2)具體來說:

客戶端:

  • first:利用這兩個類進行生成密鑰
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]+",");
        }
    }
}
  • second:進行加密
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[]=s.getBytes("UTF8");
        for(int i=0;i<ptext.length;i++){
            System.out.print(ptext[i]+",");
        }
        System.out.println("");
        byte ctext[]=cp.doFinal(ptext);
        String a="";
        for(int i=0;i<ctext.length;i++){
            a+=ctext[i] +",";
            //    System.out.print(a);
        }
        FileOutputStream f2=new FileOutputStream("SEnc.dat");
        f2.write(ctext);
        return a;

服務器:

  • third:進行解密
FileInputStream  f2=new FileInputStream("keykb1.dat");
            int num2=f2.available();
            byte[ ] keykb=new byte[num2];
            f2.read(keykb);
            SecretKeySpec 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");

結果:

  • 客戶端:
  • 服務器:

四、網絡編程與安全-4

  • (1)這一部分的實驗要求咱們須要生成新的密鑰從而進行加密和解密的過程,而這個產生新密鑰的過程就是須要用到咱們以前學到的DH交換密鑰協議,這裏先說一下我對於DH算法的理解:
  • 首先,就雙方而言,咱們須要去傳遞咱們想要的密文就須要一個密鑰,可是咱們想要增強安全性,所以就產生了DH算法,它的流程是這樣的:A方會產生一個公鑰和私鑰,這裏咱們簡稱爲公A和私A,B方會產生一個公鑰和一個私鑰,這裏簡稱爲公B和私B,咱們須要交換的是兩個公鑰,從而能夠利用咱們本身的公鑰和對方的私鑰產生一個新的密鑰,這個密鑰就是咱們須要的共享密鑰,咱們須要用這個密鑰進行對於明文的加密和解密。
    能夠結合這個圖進行理解
  • (2)具體分析:
  • first:進行新密鑰的生成,進行從"Bpub.dat","Apri.dat"讀取文檔,從而生成共享信息,而後進行加密
    客戶端:
FileInputStream f1=new FileInputStream("Bpub.dat");
        ObjectInputStream b1=new ObjectInputStream(f1);
        PublicKey pbk=(PublicKey)b1.readObject( );
//讀取本身的DH私鑰
        FileInputStream f3=new FileInputStream("Apri.dat");
        ObjectInputStream b2=new ObjectInputStream(f3);
        PrivateKey prk=(PrivateKey)b2.readObject();
        // 執行密鑰協定
        KeyAgreement ka=KeyAgreement.getInstance("DH");
        ka.init(prk);
        ka.doPhase(pbk,true);
        //生成共享信息
        byte[ ] sb=ka.generateSecret();
        SecretKeySpec k = new SecretKeySpec(sb, 0,24,"DESede");
        Cipher cp=Cipher.getInstance("DESede");
        cp.init(Cipher.ENCRYPT_MODE, k);
        byte ptext[]=s.getBytes("UTF8");
        byte ctext[]=cp.doFinal(ptext);
        String a="";
        for(int i=0;i<ctext.length;i++){
            a+=ctext[i] +",";
            //    System.out.print(a);
        }
        FileOutputStream f2=new FileOutputStream("SEnc.dat");
        f2.write(ctext);
        return a;
  • second:進行解密
    服務器:
FileInputStream f1=new FileInputStream("Apub.dat");
        ObjectInputStream b1=new ObjectInputStream(f1);
        PublicKey pbk=(PublicKey)b1.readObject( );
//讀取本身的DH私鑰
        FileInputStream f2=new FileInputStream("Bpri.dat");
        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();
        SecretKeySpec k=new  SecretKeySpec(sb,0,24,"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);

結果:

五、網絡編程與安全-5

  • (1)第五個實驗是關於MD5關於Java的摘要算法
  • (2)具體實現:
  • first:計算明文的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;
    }
  • second:進行對比,若是同樣,則計算,不同則拋出異常
DigestPass ooo=new DigestPass();
        String reply;
        if (ww.equals(ooo.Diget(p)))

        {
           reply= String.valueOf(a.suanshu(ls));
        }
        else {
            reply="返回的MD5值不一樣";
        }

結果:

  • 客戶端:
  • 服務器:

三. 實驗過程當中遇到的問題和解決過程

  • 問題1:在作第三個實驗的時候,就到底如何傳給服務器密鑰你們產生了很大的分歧,不少人認爲須要用像是傳遞原文的方式進行,有些人認爲應該用文件直接拷貝過去就能夠
  • 問題1解答:我認爲兩種方式均可以。
  • 首先咱們先分析第一種方法,也就是經過傳遞原文的方式將其傳遞過去,可是這裏就會有問題,由於,咱們不清楚究竟是如何去傳遞兩個東西,咱們並無被要求去用雙線程,何況咱們也沒有那麼厲害,所以經過和餘坤澎同窗的討論,咱們能夠用這個方法進行將兩個東西傳遞過去,舉個例子:假如咱們如今要傳遞字符串A和字符串B,可是咱們怎麼把兩個東西一塊兒傳遞過去呢,首先咱們想到,就字符串有一個split的方法,咱們能夠利用這個方法把這兩個字符串用一個字符進行切分,而後分別保存,好比「String aa =A;B」,咱們用String []bb =aa.split";";就能夠將其分紅bb[0]bb[1]這樣就把兩個東西都傳遞過去了。
  • 其次就是第二種方式,我相信第二種方式不用太過去強調,我認爲是我的應該都會的,並且最開始想到的辦法確定也是這一種方法。

  • 問題2:在服務器接受到的info老是空指針這問題
  • 問題2解決方案:

String info=null;
        String str1="";
        while(!((info = bufferedReader.readLine()) ==null)){
            System.out.println("我是服務器,用戶信息爲:" + info);
            str1=info;}
String info=null;
        while(!((info = bufferedReader.readLine()) ==null)){
            System.out.println("我是服務器,用戶信息爲:" + info);
            }

咱們須要區分這兩個代碼的區別,運用第二個會出現報錯,出現空指針,由於第二個代碼的info是直到它爲空纔會跳出這個循環,天然會拋出空指針的異常。

  • 問題3:在作到第四個實驗的時候,有一個問題卡了我好久,就是密鑰長度的問題
  • 問題3解決方案:
  • 由於一開始我查了爲何是這個問題,就是由於生成的密鑰長度不符合3DES的要求,所以就會致使這個問題,咱們知道3DES的密鑰長度要求是8的倍數,而且在咱們這個實驗裏DESede須要的是24位,可是咱們獲得的共享密鑰是128位的因此它會冒出密鑰長度的問題,在這裏先感謝張旭升學長對個人幫助,解決方法就在這一句SecretKeySpec k =new SecretKeySpec(sb,"DESede");能夠實現,首先咱們的目的是想要把那個128的密鑰只取24位,所以咱們查找了API文檔
    看了看這句話的參數有什麼,其中就有控制範圍:

    將語句變成SecretKeySpec k=new SecretKeySpec(sb,0,24,"DESede");,問題也就能夠解決了。

其餘(感悟、思考等)

這一學期立刻就要結束了,不少人如今也都已經開始放飛自我了,端午這三天,本身決定本身的收穫仍是很是大的,最近的幾回編程,我以爲我學習Java的熱情又回來了,而後我發現API真是個好東西,就像一本字典同樣,並且講解的都很是詳細,但願本身能夠堅持下去,本身立的flag,必定要作到!

參考資料

藍墨雲班課
2016-2017-2 《Java 程序設計》課堂實踐項目
Java 密碼學算法
JAVA加解密DH算法
3DES自定義密鑰問題
JAVA實現DES加密實現詳解
多線程方式實現Socket通訊
TCP

相關文章
相關標籤/搜索