20165324 Java实验五 网络编程与安全

20165324 Java实验五 网络编程与安全

一、实验报告封面

课程:Java程序设计 班级:1653班 姓名:何春江 学号:20165324

指导教师:娄嘉鹏 实验日期:2018年5月28日

实验时间:13:45 - 15:25 实验序号:24

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

二、实验内容

任务一:两人一组结对编程:

  1. 参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA
  2. 结对实现中缀表达式转后缀表达式的功能 MyBC.java
  3. 结对实现从上面功能中获取的表达式中实现后缀表达式求值的功能,调用MyDC.java
  4. 上传测试代码运行结果截图和码云链接

实现中缀表达式转后缀表达式

import java.util.Stack;
import java.util.StringTokenizer;

public class MyBC {
    /** constant for addition symbol */
    private final char ADD = '+';
    /** constant for subtraction symbol */
    private final char SUBTRACT = '-';
    /** constant for multiplication symbol */
    private final char MULTIPLY = '*';
    /** constant for division symbol */
    private final char DIVIDE = '/';
    /** the stack */
    Stack<Integer> stack=new Stack<Integer>();;

    String expression;
    public void setExpression(String str) {
        expression=str;
    }
    public  String changedWay() {
        String changedExpression = "";
        Stack signStack = new Stack();// 操作符栈
        for (int i = 0; i < expression.length(); i++) {
            char c = expression.charAt(i);
            if (c >= '0' && c <= '9') {
                changedExpression=changedExpression+c;
            }
            else if (c == '+' || c == '-' || c == '*' || c == '/') {
                changedExpression=changedExpression+" ";//分隔数字
                if (signStack.empty()) {
                    signStack.push(c);
                }
                else if (judgeValue(c) >= judgeValue((Character) signStack.peek())) {//优先级高于或等于,运算符号均进栈
                    signStack.push(c);
                }
                else {
                    changedExpression=changedExpression+(char)signStack.pop();
                    signStack.push(c);
                }
            }
            else if (c=='(') {
                signStack.push(c);
            }
            else if (c==')') {
                while((char)signStack.peek()!='(') {
                    changedExpression=changedExpression+" "+signStack.pop();
                }
                signStack.pop();
            }
        }
        while(!signStack.empty()){
            changedExpression=changedExpression+" "+String.valueOf(signStack.pop());
        }
        return changedExpression;
    }

    private static int judgeValue(char c) {
        int value = 0;
        switch (c) {
            case '(':
                value = 1;
                break;
            case '+':
            case '-':
                value = 2;
                break;
            case '*':
            case '/':
                value = 3;
                break;
            case ')':
                value = 4;
            default:
                value = 0;
        }
        return value;
    }
    public int evaluate (String expr)
    {//后缀表达式的运算方法
        int op1, op2, result = 0;
        String token;
        StringTokenizer tokenizer = new StringTokenizer (expr);//使用StringTokenizer类分解String对象的字符序列,默认为空格符...
        //此时tokenizer为一个分析器
        while (tokenizer.hasMoreTokens()) {
            token = tokenizer.nextToken();
            if (isOperator(token))
            {
                op2 = (stack.pop()).intValue();//出栈
                op1 = (stack.pop()).intValue();//出栈
                result = evalSingleOp (token.charAt(0), op1, op2);//String对象第一个字符转换为char类型的方法为:str.charAt(0)
                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 MULTIPLY:
                result = op1 * op2;
                break;
            case DIVIDE:
                result = op1 / op2;
        }
        return result;
    }
}

参考资料:

任务二:两人一组结对编程:

  1. 参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA
  2. 结对实现中缀表达式转后缀表达式的功能 MyBC.java
  3. 结对实现从上面功能中获取的表达式中实现后缀表达式求值的功能,调用MyDC.java
  4. 上传测试代码运行结果截图和码云链接
  • 获取本机IP地址:DESKTOP-HN1B8O2/172.30.2.248
InetAddress address_3=InetAddress.getLocalHost();
System.out.println(address_3.toString());
  • 结对伙伴的IP为:172.30.4.50 所选端口为:1111
  • 负责客服端的构建,实现代码为:
  • 选用AES加密算法
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.*;

public class Client_2Socket {
    public static void main(String[] args) {
        Socket Client_2Socket;
        DataInputStream Client_2in=null;
        DataOutputStream Client_2out=null;
        String expr,str;
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入表达式:");
        str=scanner.nextLine();
        MyBC mybc=new MyBC();
        mybc.setExpression(str);
        expr=mybc.changedWay();
        try {
            Client_2Socket=new Socket("172.30.2.248",5353);
            Client_2in=new DataInputStream(Client_2Socket.getInputStream());
            Client_2out=new DataOutputStream(Client_2Socket.getOutputStream());
            Client_2out.writeUTF(expr);
            String s=Client_2in.readUTF();
            System.out.println("服务器回复:
"+s);
        }
        catch (Exception e) {
            System.out.println("服务器已断开"+e);
        }
    }
}
  • 结对伙伴负责的服务器端代码为:
import java.io.*;
import java.net.*;
import java.util.*;

public class Server_2 {
    public static void main(String[] args) {
        ServerSocket Server_2forClient_2=null;
        Socket SocketOnServer_2=null;
        DataOutputStream Server_2out=null;
        DataInputStream Server_2in=null;
        try {
            Server_2forClient_2=new ServerSocket(5353);
        }
        catch (IOException e1) {
            System.out.println(e1);
            //e1.printStackTrace();
        }
        try {
            System.out.println("等待客户端呼叫……");
            SocketOnServer_2=Server_2forClient_2.accept();
            Server_2out=new DataOutputStream(SocketOnServer_2.getOutputStream());
            Server_2in=new DataInputStream(SocketOnServer_2.getInputStream());
            String expr=Server_2in.readUTF();
            System.out.println("服务器接收到表达式:"+expr);
            int result;
            MyBC mybc=new MyBC();
            result=mybc.evaluate(expr);
            Server_2out.writeUTF("后缀表达式:"+expr+",运算结果为:"+result);
            Thread.sleep(500);
        }
        catch (Exception e2) {
            System.out.println("客户端已断开"+e2);
        }
    }
}

