2018-2019-20175205 實驗五《網絡編程與安全》實驗報告

2018-2019-20175205 實驗五《網絡編程與安全》實驗報告

[TOC]html

實驗步驟

任務一

  • 兩人一組結對編程
  • 結對實現中綴表達式轉後綴表達式的功能 MyBC.java
  • 結對實現從上面功能中獲取的表達式中實現後綴表達式求值的功能,調用MyDC.java

實驗過程

  • 以前結隊編程作過同樣的題目,因此就肥腸簡單啦java

  • 爲何要將中綴表達式轉爲後綴表達式算法

    • 中綴表達式,雖然符合咱們的數學計算習慣,可是並不符合計算機運算的方式
    • 後綴表達式嚴格按照從左到右進行計算的模式 符合計算機運行方式
    • 而中綴表達式須要計算機遇到符號後向後掃描一位 若爲括號或優先級更高的操做符還須要向後繼續掃描
  • 後綴表達式的定義編程

    • 後綴表達式(又稱爲逆波蘭reverse polish)就是不須要括號就能夠實現調整運算順序的一種技法。
    • 好比:ab+cde+**,改成中綴表達式實際上是(a+b)*((d+e)*c)
    • 後綴表達式不含括號
  • 中綴轉後綴數組

    • 重要的數據結構----
    • 若是讀入操做數,則直接放入輸出字符串;
    • 若是讀入通常運算符如+-*/,則放入堆棧,可是放入堆棧以前必需要檢查棧頂,並肯定棧頂運算符的優先級比放入的運算符的優先級低;若是放入的優先級較低,則須要將棧頂的運算符放入輸出字符串
    • 若是讀入(,由於左括號優先級最高,所以放入棧中,可是注意,當左括號放入棧中後,則優先級最低
    • 若是讀入),則將棧中運算符取出放入輸出字符串,直到取出(爲止,注意:()不輸出到輸出字符串
    • 順序讀完表達式,若是棧中還有操做符,則彈出,並放入輸出字符串
  • 後綴表達式的計算安全

    • 從左到右掃描後綴表達式
    • 若是遇到操做數,將其壓入棧中
    • 若是遇到操做符,則從棧中彈出兩個操做數,計算結果
    • 而後把結果入棧
    • 直到遍歷完後綴表達式,則計算完成
    • 此時的棧頂元素即爲計算結果。

實驗代碼

  • 中綴轉後綴
import java.util.Stack;

public class MyBC {
    MyBC(){}
    public static String infixToSuffix(String exp){
        Stack<String> s = new Stack<String>();         // 建立操做符堆棧
        String suffix = "";            // 要輸出的後綴表達式字符串
        String suffix1 = "";             //上一次的後綴表達式
        String suffix2 = "";
        String str[] = exp.split(" ");
        int length = str.length; // 輸入的中綴表達式的長度
        String temp="";
        for (int i = 0; i < length; i++) {            // 對該中綴表達式的每個字符並進行判斷
            switch (str[i]) {
                case " ":break;           // 忽略空格
                case "(":
                    s.push(str[i]);                  // 若是是左括號直接壓入堆棧
                    break;
                case "+":
                case "-":
                    if(s.size() != 0){          // 碰到'+' '-',將棧中的全部運算符所有彈出去,直至碰到左括號爲止,輸出到隊列中去
                        temp = s.pop();
                        if (temp.equals("(")) {     // 將左括號放回堆棧,終止循環
                            s.push(temp);
                            s.push(str[i]);
                            break;
                        }
                        else{
                            s.push(str[i]);
                            suffix2 = suffix2 + temp + " ";
                            break;
                        }
                    }
                    else{
                        s.push(str[i]);      // 說明是當前爲第一次進入或者其餘前面運算都有括號等狀況致使棧已經爲空,此時須要將符號進棧
                        break;
                    }
                    // 若是是乘號或者除號,則彈出全部序列,直到碰到加好、減號、左括號爲止,最後將該操做符壓入堆棧
                case "*":
                case "÷":
                    if(s.size()!=0){
                        temp = s.pop();
                        if(temp.equals("+")||temp.equals("-")||temp.equals("(")){
                            s.push(temp);
                            s.push(str[i]);
                            break;
                        }
                        else{
                            s.push(str[i]);
                            suffix2 = suffix2+temp+" ";
                            break;
                        }
                    }
                    else {
                        s.push(str[i]);     //當前爲第一次進入或者其餘前面運算都有括號等狀況致使棧已經爲空,此時須要將符號進棧
                        break;
                    }
                    // 若是碰到的是右括號,則距離棧頂的第一個左括號上面的全部運算符彈出棧並拋棄左括號
                case ")":
                    while (!s.isEmpty()) {
                        temp = s.pop();
                        if (temp.equals("(")) {
                            break;
                        } else {
                            suffix2 = suffix2+temp+" ";
                        }
                    }
                    break;
                // 默認狀況,若是讀取到的是數字,則直接送至輸出序列
                default:
                    suffix2 = suffix2+str[i]+" ";
                    break;
            }

        }
        // 若是堆棧不爲空,則把剩餘運算符一次彈出,送至輸出序列
        while (s.size() != 0) {
            suffix2 = suffix2+s.pop()+" ";
        }
        if(suffix1.equals("")){          //第一個題目
            suffix1 = suffix2;
            suffix = suffix2;
        }
        else{
            if(suffix2.equals(suffix1))
                suffix = "";
            else
                suffix = suffix2;
        }
        suffix1 = suffix2;
        return suffix;
    }
}

實驗結果

任務二

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

實驗過程

  • 首先固然要知道本身本機的IP地址服務器

    • 使用InetAddress類的靜態方法getLocalHost()得到一個InetAddress的對象,該對象含有本地機器的IP地址
  • 套接字網絡

    • 兩個程序須要通訊時,經過Socket類創建套接字對象並鏈接在一塊兒
  • 客戶端套接字數據結構

    • Socket clientSocket = new Socket("服務器的IP地址",一個端口號)
    • 可能發生IOException異常
    • 使用方法getInputStream()得到一個輸入流
    • 使用方法getOutputStream()得到一個輸出流
  • SeverSocket對象與服務器端套接字socket

    • SeverSocket severForClient = new SeverSocket(端口號)
    • 當端口被佔用時,會發生IOException異常
    • 使用accept()方法將客戶端和服務器的套接字鏈接起來
      • Socket sc = severForClient.accept()
    • sc調用方法getInputStream()得到一個輸入流
    • sc調用方法getOutputStream()得到一個輸出流
  • 使用close()關閉套接字連接

實驗代碼

  • 獲取本機的地址
import java.net.*;
public class getHostAddress {
    public static void main(String[] args) {
        try{
            InetAddress hostaddress = InetAddress.getLocalHost();
            System.out.println(hostaddress.toString());
        }catch (UnknownHostException e){
            System.out.println(e);
        }
    }
}
  • 客戶端
import java.io.*;
import java.net.*;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) {
        Scanner inn = new Scanner(System.in);
        Socket mysocket;
        DataInputStream in = null;
        DataOutputStream out = null;
        try{
            mysocket = new Socket("172.30.1.177",2010);
            in = new DataInputStream(mysocket.getInputStream());
            out = new DataOutputStream(mysocket.getOutputStream());
            System.out.println("請輸入中綴表達式:");
            String infix = inn.nextLine();
            String suffix = MyBC.infixToSuffix(infix);
            out.writeUTF(suffix);
            String result = in.readUTF();
            System.out.println("小猴收到胖礫的回答"+result);
            Thread.sleep(500);
        }catch (Exception e){
            System.out.println("胖礫又去吃飯了"+e);
        }
    }
}
  • 服務器端
