1. 程式人生 > >2017-2018-2 20165318 實驗五《網絡編程與安全》實驗報告

2017-2018-2 20165318 實驗五《網絡編程與安全》實驗報告

循環 調用 ron 需求 body head sta 得到 就會

2017-2018-2 20165318 實驗五《網絡編程與安全》實驗報告

一、實驗報告封面

課程:Java程序設計 班級:1653班 姓名:孫曉暄 學號:20165318

指導教師:婁嘉鵬 實驗日期:2018年5月28日

實驗時間:13:45 - 3:25 實驗序號:實驗五

實驗名稱:網絡編程與安全

二、實驗內容及步驟

目錄

  • 任務一
  • 任務二
  • 任務三
  • 任務四
  • 任務五
  • 實驗體會
  • 代碼托管
  • PSP
  • 參考資料

任務一

實驗要求

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

實驗原理

  • 將運算符寫在兩個操作數中間的表達式,稱為“中綴表達式”,如1+2*(3-4)+5。在中綴表達式中,運算符具有不同的優先級,圓括號用於改變運算符的運算次序,所以求值過程不能直接按照從左到右的順序進行。

  • 將運算符寫在兩個操作數之後的表達式稱為“後綴表達式”,如上面的中綴表達式可轉換為後綴表達式1 2 3 4 - * + 5 +。後綴表達式中沒有括號,而且運算符沒有優先級。後綴表達式的求值過程能夠嚴格地從左到右按順序進行,符合運算器的求值規律。

  • 表達式求值算法分兩步進行:①中綴轉後綴;②求後綴表達式的值。

  • 由中綴式求得後綴式可以使用棧,偽代碼如下:

    • 設立一個棧,存放運算符,首先棧為空;
    • 從左到右掃描中綴式,若遇到操作數,直接輸出,並輸出一個空格作為兩個操作數的分隔符;
    • 若遇到運算符,則與棧頂比較,比棧頂級別高則進棧,否則退出棧頂元素並輸出,然後輸出一個空格作分隔符;
    • 若遇到左括號,進棧;若遇到右括號,則一直退棧輸出,直到退到左括號止。
    • 當棧變成空時,輸出的結果即為後綴表達式。
  • 後綴表達式求值偽代碼如下:

    • 設置一個操作數棧,開始棧為空;
    • 從左到右掃描後綴表達式,遇操作數,進棧;
    • 若遇運算符,則從棧中退出兩個元素,先退出的放到運算符的右邊,後退出的放到運算符左邊,運算後的結果再進棧,直到後綴表達式掃描完畢。
    • 重復以上步驟,直至後綴表達式結束,棧中最後一個數字就是所求表達式的值。

實驗代碼

MyBC.java

import java.util.*;

public class MyBC {
    private Stack<String> stack;
    private List<String> list;

    private String message, Message = "";

    public MyBC() {
        stack = new Stack<String>();//用來暫時存放運算符的棧
        list = new ArrayList<String>();//用來暫時存放操作數及運算符的列表
    }

    public void conversion(String expr) {   //中綴轉後綴
        String token;
        StringTokenizer tokenizer = new StringTokenizer(expr);

        while (tokenizer.hasMoreTokens()) {
            //當tokenizer有下一個值時,進行循環,並把值賦給token
            token = tokenizer.nextToken();

            if (token.equals("(")) {
                //如果是左括號,入棧
                stack.push(token);
            } else if (token.equals("+") || token.equals("-")) {
                //如果是“+”或“-”,繼續判斷棧是否為空
                if (!stack.empty()) {
                    //如果棧非空,判斷棧頂元素是什麽
                    if (stack.peek().equals("(")) {
                        //如果棧頂為“(”,運算符入棧
                        stack.push(token);
                    } else {
                        //否則先把棧頂元素移除,加到列表中,再將運算符入棧
                        list.add(stack.pop());
                        stack.push(token);
                    }
                } else {
                    //若棧為空,運算符入棧
                    stack.push(token);
                }
            } else if (token.equals("*") || token.equals("÷")) {
                //如果是“*”或“÷”,繼續判斷棧是否為空
                if (!stack.empty()) {
                    //如果棧非空,判斷棧頂元素是什麽
                    if (stack.peek().equals("*") || stack.peek().equals("÷")) {
                        //如果棧頂為“*”或“÷”,先把棧頂元素移除,加到列表中,再將運算符入棧
                        list.add(stack.pop());
                        stack.push(token);
                    } else {
                        //如果棧頂為其他,運算符直接入棧
                        stack.push(token);
                    }
                } else {
                    //如果棧為空,運算符直接入棧
                    stack.push(token);
                }
            } else if (token.equals(")")) {
                //如果遇到“)”,開始循環
                while (true) {
                    //先把棧頂元素移除並賦給A
                    String A = stack.pop();
                    if (!A.equals("(")) {
                        //如果A不為“(”,則加到列表
                        list.add(A);
                    } else {
                        //如果A為“(”,退出循環
                        break;
                    }
                }
            } else {
                //如果為操作數,進入列表
                list.add(token);
            }
        }
        while (!stack.empty()) {
            //將棧中元素取出,加到列表中,直到棧為空
            list.add(stack.pop());
        }
        ListIterator<String> li = list.listIterator();//返回此列表元素的列表叠代器(按適當順序)。
        while (li.hasNext()) {
            //將叠代器中的元素依次取出,並加上空格作為分隔符
            Message += li.next() + " ";
            li.remove();
        }
        message = Message;
    }

