2018-2019-2 20,175,214 experiments Five "network programming and security" test report

I. Overview of experimental preparations

  • Object Pair: 20175209 Wong Chi Hung
  • Before twinning projects have been completed through the four contents of the operation, and therefore is not fully use the blog link given code upon completion of the experiment, the junction code project prior to the substantially employed and twinning project four arithmetic operations may also be implemented score calculation, more comprehensive.
  • In the process of completing the study in the need to refer to the contents of three experiments in Java cryptographic algorithm.

Second, the experimental content and process

  • 1. Submission 1

    • Experimental requirements:
    结对实现中缀表达式转后缀表达式的功能 MyBC.java
    结对实现从上面功能中获取的表达式中实现后缀表达式求值的功能,调用MyDC.java
    上传测试代码运行结果截图和码云链接
    • Principle

      • We used to use an expression called infix expression, but the computer does not use the infix expression in the calculation;
      • Since infix expression requires a computer to scan backwards after encountering a symbol for the brackets or if a higher priority operators also need to continue to scan backward;
      • The postfix expression in strict accordance with the calculated pattern from left to right in line with the computer running mode;
      • Therefore expression is evaluated in two parts: turn postfix infix, postfix expression.
    • Experiment Code

      • Infix turn suffix MyBC.java

        • Fake code
        1、设立空栈用于存放操作符
        2、从左到右扫描中缀式,若遇到操作数,直接输出,并以空格作为分隔符;
        3、若遇到运算符,则与栈顶元素比较,比栈顶级别高则进栈,否则退出栈顶元素并输出,并以空格作为分隔符,优先级从高到低为')' '/' (÷*) (+-) ;
        4、若遇到左括号,进栈;若遇到右括号,则一直退栈输出,直到退到左括号止;
        5、当栈变成空时,输出的结果即为后缀表达式。
        • Product Code
        import java.util.Stack;
        public class MyBC {
         String C = new String();
         String End = "";            //存储数字的字符串
         public void ChangeString(String str) {
         C = str;
         }
         public String ChangeOrder() {
        Stack store = new Stack();     //创建一个存储字符的栈
        for (int i = 0; i < C.length(); i++) {
           char op = C.charAt(i);     //将索引值为i处的字符的值返回
           if (op >= '0' && op <= '9') {
               End = End + op;
           }
           else if (op == '(') {
               store.push(op);
           }
           else if (op == '+' || op == '-' || op == '*' || op == '÷'|| op == '/') {
               End = End + " ";
               if (store.empty()) {
                   store.push(op);
               }
               else if (compareValue(op) > compareValue((char) store.peek())) {     //比较运算符优先级
                   store.push(op);
               }
               else {
                   End = End + String.valueOf(store.pop());
                   i--;
               }
           }
           else if (op == ')') {
               while ((char) store.peek() != '(') {
                   End = End + " " + String.valueOf(store.pop());
               }
           store.pop();
           }
        }
        while (!store.empty()) {
           End = End + " " + String.valueOf(store.pop());
        }
        return End;
         }
         public int compareValue(char chi) {
        int number = 0;
        switch (chi) {
        case '(':
           number = 1;
           break;
        case '+':
        case '-':
           number = 2;
           break;
        case '*':
        case '÷':
           number = 3;
           break;
        case '/':
           number = 4;
           break;
        case ')':
           number = 5;
           break;
        default:
           number = 0;
           break;
        }
        return number;
         }
        }
      • Postfix expression computing MyDC.java

        • Fake code
        1、设置一个空栈用于存储数字元素;
        2、从左到右扫描后缀表达式,遇操作数,进栈;
        3、若遇运算符,则从栈顶弹出两个操作数,执行对应的运算,并将运算后的结果压栈栈;
        4、重复执行直至后缀表达式扫描完毕,弹出栈中的最后一个元素即为表达式的值。
        • Product Code
        import java.util.StringTokenizer;
        import java.util.Stack;
        public class MyDC {
         String q;
         Stack stack;
         public MyDC() {
        stack = new Stack();
         }
         void set(String question) {   //输入后续排列的字符串
        q = question;
         }
         public Rational get() {
        Rational op1 = new Rational();
        Rational op2 = new Rational();
        Rational result = new Rational();
        result.setNumerator(0);
        StringTokenizer token = new StringTokenizer(q, " ");
        String temp;
        while (token.hasMoreTokens()) {
           temp = token.nextToken();
           if (Isop(temp) == 1) {     //遇到操作符,弹出栈顶的两个数进行运算
               op2 = (Rational) stack.pop();
               op1 = (Rational) stack.pop();//弹出最上面两个操作数
               result = cal(temp.charAt(0), op1, op2);//根据运算符进行运算
               stack.push(result);//将计算结果压栈
           }
           else {
               Rational num = new Rational();
               num.setNumerator(Integer.parseInt(temp));
               stack.push(num);//操作数入栈
           }
        }
        return result;
         }
         Rational cal(char op, Rational a, Rational b) {           //对栈顶弹出的两个数进行运算
        Rational c = new Rational();
        switch (op) {
           case '+':
               c = a.add(b);
               break;
           case '-':
               c = a.sub(b);
               break;
           case '*':
               c = a.muti(b);
               break;
           case '÷':
           case '/':
               if(b.getNumerator()==0) {
                   System.out.println("生成的算式计算时出现了分母为0的情况!");
                   System.exit(0);
               }
               else {
                   c = a.div(b);
                   break;
               }
           default:
               System.out.println("Wrong!");
        }
        return c;
         }
         int Isop(String op) {       //判断是不是运算符
        if (op.equals("+") || op.equals("-") || op.equals("*") || op.equals("÷") || op.equals("/")) {
           return 1;
        }
        else {
           return 0;
        }
         }
        }
      • Rational class Rational
        • For fractional arithmetic
        public class Rational {
         int numerator = 1 ;   //分子
         int denominator = 1; //分母
         void setNumerator(int a) {  //设置分子
        int c=f(Math.abs(a),denominator);  //计算最大公约数
        numerator = a/c;
        denominator = denominator/c;
        if(numerator<0&&denominator<0) {
           numerator = -numerator;
           denominator = -denominator;
        }
         }
         void setDenominator(int b) {  //设置分母
        int c=f(numerator,Math.abs(b));  //计算最大公约数
        numerator = numerator/c;
        denominator = b/c;
        if(numerator<0&&denominator<0) {
           numerator = -numerator;
           denominator = -denominator;
        }
         }
         int getNumerator() {
        return numerator;
         }
         int getDenominator() {
        return denominator;
         }
         int f(int a,int b) { //求a和b的最大公约数
        if(a==0) {
           return 1;
        }
        if(a<b) {
           int c=a;
           a=b;
           b=c;
        }
        int r=a%b;
        while(r!=0) {
           a=b;
           b=r;
           r=a%b;
        }
        return b;
         }
         Rational add(Rational r) {  //加法运算
        int a=r.getNumerator();
        int b=r.getDenominator();
        int newNumerator=numerator*b+denominator*a; //计算出新分子
        int newDenominator=denominator*b;           //计算出新分母
        Rational result=new Rational();
        result.setNumerator(newNumerator);
        result.setDenominator(newDenominator);
        return result;
         }
         Rational sub(Rational r) {  //减法运算
        int a=r.getNumerator();
        int b=r.getDenominator();
        int newNumerator=numerator*b-denominator*a;
        int newDenominator=denominator*b;
        Rational result=new Rational();
        result.setNumerator(newNumerator);
        result.setDenominator(newDenominator);
        return result;
         }
         Rational muti(Rational r) { //乘法运算
        int a=r.getNumerator();
        int b=r.getDenominator();
        int newNumerator=numerator*a;
        int newDenominator=denominator*b;
        Rational result=new Rational();
        result.setNumerator(newNumerator);
        result.setDenominator(newDenominator);
        return result;
         }
         Rational div(Rational r)  { //除法运算
        int a=r.getNumerator();
        int b=r.getDenominator();
        int newNumerator=numerator*b;
        int newDenominator=denominator*a;
        Rational result=new Rational();
        if(a==0) {
           System.out.println("该算式无解");
           result.setNumerator(0);
        }
        else {
           result.setNumerator(newNumerator);
           result.setDenominator(newDenominator);
        }
        return result;
         }
        }
      • Test test code

        import java.util.*;
        public class Test {
         public static void main(String[] args) {
        String question = "";
        String question1 = "";
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入题目:");
        question = scanner.nextLine();
        MyBC change = new MyBC();
        change.ChangeString(question);
        question1 = change.ChangeOrder();
        System.out.println(question1);
        MyDC getanswer = new MyDC();
        getanswer.set(question1);
        Rational answer = getanswer.get();
        int a = answer.getNumerator();
        int b = answer.getDenominator();
        float result = (float)a/b;
        System.out.println("结果为(保留两位小数):");
        System.out.println(String.format("%.2f",result));
         }
        }
    • Test results Screenshot

  • 2. Submit 2

    • Experimental requirements
    1、基于Java Socket实现客户端/服务器功能,传输方式用TCP
    2、客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式通过网络发送给服务器
    3、服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    4、客户端显示服务器发送过来的结果
    5、上传测试结果截图和码云链接
    • Principle

      • Obtain ClientIP address of the client
        • Open the terminal input ipconfigview;
        • At the command line, enter the IP address;
        • Invoke InetAddressclass geetByNamemethod to get the IP address entered;
      • Create a socket, you can use Socketthe constructor;
        • Such as: public Socket(java.lang.String host, int port)where hostis the IP address, portport number.
      • Call the getInputStream()method to obtain an input stream
      • Call the getOutputStream()method to obtain an output stream
      • Server-side call ServerSocket realize Sockets
      • Using the accept()method of connecting the client and server socket
      • Call the getInputStream()method to obtain an input stream
      • Call the getOutputStream()method to obtain an output stream
    • Experiment Code

      • Client Client
      import java.io.*;
      import java.net.*;
      import java.util.Scanner;
      public class Client {
       public static void main(String args[]) {
        Socket mysocket;
        DataInputStream in=null;
        DataOutputStream out=null;
        Scanner scanner = new Scanner(System.in);
        try{
            System.out.print("输入服务器的IP:");
            String IP = scanner.nextLine();
            InetAddress address=InetAddress.getByName(IP);
            mysocket = new Socket(address, 2010);
            in=new DataInputStream(mysocket.getInputStream());
            out=new DataOutputStream(mysocket.getOutputStream());
            System.out.println("请输入中缀表达式:");
            while (scanner.hasNext()) {
                String question = scanner.next();
                MyBC change = new MyBC();
                change.ChangeString(question);
                String question1 = change.ChangeOrder();
                System.out.println("后缀表达式为:"+question1);
                out.writeUTF(question1);
                String s=in.readUTF(); //in读取信息,堵塞状态
                System.out.println("客户收到服务器的回答:"+s);
                Thread.sleep(500);
                System.out.println("请输入中缀表达式:");
            }
        }
        catch(Exception e) {
            System.out.println("服务器已断开"+e);
        }
       }
      }
      • Server Server
      import java.io.*;
      import java.net.*;
      public class Server {
       public static void main(String[] args) {
        ServerSocket serverForClient = null;
        Socket socketOnServer = null;
        DataOutputStream out = null;
        DataInputStream in = null;
        String question = "";
        try {
            serverForClient = new ServerSocket(2010);
        } catch (IOException e) {
            System.out.println(e);
        }
        System.out.println("等待客户呼叫");
        try {
            socketOnServer = serverForClient.accept();
            out = new DataOutputStream(socketOnServer.getOutputStream());
            in = new DataInputStream(socketOnServer.getInputStream());
            while(true) {
                question = in.readUTF(); // in读取信息,堵塞状态
                System.out.println("服务器收到客户传递的后缀表达式为:" + question);
                MyDC getanswer = new MyDC();
                getanswer.set(question);
                Rational answer = getanswer.get();
                int a = answer.getNumerator();
                int b = answer.getDenominator();
                float result = (float) a / b;
                System.out.println("计算出的结果为"+String.format("%.2f",result));
                out.writeUTF(String.format("%.2f",result));
                Thread.sleep(500);
            }
        } catch (Exception e) {
            System.out.println("客户已断开" + e);
        }
       }
      }
    • Test results Screenshot

      • Client

      • server

  • 3. Submit 3

    • Experimental requirements
    1、基于Java Socket实现客户端/服务器功能,传输方式用TCP
    2、客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密后通过网络把密文发送给服务器
    3、服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,可以用数组保存),然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    4、客户端显示服务器发送过来的结果
    5、上传测试结果截图和码云链接
    • Principle

      • 本部分主要参考Java密码学算法中“Java对称加密-DES算法”部分;
      • 但是这次和结对伙伴没有通过对象序列化方式写入文件中,而是直接将密钥进行传递。
    • 伪代码
      • 客户端
      1、获取密钥生成器KeyGenerator kg=KeyGenerator.getInstance("DESede")
      2、初始化密钥生成器kg.init(168);
      3、生成密钥SecretKey k=kg.generateKey( );
      4、获取主要编码格式byte[ ] kb=k.getEncoded( );
      5、传送密钥长度及密钥内容
      6、创建密码器Cipher cp=Cipher.getInstance("DESede");
      7、初始化密码器cp.init(Cipher.ENCRYPT_MODE, k);
      8、获取等待加密的明文byte ptext[]=s.getBytes("UTF8");
      9、执行加密byte []ptext=cp.doFinal(ctext)
      • 服务器
      1、接收密钥长度
      2、接收密钥内容
      3、创建密码器Cipher cp=Cipher.getInstance("DESede");
      4、初始化密码器cp.init(Cipher.DECRYPT_MODE, k);
      5、执行解密byte []ptext=cp.doFinal(ctext)
    • 实验代码

      • 客户端Client
      import java.io.*;
      import java.net.*;
      import javax.crypto.*;
      import java.util.Scanner;
      public class Client {
       public static void main(String args[]) throws Exception{
        Socket mysocket;
        DataInputStream in=null;
        DataOutputStream out=null;
        Scanner scanner = new Scanner(System.in);
        try {
            System.out.print("输入服务器的IP:");
            String IP = scanner.nextLine();
            InetAddress address=InetAddress.getByName(IP);
            mysocket = new Socket(address, 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+ "");
            System.out.println("产生的密钥为");
            for(int i=0;i<kb.length;i++) {
                System.out.print(kb[i]+ " ");
                out.writeUTF(kb[i] +"");
            }
            System.out.println("\n请输入中缀表达式:");
            while(scanner.hasNext()) {
                String question = scanner.next();
                MyBC change = new MyBC();
                change.ChangeString(question);
                String question1 = change.ChangeOrder();
                System.out.println("后缀表达式为:"+question1);
                Cipher cp = Cipher.getInstance("DESede");
                cp.init(Cipher.ENCRYPT_MODE,k);
                byte ptext[] = question1.getBytes("UTF8");
                byte ctext[] = cp.doFinal(ptext);
                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);
                Thread.sleep(500);
                System.out.println("请输入中缀表达式:");
            }
        }
        catch (IOException e) {
            System.out.println("服务器已断开"+e);
        }
       }
      }
      • 服务器Server
      import java.io.*;
      import java.net.*;
      import javax.crypto.*;
      import javax.crypto.spec.*;
      public class Server {
       public static void main(String[] args) throws Exception{
        ServerSocket serverForClient = null;
        Socket socketOnServer = null;
        DataOutputStream out = null;
        DataInputStream in = null;
        try {
            serverForClient = new ServerSocket(2010);
        } catch (IOException e) {
        System.out.println(e);
        }
        System.out.println("等待客户呼叫");
        try {
            socketOnServer = serverForClient.accept();
            out = new DataOutputStream(socketOnServer.getOutputStream());
            in = new DataInputStream(socketOnServer.getInputStream());
            String keylength = in.readUTF();
            byte []kb = new byte[Integer.parseInt(keylength)];
            System.out.println("收到的密钥为:");
            for(int i = 0;i<Integer.parseInt(keylength);i++) {
                String str = in.readUTF();
                kb[i] = Byte.parseByte(str);
                System.out.print(kb[i] + " ");
            }
            while(true) {
                SecretKeySpec k = new SecretKeySpec(kb, "DESede");
                Cipher cp = Cipher.getInstance("DESede");
                cp.init(Cipher.DECRYPT_MODE, k);
                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);
                }
                byte[] ptext = cp.doFinal(ctext);
                String question = new String(ptext,"UTF8");
                System.out.print("\n后缀表达式为:"+ question);
                MyDC getanswer = new MyDC();
                getanswer.set(question);
                Rational answer = getanswer.get();
                int a = answer.getNumerator();
                int b = answer.getDenominator();
                float result = (float) a / b;
                System.out.println("\n计算出的结果为"+String.format("%.2f",result));
                out.writeUTF(String.format("%.2f",result));
                Thread.sleep(500);
            }
        } catch (IOException e) {
            System.out.println("客户已断开" + e);
        }
       }
      }
    • 测试结果截图

      • 客户端

      • 服务器

  • 4.提交4

    • 实验要求
    1、基于Java Socket实现客户端/服务器功能,传输方式用TCP
    2、客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文发送给服务器
    3、客户端和服务器用DH算法进行3DES或AES算法的密钥交换
    4、服务器接收到后缀表达式表达式后,进行解密,然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    5、客户端显示服务器发送过来的结果
    6、上传测试结果截图和码云链接
    • 实验原理

      • 本部分主要参考Java密码学算法中“使用密钥协定创建共享密钥”部分
      • 对博客中的代码进行了部分更改如下:
        • Key_DHKeyAgree主类的参数改为由客户端和服务器传递,并修改方法名
          • public static void DH(String str1,String str2) throws Exception
          • public static void Agree(String str1,String str2)
        • 客户端和服务器分别产生自己的公钥和私钥,并用过字节数组的形式分别向另一方传递自己的公钥;
        • 客户端和服务器接受对方的公钥后利用自己的私钥创建共享密钥
        • 创建密钥协定对象KeyAgreement ka=KeyAgreement.getInstance("DH");
        • 初始化密钥协定对象ka.init(prk);
        • 执行密钥协定ka.doPhase(pbk,true);
        • 生成共享信息byte[ ] sb=ka.generateSecret();
        • 从文件中读取信息并给出共享密钥
    • 实验代码

      • 客户端Client
      import javax.crypto.Cipher;
      import javax.crypto.spec.SecretKeySpec;
      import java.io.*;
      import java.security.*;
      import java.util.Scanner;
      import java.net.*;
      public class Client {
       public static void main(String[] args) {
        Socket mysocket;
        DataInputStream in=null;
        DataOutputStream out=null;
        Scanner scanner = new Scanner(System.in);
        try {
            System.out.print("输入服务器的IP:");
            String IP = scanner.nextLine();
            InetAddress address=InetAddress.getByName(IP);
            mysocket = new Socket(address, 2010);
            in = new DataInputStream(mysocket.getInputStream());
            out = new DataOutputStream(mysocket.getOutputStream());
            Key_DH.DH("Lpub.dat","Lpri.dat");
            FileInputStream my = new FileInputStream("Lpub.dat");
            ObjectInputStream mypub = new ObjectInputStream(my);
            Key kp = (Key) mypub.readObject();
            ByteArrayOutputStream DH = new ByteArrayOutputStream();
            ObjectOutputStream myDH = new ObjectOutputStream(DH);
            myDH.writeObject(kp);
            byte []pub = DH.toByteArray();
            out.writeUTF(pub.length+"");
            for(int i=0;i<pub.length;i++) {
                out.writeUTF(pub[i]+ "");
            }
            Thread.sleep(1000);
            int length = Integer.parseInt(in.readUTF());
            byte cpub[] = new byte[length];
            for(int i=0;i<length;i++) {
                String temp = in.readUTF();
                cpub[i] = Byte.parseByte(temp);
            }
            ByteArrayInputStream ckey1 = new ByteArrayInputStream(cpub);
            ObjectInputStream ckey = new ObjectInputStream(ckey1);
            Key k = (Key) ckey.readObject();
            FileOutputStream f2 = new FileOutputStream("W1pub.dat");
            ObjectOutputStream b2 = new ObjectOutputStream(f2);
            b2.writeObject(k);
            KeyAgree.Agree("W1pub.dat","Lpri.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("\n请输入中缀表达式:");
            while(scanner.hasNext()) {
                String question = scanner.next();
                MyBC change = new MyBC();
                change.ChangeString(question);
                String question1 = change.ChangeOrder();
                System.out.println("后缀表达式为:" + question1);
                SecretKeySpec k1 = new SecretKeySpec(keysb, "DESede");
                Cipher cp = Cipher.getInstance("DESede");
                cp.init(Cipher.ENCRYPT_MODE, k1);
                byte ptext[] = question1.getBytes("UTF8");
                byte ctext[] = cp.doFinal(ptext);
                System.out.println("加密后的后缀表达式为:");
                for (int i = 0; i < ctext.length; i++) {
                    System.out.print(ctext[i] + " ");
                }
                out.writeUTF(ctext.length + "");
                for (int i = 0; i < ctext.length; i++) {
                    out.writeUTF(ctext[i] + "");
                }
                String s=in.readUTF(); //in读取信息,堵塞状态
                System.out.println("\n客户收到服务器的回答:"+s);
                Thread.sleep(500);
                System.out.println("请输入中缀表达式:");
            }
        }
        catch (Exception e) {
            System.out.println(e);
        }
       }
      }
      • 服务器Server
      import javax.crypto.Cipher;
      import javax.crypto.spec.SecretKeySpec;
      import java.io.*;
      import java.net.ServerSocket;
      import java.net.Socket;
      import java.security.*;
      public class Server {
       public static void main(String[] args) throws Exception {
        ServerSocket serverForClient = null;
        Socket socketOnServer = null;
        DataOutputStream out = null;
        DataInputStream in = null;
        try {
            serverForClient = new ServerSocket(2010);
        } catch (IOException e) {
            System.out.println(e);
        }
        System.out.println("等待客户呼叫");
        try {
            socketOnServer = serverForClient.accept();
            out = new DataOutputStream(socketOnServer.getOutputStream());
            in = new DataInputStream(socketOnServer.getInputStream());
            Key_DH.DH("Wpub.dat","Wpri.dat");
            int length = Integer.parseInt(in.readUTF());
            byte cpub[] = new byte[length];
            for(int i=0;i<length;i++) {
                String temp = in.readUTF();
                cpub[i] = Byte.parseByte(temp);
            }
            ByteArrayInputStream ckey1 = new ByteArrayInputStream(cpub);
            ObjectInputStream ckey = new ObjectInputStream(ckey1);
            Key k1 = (Key) ckey.readObject();
            FileOutputStream f2 = new FileOutputStream("Lpub.dat");
            ObjectOutputStream b2 = new ObjectOutputStream(f2);
            b2.writeObject(k1);
            FileInputStream my = new FileInputStream("Wpub.dat");
            ObjectInputStream mypub = new ObjectInputStream(my);
            Key kp = (Key) mypub.readObject();
            ByteArrayOutputStream DH = new ByteArrayOutputStream();
            ObjectOutputStream myDH = new ObjectOutputStream(DH);
            myDH.writeObject(kp);
            byte []pub = DH.toByteArray();
            out.writeUTF(pub.length+"");
            for(int i=0;i<pub.length;i++) {
                out.writeUTF(pub[i]+ "");
            }
            KeyAgree.Agree("Lpub.dat","Wpri.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]+" ");
            }
            while(true) {
                SecretKeySpec k = new SecretKeySpec(keysb, "DESede");
                Cipher cp = Cipher.getInstance("DESede");
                cp.init(Cipher.DECRYPT_MODE, k);
                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);
                }
                byte[] ptext = cp.doFinal(ctext);
                String question = new String(ptext, "UTF8");
                System.out.print("\n解密后的后缀表达式为:" + question);
                MyDC getanswer = new MyDC();
                getanswer.set(question);
                Rational answer = getanswer.get();
                int a = answer.getNumerator();
                int b = answer.getDenominator();
                float result = (float) a / b;
                System.out.println("\n计算出的结果为"+String.format("%.2f",result));
                out.writeUTF(String.format("%.2f",result));
                Thread.sleep(500);
            }
        }
        catch(Exception e) {
            System.out.println("客户已断开" + e);
        }
       }
      }
    • 测试结果截图

      • 客户端

      • 服务器

  • 5.任务五

    • 实验要求
    1、基于Java Socket实现客户端/服务器功能,传输方式用TCP
    2、客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文和明文的MD5値发送给服务器
    3、客户端和服务器用DH算法进行3DES或AES算法的密钥交换
    4、服务器接收到后缀表达式表达式后,进行解密,解密后计算明文的MD5值,和客户端传来的MD5进行比较,一致则调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    5、客户端显示服务器发送过来的结果
    6、上传测试结果截图和码云链接
    • 实验原理

      • 本部分主要参考Java密码学算法中“Java摘要算法- MD5”部分;
      • 主要在任务四基础上进行操作。
    • 实验代码

      • 客户端Client
      import javax.crypto.Cipher;
      import javax.crypto.spec.SecretKeySpec;
      import java.io.*;
      import java.net.Socket;
      import java.security.*;
      import java.util.Scanner;
      import java.net.*;
      public class Client {
       public static void main(String[] args) {
        Socket mysocket;
        DataInputStream in=null;
        DataOutputStream out=null;
        Scanner scanner = new Scanner(System.in);
        try {
            System.out.print("输入服务器的IP:");
            String IP = scanner.nextLine();
            InetAddress address=InetAddress.getByName(IP);
            mysocket = new Socket(address, 2010);
            in = new DataInputStream(mysocket.getInputStream());
            out = new DataOutputStream(mysocket.getOutputStream());
            Key_DH.DH("Lpub.dat","Lpri.dat");
            FileInputStream my = new FileInputStream("Lpub.dat");
            ObjectInputStream mypub = new ObjectInputStream(my);
            Key kp = (Key) mypub.readObject();
            ByteArrayOutputStream DH = new ByteArrayOutputStream();
            ObjectOutputStream myDH = new ObjectOutputStream(DH);
            myDH.writeObject(kp);
            byte []pub = DH.toByteArray();
            out.writeUTF(pub.length+"");
            for(int i=0;i<pub.length;i++) {
                out.writeUTF(pub[i]+ "");
            }
            Thread.sleep(1000);
            int length = Integer.parseInt(in.readUTF());
            byte cpub[] = new byte[length];
            for(int i=0;i<length;i++) {
                String temp = in.readUTF();
                cpub[i] = Byte.parseByte(temp);
            }
            ByteArrayInputStream ckey1 = new ByteArrayInputStream(cpub);
            ObjectInputStream ckey = new ObjectInputStream(ckey1);
            Key k = (Key) ckey.readObject();
            FileOutputStream f2 = new FileOutputStream("W1pub.dat");
            ObjectOutputStream b2 = new ObjectOutputStream(f2);
            b2.writeObject(k);
            KeyAgree.Agree("W1pub.dat","Lpri.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("\n请输入中缀表达式:");
            while(scanner.hasNext()) {
                String question = scanner.next();
                MyBC change = new MyBC();
                change.ChangeString(question);
                String question1 = change.ChangeOrder();
                System.out.println("后缀表达式为:" + question1);
                String mtoMD5 = DigestPass.MD5(question1);
                System.out.println("明文的MD5值为:"+mtoMD5);
                out.writeUTF(mtoMD5);
                SecretKeySpec k1 = new SecretKeySpec(keysb, "DESede");
                Cipher cp = Cipher.getInstance("DESede");
                cp.init(Cipher.ENCRYPT_MODE, k1);
                byte ptext[] = question1.getBytes("UTF8");
                byte ctext[] = cp.doFinal(ptext);
                System.out.println("加密后的后缀表达式为:");
                for (int i = 0; i < ctext.length; i++) {
                    System.out.print(ctext[i] + " ");
                }
                out.writeUTF(ctext.length + "");
                for (int i = 0; i < ctext.length; i++) {
                    out.writeUTF(ctext[i] + "");
                }
                String s=in.readUTF(); //in读取信息,堵塞状态
                System.out.println("\n客户收到服务器的回答:"+s);
                Thread.sleep(500);
                System.out.println("请输入中缀表达式:");
            }
        }
        catch (Exception e) {
            System.out.println(e);
        }
       }
      }
      • 服务器Server
      import javax.crypto.Cipher;
      import javax.crypto.spec.SecretKeySpec;
      import java.io.*;
      import java.net.ServerSocket;
      import java.net.Socket;
      import java.security.*;
      public class Server {
       public static void main(String[] args) throws Exception {
        ServerSocket serverForClient = null;
        Socket socketOnServer = null;
        DataOutputStream out = null;
        DataInputStream in = null;
        try {
            serverForClient = new ServerSocket(2010);
        } catch (IOException e) {
            System.out.println(e);
        }
        System.out.println("等待客户呼叫");
        try {
            socketOnServer = serverForClient.accept();
            out = new DataOutputStream(socketOnServer.getOutputStream());
            in = new DataInputStream(socketOnServer.getInputStream());
            Key_DH.DH("Wpub.dat","Wpri.dat");
            int length = Integer.parseInt(in.readUTF());
            byte cpub[] = new byte[length];
            for(int i=0;i<length;i++) {
                String temp = in.readUTF();
                cpub[i] = Byte.parseByte(temp);
            }
            ByteArrayInputStream ckey1 = new ByteArrayInputStream(cpub);
            ObjectInputStream ckey = new ObjectInputStream(ckey1);
            Key k1 = (Key) ckey.readObject();
            FileOutputStream f2 = new FileOutputStream("L1pub.dat");
            ObjectOutputStream b2 = new ObjectOutputStream(f2);
            b2.writeObject(k1);
            FileInputStream my = new FileInputStream("Wpub.dat");
            ObjectInputStream mypub = new ObjectInputStream(my);
            Key kp = (Key) mypub.readObject();
            ByteArrayOutputStream DH = new ByteArrayOutputStream();
            ObjectOutputStream myDH = new ObjectOutputStream(DH);
            myDH.writeObject(kp);
            byte []pub = DH.toByteArray();
            out.writeUTF(pub.length+"");
            for(int i=0;i<pub.length;i++) {
                out.writeUTF(pub[i]+ "");
            }
            KeyAgree.Agree("L1pub.dat","Wpri.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]+" ");
            }
            while(true) {
                String c = in.readUTF();
                SecretKeySpec k = new SecretKeySpec(keysb, "DESede");
                Cipher cp = Cipher.getInstance("DESede");
                cp.init(Cipher.DECRYPT_MODE, k);
                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);
                }
                byte[] ptext = cp.doFinal(ctext);
                String question = new String(ptext, "UTF8");
                System.out.println("\n解密后的后缀表达式为:" + question);
                String mtoMD5 = DigestPass.MD5(question);
                System.out.println("MD5的值为"+ mtoMD5);
                if(mtoMD5.equals(c)) {
                    System.out.println("传递的MD5值和解密的后缀表达式的MD5值相同,可以解密!");
                    MyDC getanswer = new MyDC();
                    getanswer.set(question);
                    Rational answer = getanswer.get();
                    int a = answer.getNumerator();
                    int b = answer.getDenominator();
                    float result = (float) a / b;
                    System.out.println("计算出的结果为"+String.format("%.2f",result));
                    out.writeUTF(String.format("%.2f",result));
                }
                else {
                    System.out.println("密文有误,不能解密!");
                }
                Thread.sleep(500);
            }
        }
        catch(Exception e) {
            System.out.println("客户已断开" + e);
        }
       }
      }
    • 测试结果截图

      • 客户端

      • 服务器

三、代码托管

四、实验心得体会

本次实验综合了教材第十三章和Java密码学的相关内容,在和伙伴的讨论中,对于java的网络和安全方面的编程有了更好地掌握。

五、参考资料

Guess you like

Origin www.cnblogs.com/fzlzc/p/10927148.html