import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils;
import java.io.*;
import java.net.*;
public class Sever {
    public static void main(String[] args) {
        ServerSocket serverForClient = null;
        Socket socketOnServer = null;
        DataOutputStream out = null;
        DataInputStream in = null;
        MyDC myDC = new MyDC();
        try{
            serverForClient = new ServerSocket(2010);
        }catch (IOException e1){
            System.out.println("我是豬,我又餓了"+e1);
        }
        try{
            System.out.println("等待小猴投喂");
            socketOnServer = serverForClient.accept();
            out = new DataOutputStream(socketOnServer.getOutputStream());
            in = new DataInputStream(socketOnServer.getInputStream());
            String suffix = in.readUTF();
            System.out.println("胖礫收到小猴的提問"+suffix);
            out.writeUTF(myDC.evaluate(suffix)+"");
            Thread.sleep(500);
        }catch (Exception e){
            System.out.println("小猴已斷開鏈接");
        }
    }
}

實驗結果

  • 獲取本機地址

  • 客戶端

  • 服務器端

任務三

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

實驗過程

  • DES密鑰

    • 獲取密鑰生成器,KeyGenerator kg=KeyGenerator.getInstance("DESede")
    • 初始化密鑰生成器,kg.init(168)
    • 生成密鑰,SecretKey k=kg.generateKey( )
  • DES密鑰編碼內容

    • 獲取主要編碼格式
      • byte[ ] kb=k.getEncoded( )
  • 傳送祕鑰的長度,out.writeUTF(kb.length+"")

  • 傳送密鑰內容