    public String getMessage() {
        return message;
    }
}

MyDC.java

import java.util.*;

public class MyDC {
    private final char ADD = ‘+‘;
    private final char SUBTRACT = ‘-‘;
    private final char MUTIPLY = ‘*‘;
    private final char DIVIDE = ‘/‘;
    private Stack<Integer> stack;
    public MyDC(){
        stack = new Stack<Integer>();
    }
    public int evaluate(String expr){
        int op1,op2,result = 0;
        String token;
        StringTokenizer tokenizer = new StringTokenizer(expr);
        while(tokenizer.hasMoreTokens()){
            token = tokenizer.nextToken();
            if(isOperator(token)){
                op2 = (stack.pop().intValue());
                op1 = (stack.pop().intValue());
                result = evalSingleOp(token.charAt(0),op1,op2);
                stack.push(new Integer(result));
            }
            else {
                stack.push(new Integer((Integer.parseInt(token))));
            }
        }
        return result;
    }
    private boolean isOperator(String token){
        return (token.equals("+")||token.equals("-")||token.equals("*")||token.equals("/"));
    }
    private int evalSingleOp(char operation,int op1,int op2) {
        int result = 0;
        switch (operation){
            case ADD:
                result = op1+op2;
                break;
            case SUBTRACT:
                result = op1-op2;
                break;
            case MUTIPLY:
                result = op1*op2;
                break;
            case DIVIDE:
                result = op1/op2;
        }
        return result;
    }
}

測試代碼
Calculator.java

import java.util.*;
public class Calculator {
    public static void main(String[] args) {
        String expression;
        int result;
        MyBC nts = new MyBC();
        MyDC value = new MyDC();
        System.out.println("Please input a nifix expression");
        Scanner in = new Scanner(System.in);
        expression = in.nextLine();
        nts.conversion(expression);
        System.out.println("The postfix expression is :"+nts.getMessage());
        result = value.evaluate(nts.getMessage());
        System.out.println("The result is :"+result);
    }
}

實驗截圖
技術分享圖片

技術分享圖片

返回目錄

任務二

實驗要求

  1. 一人負責客戶端,一人負責服務器
  2. 註意責任歸宿,要會通過測試證明自己沒有問題
  3. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
  4. 客戶端讓用戶輸入中綴表達式,然後把中綴表達式調用MyBC.java的功能轉化為後綴表達式,把後綴表達式通過網絡發送給服務器
  5. 服務器接收到後綴表達式,調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
  6. 客戶端顯示服務器發送過來的結果

實驗原理

『java.net.Socket』

  • 套接字是一個網絡連接的端點。在java中,使用java.net.Socket對象來表示一個套接字。
  • 要創建一個套接字,可以使用Socket的構造方法,如:public Socket(java.lang.String host, int port)。其中,host是遠程機器名或IP地址,port是遠程應用程序的端口號。
  • 一旦成功創建了Socket類的一個實例,就可以使用它發送或接收字節流。要發送字節流,必須先調用Socket類的getOutputStream方法來獲取一個java.io.OutputStream對象。要向遠程應用程序發送文本,通常要從返回的OutputStream對象構建一個java.io.PrintWriter對象。要接收來自連接的另一端的字節流,可以調用Socket類的getInputStream方法,它返回一個java.io.InputStream。

