实验五 网络编程与安全


课程:Java程序设计 班级:1752班 姓名:李得琛 学号:20175206
指导教师:娄嘉鹏
实验日期:2019年5月29日
实验序号:实验五
实验名称:网络编程与安全

实验五 网络编程与安全-1

两人一组结对编程:
0. 参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA

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

实验步骤

栈 (Stack)是一种只允许在表尾插入和删除的线性表,有先进后出(FILO),后进先出(LIFO)的特点。允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom)
OP + S1 + S2 为前缀表示法
S1 + OP + S2 为中缀表示法
S1 + S2 + OP 为后缀表示法
在这里面我们主要讨论中缀转后缀
部分中转后代码:

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 class action {
    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;
    }
    action add(action r) {  //加法运算
        int a=r.getNumerator();
        int b=r.getDenominator();
        int newNumerator=numerator*b+denominator*a; //计算出新分子
        int newDenominator=denominator*b;           //计算出新分母
        action result=new action();
        result.setNumerator(newNumerator);
        result.setDenominator(newDenominator);
        return result;
    }
    action sub(action r) {  //减法运算
        int a=r.getNumerator();
        int b=r.getDenominator();
        int newNumerator=numerator*b-denominator*a;
        int newDenominator=denominator*b;
        action result=new action();
        result.setNumerator(newNumerator);
        result.setDenominator(newDenominator);
        return result;
    }
    action muti(action r) { //乘法运算
        int a=r.getNumerator();
        int b=r.getDenominator();
        int newNumerator=numerator*a;
        int newDenominator=denominator*b;
        action result=new action();
        result.setNumerator(newNumerator);
        result.setDenominator(newDenominator);
        return result;
    }
    action div(action r)  { //除法运算
        int a=r.getNumerator();
        int b=r.getDenominator();
        int newNumerator=numerator*b;
        int newDenominator=denominator*a;
        action result=new action();
        if(a==0) {
            System.out.println("该算式无解");
            result.setNumerator(0);
        }
        else {
            result.setNumerator(newNumerator);
            result.setDenominator(newDenominator);
        }
        return result;
    }
}

后缀调用:

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 action get() {
        action op1 = new action();
        action op2 = new action();
        action result = new action();
        result.setNumerator(0);
        StringTokenizer token = new StringTokenizer(q, " ");
        String temp;
        while (token.hasMoreTokens()) {
            temp = token.nextToken();
            if (Isop(temp) == 1)//遇到操作符,弹出栈顶的两个数进行运算
            {
                op2 = (action) stack.pop();
                op1 = (action) stack.pop();//弹出最上面两个操作数
                result = cal(temp.charAt(0), op1, op2);//根据运算符进行运算
                stack.push(result);//将计算结果压栈
            } else {
                action num = new action();
                num.setNumerator(Integer.parseInt(temp));
                stack.push(num);//操作数入栈
            }
        }
        return result;
    }

    action cal(char op, action a, action b) {           //对栈顶弹出的两个数进行运算
        action c = new action();
        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;
        }
    }
}

测试程序BCTEST.java

import java.util.*;

public class BCTEST {
    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);
        action 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));
    }
}

实验截图

后缀:

中转后:

中转后带括号:

实验五 网络编程与安全-2

结对编程:1人负责客户端,一人负责服务器
0. 注意责任归宿,要会通过测试证明自己没有问题!

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

实验步骤

在这里面先建立客户端和服务器之间的连接,鉴于是一台电脑同做服务器与客户端,那么IP地址填写本机客户端即可,否则将填写所在用户机IP地址

首先需要查明IP地址,本次用于作为客户端IP地址为192.168.1.239,如下面截图所示

因需要实现Java Socket的功能,我们使用命令mysocket = new Socket();来输入客户端IP以及其接口

客户端调用中转后mybc,服务器调用mydc

传输数据后即可看到结果,先启动服务器,在启动客户端。

代码部分如下:

调用部分:

  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);
                action 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);
            }
        } 

传输部分:

  String IP = scanner.nextLine();
            InetAddress  address=InetAddress.getByName(IP);
            mysocket = new Socket(address, 2010);
            in=new DataInputStream(mysocket.getInputStream());
            out=new DataOutputStream(mysocket.getOutputStream());

实验截图

查询IP:

服务器:

客户端:

实验五 网络编程与安全-3

加密结对编程:1人负责客户端,一人负责服务器
0. 注意责任归宿,要会通过测试证明自己没有问题

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

实验步骤

继承上述步骤,将输入的表达式进行加密传输 ,双方均可看到密钥及数据,本次使用DES进行加密

调用DES加密进行处理

DES加密格式代码:

 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);

即可看到结果

实验截图

服务器:

客户端:

实验五 网络编程与安全-4