for(int i=0; i<kb.length; i++){
       out.writeUTF(kb[i]+"");
}
  • 客戶端DES加密

    • 建立密碼器
      • Cipher cp=Cipher.getInstance("DESede")
    • 初始化密碼器
      • cp.init(Cipher.ENCRYPT_MODE, k)
    • 獲取等待加密的明文
      • byte ptext[]=suffix.getBytes("UTF8")
    • 執行加密
      • byte ctext[]=cp.doFinal(ptext)
  • 傳輸密文長度,out.writeUTF(ctext.length+"")

  • 傳輸密文內容

for(int i=0; i<ctext.length; i++){
     out.writeUTF(ctext[i]+"");
}
  • 服務端DES解密
    • 獲取密鑰長度,String keylength = in.readUTF()

    • 獲取密鑰

byte []kb = new byte[Integer.parseInt(keylength)];
      for(int i=0; i<Integer.parseInt(keylength); i++){
          String t = in.readUTF();
          kb[i] = Byte.parseByte(t);
       }
  • 獲取密文長度,String clength = in.readUTF()

  • 獲取密文

byte []ctext = new byte[Integer.parseInt(clength)];
   for(int i=0; i<Integer.parseInt(clength); i++){
        String temp = in.readUTF();
        ctext[i] = Byte.parseByte(temp);
   }
  • 建立密碼器(Cipher對象)

    • Cipher cp=Cipher.getInstance("DESede")
  • 初始化密碼器

    • cp.init(Cipher.DECRYPT_MODE, k)
  • 執行解密

    • byte []ptext=cp.doFinal(ctext)

實驗代碼

  • 客戶端
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.io.*;
import java.net.*;
import java.util.Scanner;

public class Client1 {
    public static void main(String[] args) {
        Scanner inn = new Scanner(System.in);
        Socket mysocket;
        DataInputStream in = null;
        DataOutputStream out = null;
        try{
            mysocket = new Socket("127.0.0.1",2010);
            in = new DataInputStream(mysocket.getInputStream());
            out = new DataOutputStream(mysocket.getOutputStream());
            KeyGenerator kg=KeyGenerator.getInstance("DESede");
            kg.init(168);
            SecretKey k=kg.generateKey( );
            byte[ ] kb=k.getEncoded( );
            out.writeUTF(kb.length+"");
            for(int i=0; i<kb.length; i++){
                out.writeUTF(kb[i]+"");
            }
            System.out.println("請輸入中綴表達式:");
            String infix = inn.nextLine();
            MyBC myBC = new MyBC();
            String suffix = myBC.infixToSuffix(infix);
            Cipher cp=Cipher.getInstance("DESede");
            cp.init(Cipher.ENCRYPT_MODE, k);
            byte ptext[]=suffix.getBytes("UTF8");
            byte ctext[]=cp.doFinal(ptext);
            out.writeUTF(ctext.length+"");
            for(int i=0; i<ctext.length; i++){
                out.writeUTF(ctext[i]+"");
            }
            String result = in.readUTF();
            System.out.println("小猴收到胖礫的回答"+result);
            Thread.sleep(500);
        }catch (Exception e){
            System.out.println("胖礫又去吃飯了"+e);
        }
    }
}
  • 服務器
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.*;
public class Sever1 {
    public static void main(String[] args) {
        ServerSocket serverForClient = null;
        Socket socketOnServer = null;
        DataOutputStream out = null;
        DataInputStream in = null;
        MyDC myDC = new MyDC();
        try{
            serverForClient = new ServerSocket(2010);
        }catch (IOException e1){
            System.out.println("我是豬,我又餓了"+e1);
        }
        try{
            System.out.println("等待小猴投喂");
            socketOnServer = serverForClient.accept();
            out = new DataOutputStream(socketOnServer.getOutputStream());
            in = new DataInputStream(socketOnServer.getInputStream());
            String keylength = in.readUTF();
            byte []kb = new byte[Integer.parseInt(keylength)];
            for(int i=0; i<Integer.parseInt(keylength); i++){
                String t = in.readUTF();
                kb[i] = Byte.parseByte(t);
            }
            String clength = in.readUTF();
            byte []ctext = new byte[Integer.parseInt(clength)];
            for(int i=0; i<Integer.parseInt(clength); i++){
                String temp = in.readUTF();
                ctext[i] = Byte.parseByte(temp);
            }
            SecretKeySpec k=new  SecretKeySpec(kb,"DESede");
            Cipher cp=Cipher.getInstance("DESede");
            cp.init(Cipher.DECRYPT_MODE, k);
            byte []ptext=cp.doFinal(ctext);
            String suffix = new String(ptext,"UTF8");
            System.out.println("胖礫收到小猴的提問"+suffix);
            out.writeUTF(myDC.evaluate(suffix)+"");
            Thread.sleep(500);
        }catch (Exception e){
            System.out.println("小猴已斷開鏈接");
        }
    }
}

