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

20172319 2018.06.13-20

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

课程名称:《程序设计与数据结构》  
学生班级:1723班  
学生姓名:唐才铭  
学生学号:20172319 
实验教师:王志强老师
课程助教:刘伟康、张旭升学长
实验时间:2018年6月13日——2018年6月20日
必修/选修:必修

目录


实验内容

  1. 参考数据结构应用
    结对实现中缀表达式转后缀表达式的功能 MyBC.java
    结对实现从上面功能中获取的表达式中实现后缀表达式求值的功能,调用MyDC.java
    上传测试代码运行结果截图和码云链接;
  2. 结对编程:1人负责客户端,一人负责服务器
    注意责任归宿,要会通过测试证明自己没有问题
    基于Java Socket实现客户端/服务器功能,传输方式用TCP
    客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式通过网络发送给服务器
    服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    客户端显示服务器发送过来的结果
    上传测试代码运行结果截图和码云链接;
  3. 加密结对编程:1人负责客户端,一人负责服务器
    注意责任归宿,要会通过测试证明自己没有问题
    基于Java Socket实现客户端/服务器功能,传输方式用TCP
    客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密后通过网络把密文发送给服务器
    服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,可以用数组保存),然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    客户端显示服务器发送过来的结果
    上传测试结果截图和码云链接;
  4. 密钥分发结对编程:1人负责客户端,一人负责服务器
    注意责任归宿,要会通过测试证明自己没有问题
    基于Java Socket实现客户端/服务器功能,传输方式用TCP
    客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文发送给服务器
    客户端和服务器用DH算法进行3DES或AES算法的密钥交换
    服务器接收到后缀表达式表达式后,进行解密,然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    客户端显示服务器发送过来的结果
    上传测试结果截图和码云链接;
  5. 完整性校验结对编程:1人负责客户端,一人负责服务器
    注意责任归宿,要会通过测试证明自己没有问题
    基于Java Socket实现客户端/服务器功能,传输方式用TCP
    客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文和明文的MD5値发送给服务器
    客户端和服务器用DH算法进行3DES或AES算法的密钥交换
    服务器接收到后缀表达式表达式后,进行解密,解密后计算明文的MD5值,和客户端传来的MD5进行比较,一致则调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    客户端显示服务器发送过来的结果
    上传测试结果截图和码云链接:

返回目录


实验要求

  1. 完成蓝墨云上与实验五《网络编程与安全》相关的活动,及时提交代码运行截图和码云Git链接,截图要有学号水印,否则会扣分。
  2. 完成实验、撰写实验报告,实验报告以博客方式发表在博客园,注意实验报告重点是运行结果,遇到的问题(工具查找,安装,使用,程序的编辑,调试,运行等)、解决办法(空洞的方法如“查网络”、“问同学”、“看书”等一律得0分)以及分析(从中可以得到什么启示,有什么收获,教训等)。报告可以参考范飞龙老师的指导
  3. 严禁抄袭,有该行为者实验成绩归零,并附加其他惩罚措施。
  4. 结对编程;也可自己在idea和虚拟机间进行传输;idea本身也可以进行服务器与客户端的传输。

返回目录


实验步骤

  1. 完成蓝墨云上实验五 网络编程与安全-1
  2. 完成蓝墨云上实验五 网络编程与安全-2
  3. 完成蓝墨云上实验五 网络编程与安全-3
  4. 完成蓝墨云上实验五 网络编程与安全-4
  5. 完成蓝墨云上实验五 网络编程与安全-5

前期准备:

  1. 弄清自己的IP地址是什么:
    Linux下查找IP的命令:ifconfig -a

    Windows下查找IP的命令:ipconfig

    Windows下查找IP(笨方法):开始——设置——网络和Internet——WLAN——硬件属性

需求分析:

  1. 需要在原Socket代码上加以理解并运用;
  2. 需要掌握、并会运用实验三java密码学所学的知识。

返回目录


代码实现及解释

本次实验一共分为五个提交点:

  • 任务1:

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

  • 分别运用四则运算时的中缀转后缀、后缀求值的方法即可:

  • MyBC.java;MyDC.java

  • 截图如下:

  • 任务2:

  • 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式通过网络发送给服务器
    服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端。

  • 弄懂Socket的两个代码,将传输信息的内容换掉即可。

  • SocketClient_2.java;SocketServer_2.java

  • 对客户端代码的修改:

String info1 = "12 15 8 100 25 34 19";

   变为

 //客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式通过网络发送给服务器
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入中缀表达式");
        String info1 = scanner.nextLine();
        info1 = MyBC.infixToSuffix(info1);
  • 对服务器代码的修改:
 String info=null;
        if (!((info = bufferedReader.readLine()) ==null)){
            System.out.println("我是服务器,用户信息为:" + info);
        }

        //给客户一个响应
        //String reply=Output;
        String reply = "welcome";
        printWriter.write(reply);

   变为

 String info=null;
        if (!((info = bufferedReader.readLine()) ==null)){
            System.out.println("我是服务器,用户信息为:" + info);
        }

        //服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
        String reply = MyDC.suffixToArithmetic(info);

        printWriter.write(reply);
  • 运行结果如下:

  • 任务3:

  • 让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密后通过网络把密文发送给服务器
    服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,可以用数组保存),然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端。

  • 运用java密码学里的3DES算法;先对文件SEnc.java(加密)和SDec.java(解密)进行修改,使其从void变为String方法,返回密、明文;在客户端与服务器分别对需要传输的信息运用加解密方法。

  • 客户端:

 //客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入中缀表达式");
        String info1 = scanner.nextLine();
        info1 = MyBC.infixToSuffix(info1);

        //把后缀表达式用3DES或AES算法加密后通过网络把密文发送给服务器
        try {
            info1 = SEnc.encrypt(info1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        String info = new String(info1.getBytes("GBK"),"utf-8");
        //     printWriter.write(info);
        //     printWriter.flush();
        outputStreamWriter.write(info);
        outputStreamWriter.flush();
        socket.shutdownOutput();
  • 服务器:
 //4.读取用户输入信息
        String info=null;
        if (!((info = bufferedReader.readLine()) ==null)){
            System.out.println("我是服务器,用户信息为:" + info);
        }

        //接收到后缀表达式表达式后,进行解密
        try {
            info = SDec.decode(info);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
        String reply = MyDC.suffixToArithmetic(info);

        printWriter.write(reply);
        printWriter.flush();
  • 运行结果:

  • 任务4:

  • 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文发送给服务器
    客户端和服务器用DH算法进行3DES或AES算法的密钥交换
    服务器接收到后缀表达式表达式后,进行解密,然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端。

  • 修改java密码学中的Key_DH.java的代码,运行后分别生成客户端与服务器的公私钥;

  • Key_DH_Client.java;Key_DH_Server.java

  • 运行结果如图:

  • 对客户端的代码修改:

//客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入中缀表达式");
        String info1 = scanner.nextLine();
        info1 = MyBC.infixToSuffix(info1);

        //把后缀表达式用3DES或AES算法加密后通过网络把密文发送给服务器
        try {
            info1 = SEnc.encrypt(info1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 客户端和服务器用DH算法进行3DES或AES算法的密钥交换
        try{
            // 读取对方的DH公钥
            FileInputStream f1=new FileInputStream("Bpub.dat");
            ObjectInputStream b1=new ObjectInputStream(f1);
            PublicKey  pbk=(PublicKey)b1.readObject( );
            //读取自己的DH私钥
            FileInputStream f2=new FileInputStream("Apri.dat");
            ObjectInputStream b2=new ObjectInputStream(f2);
            PrivateKey  prk=(PrivateKey)b2.readObject( );
            // 执行密钥协定
            KeyAgreement ka=KeyAgreement.getInstance("DH");
            ka.init(prk);
            ka.doPhase(pbk,true);
            System.out.println("\n" + "公钥为:");
            //生成共享信息
            byte[ ] sb=ka.generateSecret();
            for(int i=0;i<sb.length;i++){
                System.out.print(sb[i]+",");
            }
            SecretKeySpec k=new  SecretKeySpec(sb,"DESede");
        } catch (Exception e) {
            e.printStackTrace();
        }


        String info = new String(info1.getBytes("GBK"),"utf-8");
  • 对服务器的代码修改:
String info=null;
        if (!((info = bufferedReader.readLine()) ==null)){
            System.out.println("我是服务器,用户信息为:" + info);
        }

        //接收到后缀表达式表达式后,进行解密
        try {
            info = SDec.decode(info);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 客户端和服务器用DH算法进行3DES或AES算法的密钥交换
        try{
            // 读取对方的DH公钥
            FileInputStream f1=new FileInputStream("Apub.dat");
            ObjectInputStream b1=new ObjectInputStream(f1);
            PublicKey pbk=(PublicKey)b1.readObject( );
            //读取自己的DH私钥
            FileInputStream f2=new FileInputStream("Bpri.dat");
            ObjectInputStream b2=new ObjectInputStream(f2);
            PrivateKey prk=(PrivateKey)b2.readObject( );
            // 执行密钥协定
            KeyAgreement ka=KeyAgreement.getInstance("DH");
            ka.init(prk);
            ka.doPhase(pbk,true);
            System.out.println("\n" + "公钥为:");
            //生成共享信息
            byte[ ] sb=ka.generateSecret();
            for(int i=0;i<sb.length;i++){
                System.out.print(sb[i]+",");
            }
            SecretKeySpec k=new  SecretKeySpec(sb,"DESede");
        } catch (Exception e) {
            e.printStackTrace();
        }

        //调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
        String reply = MyDC.suffixToArithmetic(info);
  • 运行结果截图:

  • 任务5:

  • 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文和明文的MD5値发送给服务器
    客户端和服务器用DH算法进行3DES或AES算法的密钥交换
    服务器接收到后缀表达式表达式后,进行解密,解密后计算明文的MD5值,和客户端传来的MD5进行比较,一致则调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端

  • 对客户端代码进行的修改:

       //客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式
        String a1,a2,a3,a4;
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入中缀表达式");
        String info1 = scanner.nextLine();
        info1 = MyBC.infixToSuffix(info1);  // 转后缀
        a1 = info1 + "###";
        String suffix = new String(a1.getBytes("GBK"),"utf-8");
        outputStreamWriter.write(suffix);
        outputStreamWriter.flush();
        String cleartext = "",ciphertext = "";

        //把后缀表达式用3DES或AES算法加密后通过网络把密文和明文的MD5値发送给服务器
        try {
             cleartext = DigestPass.MD5(info1); // 明文MID5
            a2 = cleartext + "###";
            String info_cleartext = new String(a2.getBytes("GBK"),"utf-8");
            outputStreamWriter.write(info_cleartext);
            outputStreamWriter.flush();
            info1 = SEnc.encrypt(info1);  // 加密
            a3 = info1 + "###";
            String encrypt = new String(a3.getBytes("GBK"),"utf-8");
            outputStreamWriter.write(encrypt);
            outputStreamWriter.flush();
             ciphertext = DigestPass.MD5(info1); // 密文MID5


        } catch (Exception e) {
            e.printStackTrace();
        }

        // 客户端和服务器用DH算法进行3DES或AES算法的密钥交换
        try{
            // 读取对方的DH公钥
            FileInputStream f1=new FileInputStream("Bpub.dat");
            ObjectInputStream b1=new ObjectInputStream(f1);
            PublicKey  pbk=(PublicKey)b1.readObject( );
            //读取自己的DH私钥
            FileInputStream f2=new FileInputStream("Apri.dat");
            ObjectInputStream b2=new ObjectInputStream(f2);
            PrivateKey  prk=(PrivateKey)b2.readObject( );
            // 执行密钥协定
            KeyAgreement ka=KeyAgreement.getInstance("DH");
            ka.init(prk);
            ka.doPhase(pbk,true);
            System.out.println("\n" + "公钥为:");
            //生成共享信息
            byte[ ] sb=ka.generateSecret();
            for(int i=0;i<sb.length;i++){
                System.out.print(sb[i]+",");
            }
            SecretKeySpec k=new  SecretKeySpec(sb,"DESede");
        } catch (Exception e) {
            e.printStackTrace();
        }

        String info_ciphertext = new String(ciphertext.getBytes("GBK"),"utf-8");
        //     printWriter.write(info);
        //     printWriter.flush();

        outputStreamWriter.write(info_ciphertext);
  • 对服务器代码进行的修改:
//4.读取用户输入信息
        String info,info1,info2,info3,info4,info5 = null,reply = null;
        info = bufferedReader.readLine();
        System.out.println("我是服务器,用户信息为:" + info);
        String[] history = info.split("###");
        info1 = history[0];
            System.out.println("我是服务器,用户明文为:" + info1);
        info2 = history[1];
        System.out.println("我是服务器,用户明文MID5值为:" + info2);
        info3 = history[2];
        System.out.println("我是服务器,用户密文为:" + info3);
        info4 = history[3];
        System.out.println("我是服务器,用户密文MID5值为:" + info4);

        //接收到后缀表达式表达式后,进行解密并计算器MID5值
        try {
            info3 = SDec.decode(info3);
            info5 = DigestPass.MD5(info3);
            System.out.println("解密后求得的MID5:" + info5);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 客户端和服务器用DH算法进行3DES或AES算法的密钥交换
        try{
            // 读取对方的DH公钥
            FileInputStream f1=new FileInputStream("Apub.dat");
            ObjectInputStream b1=new ObjectInputStream(f1);
            PublicKey pbk=(PublicKey)b1.readObject( );
            //读取自己的DH私钥
            FileInputStream f2=new FileInputStream("Bpri.dat");
            ObjectInputStream b2=new ObjectInputStream(f2);
            PrivateKey prk=(PrivateKey)b2.readObject( );
            // 执行密钥协定
            KeyAgreement ka=KeyAgreement.getInstance("DH");
            ka.init(prk);
            ka.doPhase(pbk,true);
            System.out.println("\n" + "公钥为:");
            //生成共享信息
            byte[ ] sb=ka.generateSecret();
            for(int i=0;i<sb.length;i++){
                System.out.print(sb[i]+",");
            }
            SecretKeySpec k=new  SecretKeySpec(sb,"DESede");
        } catch (Exception e) {
            e.printStackTrace();
        }

        //调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
        if (info2.equals(info5)) {
             reply = MyDC.suffixToArithmetic(info1);
        }
        else {
            reply = "抱歉,二者的MID5值不一致!";
        }
        printWriter.write(reply);
  • 运行结果截图:

返回目录


测试过程及遇到的问题

  • 问题1:'ipconfig' 不是内部或外部命令,也不是可运行的程序或批处理文件。

  • 解决:起初为了试验能进行,采用了需求分析里的笨方法,后来发现是环境变量的问题,参考解决'不是内部或外部命令,也不是可运行的程序即可解决。

  • 问题2:我作为客户端,伙伴作为服务器可以正常传输,而交换则显示connect timed out

  • 解决:当时电脑出现关于IDEA的警告,我允许了其行为,但并没有真正关掉防火墙,所以导致链接超时;
    开始——设置——更新和安全——windows安全——防火墙和保护——关掉公共网络的防火墙即可

  • 问题3:DH算法进行传输时两边的密钥不对等

  • 解决:刚开始我对Key_DH里的方法做了修改:

  • 分别运用到服务器和客户端中,结果:


    很明显生成的公钥是不一样的,这明显不符合DH算法的原理;
    下面针对客户端与服务器的代码进行分析:

    可以明显看出执行到try之后,已经使用了Key_DH.java中的client方法生成关于客户端的公私钥,这里显然没什么问题,
    但要小心,此时服务器的公钥Bpub.dat是读不到的,因为还没有任何操作进行相应的生成,之后当数据传输给服务器时,
    其实客户端只读取了客户端自己的私钥,而传给服务器的,仅仅是用私钥进行运算后的;
    再看服务器:

    一样的道理,在向客户端传回数据前并没有读到客户端的公钥Apub.dat,因此等同客户端,只进行了私钥的运算就传输了,
    所以二者才不一样。
  • 最后,将原文件Key_DH.java扩展成两个文件,直接运行生成二者的公私钥,在服务器与客户端不再进行生成操作,而是直接读取。

返回目录


分析总结

  • 本次实验,内容基本相关连,每一个都是在前者的基础上进行扩充,虽然看似简单,但其实也不太容易;回顾了java密码学的相关知识,学会了几种算法的基本应用,还学会如何在不同机器间进行传输。

返回目录


代码链接

返回目录


参考资料

Intellj IDEA 简易教程
Android开发简易教程
java 密码学

返回目录

posted @ 2018-06-19 20:00  ⊙ω⊙  阅读(291)  评论(0编辑  收藏  举报