密钥分发结对编程:1人负责客户端,一人负责服务器
0. 注意责任归宿,要会通过测试证明自己没有问题

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

实验步骤

继承实验三,使用DH算法将DES算法的密钥进行交换,服务器收到后解密,调用后缀进行计算,把结果返回客户端

在这里使用了DH算法

DH算法

1、初始化发送方的密钥
2、初始化接受方的密钥
3、密钥构建
4、加密和解密

DH代码:

(byte)0xF4, (byte)0x88, (byte)0xFD, (byte)0x58,
            (byte)0x4E, (byte)0x49, (byte)0xDB, (byte)0xCD,
            (byte)0x20, (byte)0xB4, (byte)0x9D, (byte)0xE4,
            (byte)0x91, (byte)0x07, (byte)0x36, (byte)0x6B,
            (byte)0x33, (byte)0x6C, (byte)0x38, (byte)0x0D,
            (byte)0x45, (byte)0x1D, (byte)0x0F, (byte)0x7C,
            (byte)0x88, (byte)0xB3, (byte)0x1C, (byte)0x7C,
            (byte)0x5B, (byte)0x2D, (byte)0x8E, (byte)0xF6,
            (byte)0xF3, (byte)0xC9, (byte)0x23, (byte)0xC0,
            (byte)0x43, (byte)0xF0, (byte)0xA5, (byte)0x5B,
            (byte)0x18, (byte)0x8D, (byte)0x8E, (byte)0xBB,
            (byte)0x55, (byte)0x8C, (byte)0xB8, (byte)0x5D,
            (byte)0x38, (byte)0xD3, (byte)0x34, (byte)0xFD,
            (byte)0x7C, (byte)0x17, (byte)0x57, (byte)0x43,
            (byte)0xA3, (byte)0x1D, (byte)0x18, (byte)0x6C,
            (byte)0xDE, (byte)0x33, (byte)0x21, (byte)0x2C,
            (byte)0xB5, (byte)0x2A, (byte)0xFF, (byte)0x3C,
            (byte)0xE1, (byte)0xB1, (byte)0x29, (byte)0x40,
            (byte)0x18, (byte)0x11, (byte)0x8D, (byte)0x7C,
            (byte)0x84, (byte)0xA7, (byte)0x0A, (byte)0x72,
            (byte)0xD6, (byte)0x86, (byte)0xC4, (byte)0x03,
            (byte)0x19, (byte)0xC8, (byte)0x07, (byte)0x29,
            (byte)0x7A, (byte)0xCA, (byte)0x95, (byte)0x0C,
            (byte)0xD9, (byte)0x96, (byte)0x9F, (byte)0xAB,
            (byte)0xD0, (byte)0x0A, (byte)0x50, (byte)0x9B,
            (byte)0x02, (byte)0x46, (byte)0xD3, (byte)0x08,
            (byte)0x3D, (byte)0x66, (byte)0xA4, (byte)0x5D,
            (byte)0x41, (byte)0x9F, (byte)0x9C, (byte)0x7C,
            (byte)0xBD, (byte)0x89, (byte)0x4B, (byte)0x22,
            (byte)0x19, (byte)0x26, (byte)0xBA, (byte)0xAB,
            (byte)0xA2, (byte)0x5E, (byte)0xC3, (byte)0x55,
            (byte)0xE9, (byte)0x2F, (byte)0x78, (byte)0xC7

生成一系列的dat文件在这里是一堆乱码,就不在这里表达了。

实验截图

服务器:

客户端:

实验五 网络编程与安全-5

完整性校验结对编程:1人负责客户端,一人负责服务器
0. 注意责任归宿,要会通过测试证明自己没有问题

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

实验步骤

MD5:

MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。

MD5算法具有以下特点:

压缩性:任意长度的数据,算出的MD5值长度都是固定的。
容易计算:从原数据计算出MD5值很容易。
抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。

使用MD5对DES进行加解密的过程,与DH过程类似

MD5代码:

public class MD5{
    public static String MD5(String str) throws Exception{
        String x=str;
        MessageDigest m=MessageDigest.getInstance("MD5");
        m.update(x.getBytes("UTF8"));
        byte s[ ]=m.digest( );
        String result="";
        for (int i=0; i<s.length; i++){
            result+=Integer.toHexString((0x000000ff & s[i]) |
                    0xffffff00).substring(6);
        }
        return result;
    }
}

实验截图

服务器:

客户端:

.

参考资料

数据结构应用

java密码学算法

代码链接

20175206李得琛

总结分析

步骤 耗时 百分比
需求分析 10min 12.5%
设计 15min 18.75%
代码实现 30min 37.5%
测试 5min 6.25%
分析总结 20min 25%
posted @ 2019-05-27 22:09  20175206ldc  阅读(467)  评论(0编辑  收藏  举报