實驗結果

  • 客戶端

  • 服務端

任務四

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

實驗過程

  • 建立DH公鑰和私鑰

    • Server保存本身的私鑰和Client的公鑰
    • Client保存本身的私鑰和Server的公鑰
  • 建立共享祕鑰

    • DH算法中,Client能夠用本身的密鑰和Server的公鑰按照必定方法生成一個密鑰,Server也能夠用本身的密鑰和Client的公鑰按照必定方法生成一個密鑰,因爲一些數學規律,這兩個密鑰徹底相同。
    • 讀取本身的DH私鑰和對方的DH公鑰,第一個參數爲對方的公鑰文件名,第二個參數爲本身的私鑰文件名
FileInputStream f1 = new FileInputStream("Serverpub.dat");
ObjectInputStream b1 = new ObjectInputStream(f1);
FileInputStream f2 = new FileInputStream("Clientpri.dat");
ObjectInputStream b2 = new ObjectInputStream(f2);
  • 建立密鑰協定對象,KeyAgreement ka=KeyAgreement.getInstance("DH")

  • 初始化密鑰協定對象,ka.init(prk)

  • 執行密鑰協定,ka.doPhase(pbk,true)

  • 生成共享信息,byte[ ] sb=ka.generateSecret()

  • 使用SecretKeySpec k=new SecretKeySpec(sb,"DESede"),建立密鑰。

  • 用3DES算法加密中綴表達式

  • 用共享祕鑰加密密鑰

  • 給服務器發送密文和加密後的密鑰

  • 服務器用共享祕鑰解密密鑰

  • 服務器用解密後的密鑰對密文進行解密

實驗代碼

  • 客戶端