『java.net.ServerSocket』

  • ServerSocket是服務器套接字的一個實現。ServerSocket和Socket不同,服務器套接字的角色是,等待來自客戶端的連接請求。一旦服務器套接字獲得了一個連接請求,它就會創建一個Socket實例,以處理和客戶端的通信。

實驗代碼

調用任務一中的MyBC.java和MyDC.java,將中綴表達式轉後綴表達式,並對後綴表達式求值。

查看自己電腦的IP地址:
Address.java

import java.net.*;

public class Address {

    public static void main(String[] args) throws UnknownHostException {

        InetAddress net = InetAddress.getLocalHost();

        System.out.println(net.toString());

    }

}

客戶端

import java.io.*;
import java.net.*;

public class Client2 {
    public static void main(String args[]) {
        System.out.println("客戶端啟動...");
        //while (true) {
            Socket mysocket;
            DataInputStream in = null;
            DataOutputStream out = null;
            try {
                mysocket = new Socket("192.168.188.1", 2010);
                in = new DataInputStream(mysocket.getInputStream());
                out = new DataOutputStream(mysocket.getOutputStream());
                System.out.println("請輸入:");
                String str = new BufferedReader(new InputStreamReader(System.in)).readLine();
                MyBC turner = new MyBC();
                turner.conversion(str);
                String str1 = turner.getMessage();
                out.writeUTF(str1);
                String s = in.readUTF();   //in讀取信息,堵塞狀態
                System.out.println("客戶收到服務器的回答:" + s);
                Thread.sleep(500);
            } catch (Exception e) {
                System.out.println("服務器已斷開" + e);
            }
        //}
    }
}

服務器端

import java.io.*;
        import java.net.*;

public class Server2 {
    public static void main(String[] args) throws IOException {
        int answer;
        //while (true) {
        ServerSocket serverForClient = null;
        Socket socketOnServer = null;
        DataOutputStream out = null;
        DataInputStream in = null;
        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 s = in.readUTF(); // in讀取信息,堵塞狀態
            System.out.println("服務器收到客戶的提問:" + s);
            MyDC myDC = new MyDC();
            answer = myDC.evaluate(s);
            out.writeUTF(answer + "");
            Thread.sleep(500);
        } catch (Exception e) {
            System.out.println("客戶已斷開" + e);
        }
        //}
    }
}

實驗截圖
技術分享圖片

技術分享圖片

返回目錄

任務三

實驗要求

  1. 一人負責客戶端,一人負責服務器
  2. 註意責任歸宿,要會通過測試證明自己沒有問題
  3. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
  4. 客戶端讓用戶輸入中綴表達式,然後把中綴表達式調用MyBC.java的功能轉化為後綴表達式,把後綴表達式用3DES或AES算法加密後通過網絡把密文發送給服務器
  5. 服務器接收到後綴表達式表達式後,進行解密(和客戶端協商密鑰,可以用數組保存),然後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
  6. 客戶端顯示服務器發送過來的結果

實驗原理

  • 實現DES加密主要有以下幾個步驟:
    • 對稱密鑰的生成和保存;
    • 使用對稱密鑰進行加密和解密;
    • 從文件中獲取加密時使用的密鑰,使用密鑰進行解密。

實驗代碼

DES生成密鑰並加解密的程序參考Java 密碼學算法在此就不一一列出

客戶端

import javax.crypto.Cipher;
import java.io.*;
import java.net.Socket;
import java.security.Key;
import java.util.Scanner;

public class Client3 {
    public static void main(String args[]) {
        Socket mysocket;
        MyBC mybc = new MyBC();
        DataInputStream in = null;
        DataOutputStream out = null;
        Scanner scanner = new Scanner(System.in);
        String str;
        try {
            mysocket = new Socket("192.168.188.1", 5318);
            in = new DataInputStream(mysocket.getInputStream());
            out = new DataOutputStream(mysocket.getOutputStream());
            System.out.println("客戶端啟動...");
            FileInputStream f = new FileInputStream("key1.dat");
            ObjectInputStream b = new ObjectInputStream(f);
            Key key = (Key) b.readObject();
            Cipher cp = Cipher.getInstance("DESede");
            cp.init(Cipher.ENCRYPT_MODE, key);
            System.out.println("請輸入中綴表達式:");
            str = scanner.nextLine();
            mybc.conversion(str);
            String str1 = mybc.getMessage();
            byte ptext[] = str1.getBytes("UTF-8");
            byte ctext[] = cp.doFinal(ptext);
            System.out.println("被加密的後綴表達式:");
            for (int i = 0; i < ctext.length; i++) {
                System.out.print(ctext[i] + ",");
            }
            System.out.println("");
            out.writeUTF(ctext.length + "");
            for (int i = 0; i < ctext.length; i++) {
                out.writeUTF(ctext[i] + "");
                //System.out.print();
            }
            String s = in.readUTF();   //in讀取信息,堵塞狀態
            System.out.println("客戶收到服務器的回應:" + s);
        } catch (Exception e) {
            System.out.println("服務器已斷開" + e);
        }
    }
}

