课程名称:《程序设计与数据结构》 学生班级:1723班 学生姓名:唐才铭 学生学号:20172319 实验教师:王志强老师课程助教:刘伟康、张旭升学长实验时间:2018年6月13日——2018年6月20日必修/选修:必修
- 参考 结对实现中缀表达式转后缀表达式的功能 MyBC.java 结对实现从上面功能中获取的表达式中实现后缀表达式求值的功能,调用MyDC.java 上传测试代码运行结果截图和码云链接;
- 结对编程:1人负责客户端,一人负责服务器 注意责任归宿,要会通过测试证明自己没有问题 基于Java Socket实现客户端/服务器功能,传输方式用TCP 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式通过网络发送给服务器 服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端 客户端显示服务器发送过来的结果 上传测试代码运行结果截图和码云链接;
- 加密结对编程:1人负责客户端,一人负责服务器 注意责任归宿,要会通过测试证明自己没有问题 基于Java Socket实现客户端/服务器功能,传输方式用TCP 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密后通过网络把密文发送给服务器 服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,可以用数组保存),然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端 客户端显示服务器发送过来的结果 上传测试结果截图和码云链接;
- 密钥分发结对编程:1人负责客户端,一人负责服务器 注意责任归宿,要会通过测试证明自己没有问题 基于Java Socket实现客户端/服务器功能,传输方式用TCP 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文发送给服务器 客户端和服务器用DH算法进行3DES或AES算法的密钥交换 服务器接收到后缀表达式表达式后,进行解密,然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端 客户端显示服务器发送过来的结果 上传测试结果截图和码云链接;
- 完整性校验结对编程:1人负责客户端,一人负责服务器 注意责任归宿,要会通过测试证明自己没有问题 基于Java Socket实现客户端/服务器功能,传输方式用TCP 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文和明文的MD5値发送给服务器 客户端和服务器用DH算法进行3DES或AES算法的密钥交换 服务器接收到后缀表达式表达式后,进行解密,解密后计算明文的MD5值,和客户端传来的MD5进行比较,一致则调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端 客户端显示服务器发送过来的结果 上传测试结果截图和码云链接:
- 完成蓝墨云上与实验五《网络编程与安全》相关的活动,及时提交代码运行截图和码云Git链接,截图要有学号水印,否则会扣分。
- 完成实验、撰写实验报告,实验报告以博客方式发表在博客园,注意实验报告重点是运行结果,遇到的问题(工具查找,安装,使用,程序的编辑,调试,运行等)、解决办法(空洞的方法如“查网络”、“问同学”、“看书”等一律得0分)以及分析(从中可以得到什么启示,有什么收获,教训等)。报告可以参考范飞龙老师的。
- 严禁抄袭,有该行为者实验成绩归零,并附加其他惩罚措施。
- 结对编程;也可自己在idea和虚拟机间进行传输;idea本身也可以进行服务器与客户端的传输。
- 完成蓝墨云上实验五 网络编程与安全-1
- 完成蓝墨云上实验五 网络编程与安全-2
- 完成蓝墨云上实验五 网络编程与安全-3
- 完成蓝墨云上实验五 网络编程与安全-4
- 完成蓝墨云上实验五 网络编程与安全-5
前期准备:
- 弄清自己的IP地址是什么: Linux下查找IP的命令:
ifconfig -a
Windows下查找IP的命令:ipconfig
Windows下查找IP(笨方法):开始——设置——网络和Internet——WLAN——硬件属性
需求分析:
- 需要在原Socket代码上加以理解并运用;
- 需要掌握、并会运用实验三java密码学所学的知识。
本次实验一共分为五个提交点:
- 任务1:
- 结对实现中缀表达式转后缀表达式的功能 MyBC.java; 结对实现从上面功能中获取的表达式中实现后缀表达式求值的功能,调用MyDC.java
- 分别运用四则运算时的中缀转后缀、后缀求值的方法即可:
- ;
截图如下:
- 任务2:
- 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式通过网络发送给服务器 服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端。
- 弄懂Socket的两个代码,将传输信息的内容换掉即可。
- ;
对客户端代码的修改:
由
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算法;先对文件(加密)和(解密)进行修改,使其从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的代码,运行后分别生成客户端与服务器的公私钥;
- ;
- 运行结果如图:
- 对客户端的代码修改:
//客户端让用户输入中缀表达式,然后把中缀表达式调用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
- 对服务器的代码修改:
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
运行结果截图:
- 任务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
- 对服务器代码进行的修改:
//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
- 运行结果截图:
- 问题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密码学的相关知识,学会了几种算法的基本应用,还学会如何在不同机器间进行传输。