import javax.crypto.spec.*;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Client4 {
    public static void main(String[] args) {
        Scanner inn = new Scanner(System.in);
        Socket mysocket;
        DataInputStream in = null;
        DataOutputStream out = null;
        try {
            mysocket = new Socket("127.0.0.1", 2010);
            in = new DataInputStream(mysocket.getInputStream());
            out = new DataOutputStream(mysocket.getOutputStream());
            KeyGenerator kg = KeyGenerator.getInstance("DESede");
            kg.init(168);
            SecretKey k = kg.generateKey();
            byte[] kb = k.getEncoded();
            System.out.println("請輸入中綴表達式:");
            String infix = inn.nextLine();
            MyBC myBC = new MyBC();
            String suffix = myBC.infixToSuffix(infix);
            System.out.println(suffix);
            //中綴表達式加密
            Cipher cp = Cipher.getInstance("DESede");
            cp.init(Cipher.ENCRYPT_MODE, k);
            byte ptext[] = suffix.getBytes("UTF8");
            byte ctext[] = cp.doFinal(ptext);
            out.writeUTF(ctext.length + "");
            for (int i = 0; i < ctext.length; i++) {
                out.writeUTF(ctext[i] + "");
            }
            //對密鑰進行加密
            KeyAgree keyAgree = new KeyAgree();
            SecretKeySpec k1 = keyAgree.KeyAgree("Serverpub.dat","Clientpri.dat");
            cp.init(Cipher.ENCRYPT_MODE, k1);
            byte ckey[] = cp.doFinal(kb);
            out.writeUTF(ckey.length + "");
            for (int i = 0; i < ckey.length; i++) {
                out.writeUTF(ckey[i] + "");
            }
            String result = in.readUTF();
            System.out.println("小猴收到胖礫的回答" + result);
            Thread.sleep(500);
        } catch (Exception e) {
            System.out.println("胖礫又去吃飯了" + e);
        }
    }
}
  • 服務器
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.*;
public class Server4 {
    public static void main(String[] args) {
        ServerSocket serverForClient = null;
        Socket socketOnServer = null;
        DataOutputStream out = null;
        DataInputStream in = null;
        MyDC myDC = new MyDC();
        try{
            serverForClient = new ServerSocket(2010);
        }catch (IOException e1){
            System.out.println("我是豬,我又餓了"+e1);
        }
        try{
            System.out.println("等待小猴投喂");
            socketOnServer = serverForClient.accept();
            out = new DataOutputStream(socketOnServer.getOutputStream());
            in = new DataInputStream(socketOnServer.getInputStream());
            //獲取密文
            String clength = in.readUTF();
            byte []ctext = new byte[Integer.parseInt(clength)];
            for(int i=0; i<Integer.parseInt(clength); i++){
                String temp = in.readUTF();
                ctext[i] = Byte.parseByte(temp);
            }
            //獲取密鑰
            String keylength = in.readUTF();
            byte []ckey = new byte[Integer.parseInt(keylength)];
            for(int i=0; i<Integer.parseInt(keylength); i++){
                String temp = in.readUTF();
                ckey[i] = Byte.parseByte(temp);
            }
            //密鑰解密
            SecretKeySpec k1 = KeyAgree.KeyAgree("Clientpub.dat","Serverpri.dat");
            Cipher cp=Cipher.getInstance("DESede");
            cp.init(Cipher.DECRYPT_MODE, k1);
            byte []pkey=cp.doFinal(ckey);
            //密文解密
            SecretKeySpec k=new  SecretKeySpec(pkey,"DESede");
            cp.init(Cipher.DECRYPT_MODE, k);
            byte []ptext=cp.doFinal(ctext);
            String suffix = new String(ptext,"UTF8");
            System.out.println("胖礫收到小猴的提問"+suffix);
            out.writeUTF(myDC.evaluate(suffix)+"");
            Thread.sleep(500);
        }catch (Exception e){
            System.out.println("小猴已斷開鏈接");
        }
    }
}

實驗結果

  • 客戶端

  • 服務器

任務五

  • 完整性校驗結對編程:1人負責客戶端,一人負責服務器
  • 注意責任歸宿,要會經過測試證實本身沒有問題
  • 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
  • 客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密經過網絡把密文和明文的MD5値發送給服務器
  • 客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
  • 服務器接收到後綴表達式表達式後,進行解密,解密後計算明文的MD5值,和客戶端傳來的MD5進行比較,一致則調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
  • 客戶端顯示服務器發送過來的結果

實驗過程

  • Java摘要算法-MD5
    • 生成MessageDigest對象,MessageDigest m=MessageDigest.getInstance("MD5")
    • 傳入須要計算的字符串,m.update(x.getBytes("UTF8" ))
    • 計算消息摘要,byte s[ ]=m.digest( )
    • 處理計算結果

實驗代碼

MessageDigest m = MessageDigest.getInstance("MD5");
            m.update(suffix.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);
            }

實驗結果

  • 客戶端

  • 服務器

實驗總結

本次實驗是對教材十三章網絡編程和Java密碼學算法的實際應用,當時學的時候感受就有點迷糊不知道如何真實應用,經過此次實驗不只複習了相關知識,理解之前不懂的知識點,還了解了另外一種通訊手段

參考資料

Java密碼學算法

相關文章
相關標籤/搜索