• 20175221曾祥杰 实验五《网络编程与安全》


    实验五《网络编程与安全》

    实验报告封面

    课程:Java程序设计 班级:1752班 姓名:曾祥杰 学号:20175221

    指导教师:娄嘉鹏 实验日期:2019年5月26日

    实验时间:13:10 - 15:25 实验序号:21

    实验名称:网络编程与安全

    实验步骤

    • 第一部分

    • 要求:

    • 两人一组结对编程:

    • 0. 参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA

    • 1. 结对实现中缀表达式转后缀表达式的功能 MyBC.java

    • 2. 结对实现从上面功能中获取的表达式中实现后缀表达式求值的功能,调用MyDC.java

    • 3. 上传测试代码运行结果截图和码云链接

    • 相关原理:

    • 栈 (Stack)是一种只允许在表尾插入和删除的线性表,有先进后出(FILO),后进先出(LIFO)的特点。允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom)。栈的一个应用是用来对四则运算表达式进行求值。
    • 表达式 Exp = S1 + OP + S2 (S1 ,S2是两个操作数,OP为运算符)有三种标识方法:

    • OP + S1 + S2  为前缀表示法
    • S1 + OP + S2  为中缀表示法
    • S1 + S2 + OP  为后缀表示法
    • Java中有Stack类,以及一些方法:
    • empty()

    • push()

    • pop()
    • 具体操作

    • 我们可以使用栈来实现dc 。对逆波兰式求值时,不需要再考虑运算符的优先级,只需从左到右扫描一遍后缀表达式即可。求值伪代码如下:

    • 1.设置一个操作数栈,开始栈为空;
      2.从左到右扫描后缀表达式,遇操作数,进栈;
      3.若遇运算符,则从栈中退出两个元素,先退出的放到运算符的右边,后退出的放到运算符左边,运算后的结果再进栈,直到后缀表达式扫描完毕。
      4.此时,栈中仅有一个元素,即为运算的结果。
    • MyBC.java

    • import java.util.*;
      /**
       * @author 20175221 Zxj
       */
      public class MyBC {
          private Stack<String> stack;
          private List<String> list;
          private String information;
          private String Information = "";
          public MyBC() {
              stack = new Stack<String>();//设立一个栈,存放运算符
              list = new ArrayList<String>();//创建一个表,存放操作数及运算符
          }
          public void conversion(String exp) {   //中缀转后缀
              String element ;
              StringTokenizer tokenizer = new StringTokenizer(exp);
              while (tokenizer.hasMoreTokens()) {  //当tokenizer有下一个值时,进行循环,并把值赋给element
                  element  = tokenizer.nextToken();
                  if (element.equals("(")) {  //若是左括号,入栈
                      stack.push(element);
                  }
                  else if (element.equals("+") || element.equals("-")) {  //若是“+”或“-”,继续判断栈是否为空
                      if (!stack.empty()) {  //若栈非空,判断栈顶元素
                          if (stack.peek().equals("(")) {  //若栈顶为“(”,运算符入栈
                              stack.push(element);
                          }
                          else {  //否则先把栈顶元素移除,加到表中,再将运算符入栈
                              list.add(stack.pop());
                              stack.push(element);
                          }
                      }
                      else {  //若栈为空,运算符入栈
                          stack.push(element);
                      }
                  }
                  else if (element.equals("*") || element.equals("/")) {  //若是“*”或“/”,继续判断栈是否为空
                      if (!stack.empty()) {  //若栈非空,判断栈顶元素是什么
                          if (stack.peek().equals("*") || stack.peek().equals("/")) {  //若栈顶为“*”或“/”,先把栈顶元素移除,加到表中,再将运算符入栈
                              list.add(stack.pop());
                              stack.push(element);
                          }
                          else {  //若栈顶为其他,运算符直接入栈
                              stack.push(element);
                          }
                      }
                      else {  //若栈为空,运算符直接入栈
                          stack.push(element);
                      }
                  }
                  else if (element.equals(")")) {  //若遇到“)”,开始循环
                      while (true) {  //先把栈顶元素移除并赋给temp
                          String temp = stack.pop();
                          if (!temp.equals("(")) {  //若temp不为“(”,则加到表
                              list.add(temp);
                          }
                          else {  //若temp为“(”,退出循环
                              break;
                          }
                      }
                  }
                  else {  //若为操作数,进入列表
                      list.add(element);
                  }
              }
              while (!stack.empty()) {  //将栈中元素取出,加到列表中,直到栈为空
                  list.add(stack.pop());
              }
              ListIterator<String> List = list.listIterator();  //返回此列表元素的列表迭代器
              while (List.hasNext()) {  //将迭代器中的元素依次取出,并加上空格作为分隔符
                  Information += List.next() + " ";
                  List.remove();
              }
              information = Information;
          }
      
          public String getInformation() {
              return information;
          }
      }
    • 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 exp){
              int op1,op2,result = 0;
              String element;
              StringTokenizer tokenizer = new StringTokenizer(exp);
              while(tokenizer.hasMoreTokens()){
                  element = tokenizer.nextToken();
                  if(isOperator(element)){
                      op2 = (stack.pop().intValue());
                      op1 = (stack.pop().intValue());
                      result = evalSingleOp(element.charAt(0),op1,op2);
                      stack.push(new Integer(result));
                  }
                  else {
                      stack.push(new Integer((Integer.parseInt(element))));
                  }
              }
              return result;
          }
          private boolean isOperator(String element){
              return (element.equals("+")||element.equals("-")||element.equals("*")||element.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;
          }
      }
    • MyDCTest.java

    • import java.util.*;
      public class MyDCTester {
          public static void main(String[] args) {
              int result;
              String exp;
              MyBC bc = new MyBC();
              MyDC dc = new MyDC();
              System.out.println("请输入中缀表达式:");
              Scanner in = new Scanner(System.in);
              exp = in.nextLine();
              bc.conversion(exp);
              System.out.println("后缀表达式为:
      "+bc.getInformation());
              result = dc.evaluate(bc.getInformation());
              System.out.println("计算结果为:
      "+result);
          }
      }
    • 运行如下:
    • 第二部分

    • 要求:

    •  结对编程:1人负责客户端,一人负责服务器

    • 0. 注意责任归宿,要会通过测试证明自己没有问题

    • 1. 基于Java Socket实现客户端/服务器功能,传输方式用TCP

    • 2. 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式通过网络发送给服务器

    • 3. 服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端

    • 4. 客户端显示服务器发送过来的结果

    • 5. 上传测试结果截图和码云链接

    • 相关原理:

    • 套接字是一个网络连接的端点。在java中,使用java.net.Socket对象来表示一个套接字。
    • 客户端套接字 Socket clientSocket = new Socket("服务器IP地址",端口号) 
    • 服务器端套接字 SeverSocket severForClient = new SeverSocket(端口号) 
    • 使用 close() 关闭套接字链接
    • 具体操作:

    • 我和 20175120 结对编程,我负责客户端
    • 首先查看自己电脑的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());
          }
      }


       

    • Client.java

    • import java.io.*;
      import java.net.*;
      
      public class Client {
          public static void main(String args[]) {
              System.out.println("20175221 正在启动...");//向服务器端发送信息
              Socket mysocket;//创建客户端Socket
              DataInputStream in = null;
              DataOutputStream out = null;
              try {
                  mysocket = new Socket("169.254.245.151", 2010);//客户端指向服务器地址和端口
                  in = new DataInputStream(mysocket.getInputStream());
                  out = new DataOutputStream(mysocket.getOutputStream());
                  System.out.println("请输入中缀表达式:");//向本机的2010端口发出客户请求
                  String string = new BufferedReader(new InputStreamReader(System.in)).readLine();
                  MyBC conv = new MyBC();
                  conv.conversion(string);
                  String string1 = conv.getInformation();
                  out.writeUTF(string1);
                  String reply = in.readUTF();//in读取信息,堵塞状态
                  System.out.println("20175221 收到 20175120 的回答:
      " + reply);// 从Server读入字符串,并打印
                  Thread.sleep(2000);
              } catch (Exception e) {
                  System.out.println("20175120 已掉线" + e);//输出异常
              }
          }
      }
    • Server.java

    • import java.io.*;
      import java.net.*;
      
      public class Server {
          public static void main(String[] args) throws IOException {
              int reply;
              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("等待 20175221 呼叫...");
                  socketOnServer = serverForClient.accept(); //堵塞状态,除非20175221呼叫
                  in = new DataInputStream(socketOnServer.getInputStream());
                  out = new DataOutputStream(socketOnServer.getOutputStream());
                  String information = in.readUTF(); // in读取信息,堵塞状态
                  System.out.println("20175120 收到 20175221 的提问:" + information);
                  MyDC mydc = new MyDC();
                  reply = mydc.evaluate(information);
                  out.writeUTF(reply + "");
                  Thread.sleep(2000);
              } catch (Exception e) {
                  System.out.println("20175221 已掉线" + e);
              }
          }
      }
    • 运行如下:
    • 第三部分

    • 要求:

    • 加密结对编程:1人负责客户端,一人负责服务器
    • 0. 注意责任归宿,要会通过测试证明自己没有问题
    • 1. 基于Java Socket实现客户端/服务器功能,传输方式用TCP
    • 2. 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密后通过网络把密文发送给服务器
    • 3. 服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,可以用数组保存),然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    • 4. 客户端显示服务器发送过来的结果
    • 5. 上传测试结果截图和码云链接
    • 相关原理:

    • 由于老师曾经在课上就让我们练习过用DES加解密自己的学号姓名,所以相较AES密码算法,DES比较熟悉,因此我们选择DES。
    • DES算法参考娄老师的博客“Java 密码学算法
    • 实现DES加密主要有以下几个步骤:
    • 对称密钥的生成和保存;
    • 使用对称密钥进行加密和解密;
    • 从文件中获取加密时使用的密钥,使用密钥进行解密。
    • 具体操作:

    • 编程思路:
    • 1.获取密钥生成器

    •  KeyGenerator kg=KeyGenerator.getInstance("DESede"); 
    • 2.初始化密钥生成器
    •  kg.init(168); 
    • 3. 生成密钥
    •  SecretKey k=kg.generateKey( ); 
    • 4.通过对象序列化方式将密钥保存在文件中
    • FileOutputStream f=new FileOutputStream("key1.dat");
       ObjectOutputStream b=new ObjectOutputStream(f);
       b.writeObject(k);
    • 我依旧负责的是客户端, Client.java 在刚才的基础上增加了使用DES算法加密的部分,实现DES的加密
    • Client.java

    • import javax.crypto.Cipher;
      import java.io.*;
      import java.net.Socket;
      import java.security.Key;
      import java.util.Scanner;
      
      public class Client {
          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 string;
              try {
                  mysocket = new Socket("169.254.245.151", 5221);
                  in = new DataInputStream(mysocket.getInputStream());
                  out = new DataOutputStream(mysocket.getOutputStream());
                  System.out.println("20175221 正在启动...");
                  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("请输入中缀表达式:");
                  string = scanner.nextLine();
                  mybc.conversion(string);
                  String string1 = mybc.getInformation();
                  byte ptext[] = string1.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();
                  System.out.println("20175221 收到 20175120 的回应:
      " + s);
              } catch (Exception e) {
                  System.out.println("20175120 已掉线..." + e);
              }
          }
      }
    • Server.java

    • import javax.crypto.Cipher;
      import javax.crypto.spec.SecretKeySpec;
      import java.io.*;
      import java.net.ServerSocket;
      import java.net.Socket;
      
      public class Server {
          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(5221);
              } catch (IOException e1) {
                  System.out.println(e1);
              }
              try {
                  System.out.println("等待 20175221 下达命令...");
                  socketOnServer = serverForClient.accept(); //堵塞状态,除非 20175221 呼叫
                  System.out.println("20175221 终于连接上了");
                  out = new DataOutputStream(socketOnServer.getOutputStream());
                  in = new DataInputStream(socketOnServer.getInputStream());
                  String str = in.readUTF(); // in读取信息,堵塞状态
                  byte ctext[] = new byte[Integer.parseInt(str)];
                  for (int i = 0;i<Integer.parseInt(str);i++) {
                      String temp = in.readUTF();
                      ctext[i] = Byte.parseByte(temp);
                  }
                  // 获取密钥
                  FileInputStream f = new FileInputStream("keykb1.dat");
                  int num = f.available();
                  byte[] keykb = new byte[num];
                  f.read(keykb);
                  SecretKeySpec k = new SecretKeySpec(keykb, "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 s = mydc.evaluate(p)+"";
                  System.out.println("解密后的后缀表达式:
      " + p);
                  System.out.println("开始计算后缀表达式:
      " + p);
                  System.out.println("后缀表达式的值为:
      " + s);
                  out.writeUTF(mydc.evaluate(p)+"");
                  System.out.println("20175120 正在将值传给 20175221...");
              } catch (Exception e) {
                  System.out.println("20175221 已掉线..." + e);
              }
          }
      }


       

    • 运行如下:

    • 第四部分
    • 要求:

    • 密钥分发结对编程:1人负责客户端,一人负责服务器
    • 0. 注意责任归宿,要会通过测试证明自己没有问题
    • 1. 基于Java Socket实现客户端/服务器功能,传输方式用TCP
    • 2. 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文发送给服务器
    • 3. 客户端和服务器用DH算法进行3DES或AES算法的密钥交换
    • 4. 服务器接收到后缀表达式表达式后,进行解密,然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    • 5. 客户端显示服务器发送过来的结果
    • 6. 上传测试结果截图和码云链接
    • 相关原理:

    • DH算法大致分为以下两步:
    • 1.创建DH公钥和私钥;
    • 2.创建共享密钥。
    • 具体操作:

    • Client.java

    • 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 Client {
          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("169.254.245.151", 5221);
                  System.out.println("20175221 正在启动...");
                  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.getInformation();
                  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("20175221 收到 20175120 的回应:" + s);
              } catch (Exception e) {
                  System.out.println("20175120 已掉线..." + e);
              }
          }
      }
      • Server.java

      • 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 Server {
            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(5221);
                } catch (IOException e1) {
                    System.out.println(e1);
                }
                try {
                    System.out.println("等待 20175221 下达命令...");
                    socketOnServer = serverForClient.accept(); //堵塞状态,除非 20175221 呼叫
                    System.out.println("20175221 终于连接上了!");
                    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");
                    String s = mydc.evaluate(p)+"";
                    System.out.println("解密后的后缀表达式:" + p);
                    System.out.println("开始计算后缀表达式: " + p);
                    System.out.println("后缀表达式的值为:"+ s);
                    out.writeUTF(mydc.evaluate(p)+"");
                    System.out.println("20175120 正在将值传给 20175221...");
                } catch (Exception e) {
                    System.out.println("20175221 已掉线..." + e);
                }
            }
        }


         

        • 运行如下

        • 第五部分

        • 要求:

        • 完整性校验结对编程:1人负责客户端,一人负责服务器
        • 0. 注意责任归宿,要会通过测试证明自己没有问题
        • 1. 基于Java Socket实现客户端/服务器功能,传输方式用TCP
        • 2. 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文和明文的MD5値发送给服务器
        • 3. 客户端和服务器用DH算法进行3DES或AES算法的密钥交换
        • 4. 服务器接收到后缀表达式表达式后,进行解密,解密后计算明文的MD5值,和客户端传来的MD5进行比较,一致则调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
        • 5. 客户端显示服务器发送过来的结果
        • 6. 上传测试结果截图和码云链接
        • 相关原理:                        

        • 可以使用Java计算指定字符串的消息摘要

        •  update() 可以将原始数据传递给该对象

        •  digest() 可以得到消息摘要    

        • 具体操作:

        • Client.java

        • 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 Client {
              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("169.254.245.151", 5221);
                      System.out.println("20175221 正在启动...");
                      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.getInformation();
                      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("20175221 收到 20175120 的回应:
          " + s);
                  } catch (Exception e) {
                      System.out.println("20175120 已掉线..." + e);
                  }
              }
          }
        • Server.java

        • 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 Server {
              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(5221);
                  } catch (IOException e1) {
                      System.out.println(e1);
                  }
                  try {
                      System.out.println("等待 20175221 呼叫...");
                      socketOnServer = serverForClient.accept(); //堵塞状态,除非有客户呼叫
                      System.out.println("20175221 终于连接上了!");
                      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 s = mydc.evaluate(p)+"";
                      String pMd5 = DigestPass.DP(p);
                      System.out.println("解密得到明文的MD5值:
          "+pMd5);
                      if (pMd5.equals(check)){
                          System.out.println("已验证与 20175221 的MD5值一致");
                          System.out.println("计算后缀表达式: 
          " + p);
                          out.writeUTF(mydc.evaluate(p)+"");
                          System.out.println("后缀表达式的值为:
          "+ s);
                      }
                      else {
                          System.out.println("警告!!! MD5值不一致!你是不是背叛了 20175221!");
                      }
                  } catch (Exception e) {
                      System.out.println("20175221 已掉线..." + e);
                  }
              }
          }
        • 运行如下:
        •  
    • 码云链接

    实验体会:

    • 此次实验的内容是网络编程,同时要求两人结对完成。基本上所有的实验点都与客户端和服务器有关,我主要负责客户端,我的搭档负责服务器。这就要求我们俩要配合默契,不能有一个人没有完成指定的任务,否则就达不到实验点的要求。
    • 在这次实验之前,虽然有看过一些Java网络编程理论的内容。但等我真正自己动手操作时,发现其实还是有许多与预想不一样的地方,这就是慢慢修改,考验耐心的时刻,但很庆幸我挺了过来。
    • 在和搭档一起做实验的过程中,我们也复习了网络编程和密码学算法的相关知识,参考了书上代码和以及娄老师的博客---Java 密码学算法,我们着实在这个过程中学到了很多新的内容。
    • 这次结对编程,相当于减轻了一半的工作量。为了给这次实验增添一些乐趣,我们也是尽可能把一些语言丰富。
    • 这是Java的最后一次实验,我收获颇丰,感激这一段学习Java的时间。
    步骤耗时百分比
    需求分析 10min 5%
    设计 40min 20%
    代码实现 100min 50%
    测试 30min 15%
    分析总结 20min 10%

     参考资料

  • 相关阅读:
    【作业7】完成调查问卷
    用博客园第一周
    讲座观后感
    调查问卷
    第十一周·前端学习笔记--正则表达式
    调查问卷
    思维导图
    讲座心得1
    第一次作业(8.学习进度表)
    第一次作业(7.问卷调查)
  • 原文地址:https://www.cnblogs.com/zxja/p/10925619.html
Copyright © 2020-2023  润新知