服務器端

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server3 {
    public static void main(String args[]) {
        MyDC mydc = new MyDC();
        ServerSocket serverForClient = null;
        Socket socketOnServer = null;
        DataOutputStream out = null;
        DataInputStream in = null;
        try {
            serverForClient = new ServerSocket(5318);
        } catch (IOException e1) {
            System.out.println(e1);
        }
        try {
            System.out.println("等待客戶呼叫");
            socketOnServer = serverForClient.accept(); //堵塞狀態,除非有客戶呼叫
            System.out.println("客戶已連接");
            out = new DataOutputStream(socketOnServer.getOutputStream());
            in = new DataInputStream(socketOnServer.getInputStream());
            String leng = in.readUTF(); // in讀取信息,堵塞狀態
            byte ctext[] = new byte[Integer.parseInt(leng)];
            for (int i = 0;i<Integer.parseInt(leng);i++) {
                String temp = in.readUTF();
                ctext[i] = Byte.parseByte(temp);
            }
            // 獲取密鑰
            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);
            /*for (int i = 0; i < ptext.length; i++) {
                System.out.print(ptext[i] + ",");
            }
            */
            System.out.println("");
            // 顯示明文
            String p = new String(ptext,"UTF8");
            System.out.println("被解密的後綴表達式:" + p);
            System.out.println("計算後綴表達式" + p);
            out.writeUTF(mydc.evaluate(p)+"");
        } catch (Exception e) {
            System.out.println("客戶已斷開" + e);
        }
    }
}

實驗截圖

技術分享圖片

技術分享圖片
返回目錄

任務四

實驗要求

  1. 一人負責客戶端,一人負責服務器
  2. 註意責任歸宿,要會通過測試證明自己沒有問題
  3. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
  4. 客戶端讓用戶輸入中綴表達式,然後把中綴表達式調用MyBC.java的功能轉化為後綴表達式,把後綴表達式用3DES或AES算法加密通過網絡把密文發送給服務器
  5. 客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
  6. 服務器接收到後綴表達式表達式後,進行解密,然後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
  7. 客戶端顯示服務器發送過來的結果

實驗原理

  • 執行密鑰協定的標準算法是DH算法(Diffie-Hellman算法),分為以下兩步:
    • 創建DH公鑰和私鑰;
    • 創建共享密鑰。

實驗代碼

客戶端

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.Socket;
import java.security.Key;
import java.util.Optional;
import java.util.Scanner;