  • 实验截图

任务三:加密结对编程:1人负责客户端,一人负责服务器

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

public class Client_3 {
    public static void main(String[] args) {
        Socket Client_2Socket;
        DataInputStream Client_2in=null;
        DataOutputStream Client_2out=null;
        String expr=null;
        String str=null;
        String Ciphertext=null;
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入表达式:");
        str=scanner.nextLine();
        MyBC mybc=new MyBC();
        mybc.setExpression(str);
        expr=mybc.changedWay();
        try {
            AES.produceAESKey();//生成AES密钥
            byte[]cc= AES.EncryptionAES(expr);//需要传输的密文,数组形式传输。
            Ciphertext = Base64.getEncoder().encodeToString(cc);//将加密后的密文由byte[]转换为String类型
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            Client_2Socket=new Socket("172.30.2.248",5300);
            Client_2in=new DataInputStream(Client_2Socket.getInputStream());
            Client_2out=new DataOutputStream(Client_2Socket.getOutputStream());
            Client_2out.writeUTF(Ciphertext);
            String s=Client_2in.readUTF();
            System.out.println("服务器回复:
"+s);
        }
        catch (Exception e) {
            System.out.println("服务器已断开"+e);
        }
    }
}

  • 结对伙伴负责构建服务器,代码为:
import sun.security.krb5.internal.crypto.Aes128;

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

public class Server_3 {
    public static void main(String[] args) {
        ServerSocket Server_2forClient_2=null;
        Socket SocketOnServer_2=null;
        DataOutputStream Server_2out=null;
        DataInputStream Server_2in=null;
        try {
            Server_2forClient_2=new ServerSocket(5300);
        }
        catch (IOException e1) {
            System.out.println(e1);
        }
        try {
            System.out.println("等待客户端呼叫……");
            SocketOnServer_2=Server_2forClient_2.accept();
            Server_2out=new DataOutputStream(SocketOnServer_2.getOutputStream());
            Server_2in=new DataInputStream(SocketOnServer_2.getInputStream());
            String Ciphertext=Server_2in.readUTF();//密文
            byte[] data= Base64.getDecoder().decode(Ciphertext);
            String expr= AES.DecryptionAES(data);
            System.out.println("服务器接收到表达式:"+expr);
            int result;
            MyBC mybc=new MyBC();
            result=mybc.evaluate(expr);
            Server_2out.writeUTF("后缀表达式:"+expr+",运算结果为:"+result);
            Thread.sleep(500);
        }
        catch (Exception e2) {
            System.out.println("客户端已断开"+e2);
        }
    }
}

  • 实验截图

任务四:密钥分发结对编程:1人负责客户端,一人负责服务器

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

DH算法相关链接:

  • DH算法原理

  • 密钥交换算法DH(Java实现)

  • 密钥交换实现过程:

    1. 由消息发送的一方构建密钥,这里由甲方构建密钥。
    2. 由构建密钥的一方向对方公布其公钥,这里由甲方向乙方发布公钥。
    3. 由消息接收的一方通过对方公钥构建自身密钥,这里由乙方使用甲方公钥构建乙方密钥。
    4. 由消息接收的一方向对方公布其公钥,这里由乙方向甲方公布公钥。
  • 使用密钥协定创建共享密钥截图:

  • 使用创建的共享密钥就可以对AES的密钥进行加解密。因为生成的共享密钥为DESede密钥类型,则使用DESede加解密模式,密钥为共享密钥其余不变。即将共享密钥保存于文件Key_DESede_DH.dat中即可。

  • 实现关键代码:

        SecretKeySpec k=new  SecretKeySpec(sb,"DESede");
        FileOutputStream  f=new FileOutputStream("A_Key_DESede_DH.dat");//指定产生密钥输出流文件
        ObjectOutputStream b=new  ObjectOutputStream(f);//将对象序列化,以流的方式进行处理
        b.writeObject(k);//通过以对象序列化方式将密钥保存在文件中
        
  • 问题一:生成的共享密钥文件既然是DESede密钥类型,而DESede的长度密钥长度可以是112或168位。但生成的共享密钥的长度不为DESede规定的位数出现错误:java.security.InvalidKeyException: Invalid key length: 128 bytes
  • 问题一解决方法:使用AES密码机也不行..........产生同样的错误。

任务五:完整性校验结对编程:1人负责客户端,一人负责服务器

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

原文地址:https://www.cnblogs.com/20165324hcj/p/9093283.html