public class Client4 {
    public static void main(String args[]) {
        MyBC mybc = new MyBC();
        Socket mysocket;
        DataInputStream in = null;
        DataOutputStream out = null;
        Scanner scanner = new Scanner(System.in);
        String str;
        try {
            mysocket = new Socket("192.168.188.1", 5318);
            System.out.println("客戶端啟動...");
            in = new DataInputStream(mysocket.getInputStream());
            out = new DataOutputStream(mysocket.getOutputStream());
            System.out.println("請輸入中綴表達式:");
            str = scanner.nextLine();

            Key_DH.DH("Cpub.dat","Cpri.dat");
            FileInputStream fp = new FileInputStream("Cpub.dat");
            ObjectInputStream bp = new ObjectInputStream(fp);
            Key kp = (Key) bp.readObject();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(kp);
            byte[] kb = baos.toByteArray();
            out.writeUTF(kb.length + "");
            for (int i = 0; i < kb.length; i++) {
                out.writeUTF(kb[i] + "");
            }
            Thread.sleep(1000);
            int len = Integer.parseInt(in.readUTF());
            byte np[] = new byte[len];
            for (int i = 0;i<len;i++) {
                String temp = in.readUTF();
                np[i] = Byte.parseByte(temp);
            }
            ObjectInputStream ois = new ObjectInputStream (new ByteArrayInputStream (np));
            Key k2 = (Key)ois.readObject();;
            FileOutputStream f2 = new FileOutputStream("Spub.dat");
            ObjectOutputStream b2 = new ObjectOutputStream(f2);
            b2.writeObject(k2);

            KeyAgree.DH("Spub.dat","Cpri.dat");
            FileInputStream f = new FileInputStream("sb.dat");
            byte[] keysb = new byte[24];
            f.read(keysb);
            System.out.println("公共密鑰:");
            for (int i = 0;i<24;i++) {
                System.out.print(keysb[i]+",");
            }
            System.out.println("");
            SecretKeySpec k = new SecretKeySpec(keysb, "DESede");
            Cipher cp = Cipher.getInstance("DESede");
            cp.init(Cipher.ENCRYPT_MODE, k);
            mybc.conversion(str);
            String str1 = mybc.getMessage();
            byte ptext[] = str1.getBytes("UTF-8");
            byte ctext[] = cp.doFinal(ptext);
            System.out.println("後綴表達式已被加密:");
            for (int i = 0; i < ctext.length; i++) {
                System.out.print(ctext[i] + ",");
            }
            System.out.println("");
            out.writeUTF(ctext.length + "");
            for (int i = 0; i < ctext.length; i++) {
                out.writeUTF(ctext[i] + "");
            }
            String s = in.readUTF();   //in讀取信息,堵塞狀態
            System.out.println("客戶收到服務器的回應:" + s);
        } catch (Exception e) {
            System.out.println("服務器已斷開" + e);
        }
    }
}

服務器端

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.Key;

public class Server4 {
    public static void main(String args[]) {
        MyDC mydc = new MyDC();
        ServerSocket serverForClient = null;
        Socket socketOnServer = null;
        DataOutputStream out = null;
        DataInputStream in = null;
        try {
            serverForClient = new ServerSocket(5318);
        } catch (IOException e1) {
            System.out.println(e1);
        }
        try {
            System.out.println("等待客戶呼叫");
            socketOnServer = serverForClient.accept(); //堵塞狀態,除非有客戶呼叫
            System.out.println("客戶已連接");
            out = new DataOutputStream(socketOnServer.getOutputStream());
            in = new DataInputStream(socketOnServer.getInputStream());

            Key_DH.DH("Spub.dat","Spri.dat");
            int len = Integer.parseInt(in.readUTF());
            byte np[] = new byte[len];
            for (int i = 0;i<len;i++) {
                String temp = in.readUTF();
                np[i] = Byte.parseByte(temp);
            }
            ObjectInputStream ois = new ObjectInputStream (new ByteArrayInputStream (np));
            Key k2 = (Key)ois.readObject();;
            FileOutputStream f2 = new FileOutputStream("Cpub.dat");
            ObjectOutputStream b2 = new ObjectOutputStream(f2);
            b2.writeObject(k2);

            FileInputStream fp = new FileInputStream("Spub.dat");
            ObjectInputStream bp = new ObjectInputStream(fp);
            Key kp = (Key) bp.readObject();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(kp);
            byte[] kb = baos.toByteArray();
            out.writeUTF(kb.length + "");
            for (int i = 0; i < kb.length; i++) {
                out.writeUTF(kb[i] + "");
            }

            KeyAgree.DH("Cpub.dat","Spri.dat");

            String leng = in.readUTF(); // in讀取信息,堵塞狀態
            byte ctext[] = new byte[Integer.parseInt(leng)];
            for (int i = 0;i<Integer.parseInt(leng);i++) {
                String temp = in.readUTF();
                ctext[i] = Byte.parseByte(temp);
            }
            // 獲取密鑰
            FileInputStream f = new FileInputStream("sb.dat");
            byte[] keysb = new byte[24];
            f.read(keysb);
            System.out.println("公共密鑰:");
            for (int i = 0;i<24;i++) {
                System.out.print(keysb[i]+",");
            }
            System.out.println("");
            SecretKeySpec k = new SecretKeySpec(keysb, "DESede");
            // 解密
            Cipher cp = Cipher.getInstance("DESede");
            cp.init(Cipher.DECRYPT_MODE, k);
            byte[] ptext = cp.doFinal(ctext);
            System.out.println("");
            // 顯示明文
            String p = new String(ptext,"UTF8");
            System.out.println("被解密的後綴表達式:" + p);
            System.out.println("計算後綴表達式" + p);
            out.writeUTF(mydc.evaluate(p)+"");
        } catch (Exception e) {
            System.out.println("客戶已斷開" + e);
        }
    }
}

實驗截圖

技術分享圖片

技術分享圖片
返回目錄

任務五

實驗要求

  1. 一人負責客戶端,一人負責服務器
  2. 註意責任歸宿,要會通過測試證明自己沒有問題
  3. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
  4. 客戶端讓用戶輸入中綴表達式,然後把中綴表達式調用MyBC.java的功能轉化為後綴表達式,把後綴表達式用3DES或AES算法加密通過網絡把密文和明文的MD5値發送給服務器
  5. 客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
  6. 服務器接收到後綴表達式表達式後,進行解密,解密後計算明文的MD5值,和客戶端傳來的MD5進行比較,一致則調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
  7. 客戶端顯示服務器發送過來的結果
    實驗原理
  • 可以使用Java計算指定字符串的消息摘要。java.security包中的MessageDigest類提供了計算消息摘要的方法,首先生成對象,執行其update()方法可以將原始數據傳遞給該對象,然後執行其digest( )方法即可得到消息摘要。

實驗代碼

客戶端

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.Socket;
import java.security.Key;
import java.util.Scanner;

public class Client5 {
    public static void main(String args[]) {
        MyBC mybc = new MyBC();
        Socket mysocket;
        DataInputStream in = null;
        DataOutputStream out = null;
        Scanner scanner = new Scanner(System.in);
        String str;
        try {
            mysocket = new Socket("192.168.188.1", 5318);
            System.out.println("客戶端啟動...");
            in = new DataInputStream(mysocket.getInputStream());
            out = new DataOutputStream(mysocket.getOutputStream());
            System.out.println("請輸入中綴表達式:");
            str = scanner.nextLine();

            Key_DH.DH("Cpub.dat","Cpri.dat");
            FileInputStream fp = new FileInputStream("Cpub.dat");
            ObjectInputStream bp = new ObjectInputStream(fp);
            Key kp = (Key) bp.readObject();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(kp);
            byte[] kb = baos.toByteArray();
            out.writeUTF(kb.length + "");
            for (int i = 0; i < kb.length; i++) {
                out.writeUTF(kb[i] + "");
            }
            Thread.sleep(500);
            int len = Integer.parseInt(in.readUTF());
            byte np[] = new byte[len];
            for (int i = 0;i<len;i++) {
                String temp = in.readUTF();
                np[i] = Byte.parseByte(temp);
            }
            ObjectInputStream ois = new ObjectInputStream (new ByteArrayInputStream (np));
            Key k2 = (Key)ois.readObject();;
            FileOutputStream f2 = new FileOutputStream("Spub.dat");
            ObjectOutputStream b2 = new ObjectOutputStream(f2);
            b2.writeObject(k2);

            KeyAgree.DH("Spub.dat","Cpri.dat");
            FileInputStream f = new FileInputStream("sb.dat");
            byte[] keysb = new byte[24];
            f.read(keysb);
            System.out.println("公共密鑰:");
            for (int i = 0;i<24;i++) {
                System.out.print(keysb[i]+",");
            }
            System.out.println("");
            SecretKeySpec k = new SecretKeySpec(keysb, "DESede");
            Cipher cp = Cipher.getInstance("DESede");
            cp.init(Cipher.ENCRYPT_MODE, k);

            mybc.conversion(str);
            String str1 = mybc.getMessage();
            byte ptext[] = str1.getBytes("UTF-8");
            String ptextMd5 = DigestPass.DP(str1);
            System.out.println("明文的MD5值:"+ptextMd5);
            byte ctext[] = cp.doFinal(ptext);
            System.out.println("被加密的後綴表達式:");
            for (int i = 0; i < ctext.length; i++) {
                System.out.print(ctext[i] + ",");
            }
            System.out.println("");
            out.writeUTF(ctext.length + "");
            for (int i = 0; i < ctext.length; i++) {
                out.writeUTF(ctext[i] + "");
            }
            out.writeUTF(ptextMd5);
            String s = in.readUTF();   //in讀取信息,堵塞狀態
            System.out.println("客戶收到服務器的回應:" + s);
        } catch (Exception e) {
            System.out.println("服務器已斷開" + e);
        }
    }
}

服務器端

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.Key;

public class Server5 {
    public static void main(String args[]) {
        MyDC mydc = new MyDC();
        ServerSocket serverForClient = null;
        Socket socketOnServer = null;
        DataOutputStream out = null;
        DataInputStream in = null;
        try {
            serverForClient = new ServerSocket(5318);
        } catch (IOException e1) {
            System.out.println(e1);
        }
        try {
            System.out.println("等待客戶呼叫");
            socketOnServer = serverForClient.accept(); //堵塞狀態,除非有客戶呼叫
            System.out.println("客戶已連接");
            out = new DataOutputStream(socketOnServer.getOutputStream());
            in = new DataInputStream(socketOnServer.getInputStream());

            Key_DH.DH("Spub.dat","Spri.dat");
            int len = Integer.parseInt(in.readUTF());
            byte np[] = new byte[len];
            for (int i = 0;i<len;i++) {
                String temp = in.readUTF();
                np[i] = Byte.parseByte(temp);
            }
            ObjectInputStream ois = new ObjectInputStream (new ByteArrayInputStream(np));
            Key k2 = (Key)ois.readObject();;
            FileOutputStream f2 = new FileOutputStream("Cpub.dat");
            ObjectOutputStream b2 = new ObjectOutputStream(f2);
            b2.writeObject(k2);

            FileInputStream fp = new FileInputStream("Spub.dat");
            ObjectInputStream bp = new ObjectInputStream(fp);
            Key kp = (Key) bp.readObject();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(kp);
            byte[] kb = baos.toByteArray();
            out.writeUTF(kb.length + "");
            for (int i = 0; i < kb.length; i++) {
                out.writeUTF(kb[i] + "");
            }

            KeyAgree.DH("Cpub.dat","Spri.dat");

            String leng = in.readUTF(); // in讀取信息,堵塞狀態
            byte ctext[] = new byte[Integer.parseInt(leng)];
            for (int i = 0;i<Integer.parseInt(leng);i++) {
                String temp = in.readUTF();
                ctext[i] = Byte.parseByte(temp);
            }
            String check = in.readUTF();
            // 獲取密鑰
            FileInputStream f = new FileInputStream("sb.dat");
            byte[] keysb = new byte[24];
            f.read(keysb);
            System.out.println("公共密鑰:");
            for (int i = 0;i<24;i++) {
                System.out.print(keysb[i]+",");
            }
            System.out.println("");
            SecretKeySpec k = new SecretKeySpec(keysb, "DESede");
            // 解密
            Cipher cp = Cipher.getInstance("DESede");
            cp.init(Cipher.DECRYPT_MODE, k);
            byte[] ptext = cp.doFinal(ctext);
            System.out.println("");
            // 顯示明文
            String p = new String(ptext, "UTF8");
            String pMd5 = DigestPass.DP(p);
            System.out.println("被解密明文的MD5值:"+pMd5);
            if (pMd5.equals(check)){
                System.out.println("和客戶端的MD5值一致");
                System.out.println("計算後綴表達式" + p);
                out.writeUTF(mydc.evaluate(p)+"");
            }
            else {
                System.out.println("警告:和客戶端的MD5值不一致!");
            }
        } catch (Exception e) {
            System.out.println("客戶已斷開" + e);
        }
    }
}

實驗截圖

技術分享圖片

技術分享圖片

返回目錄

實驗體會

此次實驗的內容主要是是網絡編程,同時結合密碼學算法。在這次實驗之前,雖然有學過Java網絡編程理論內容,但真正自己動手編程時,發現並不太理解如何實現客戶端和服務器,在和結對小夥變一起復習網絡編程和密碼學算法相關內容後,我們參考書上代碼和Java 密碼學算法,最終完成了實驗,在這個過程中,我們復習了相關知識,也學到了很多信的內容。

返回目錄

代碼托管

碼雲鏈接

返回目錄

PSP

步驟 耗時 百分比
需求分析 50min 20%
設計 20min 8%
代碼實現 100min 42%
測試 20min 8%
分析總結 50min 22%

返回目錄

參考資料

Java 密碼學算法
2016-2017-2 《Java 程序設計》課堂實踐項目

返回目錄

2017-2018-2 20165318 實驗五《網絡編程與安全》實驗報告