2018-2019-2 20175320实验五《网络编程与安全》实验报告

2018-2019-2 20175320实验五《网络编程与安全》实验报告

1、相关介绍

在本次实验中我主要使用了书本第13章Java网络编程以及Java密码学的内容,基于TCP的信息传输使用socket进行实现,加密、解密、生成共享密钥以及进行摘要验证使用了Java中的JCA以及JCE。html

2、实验步骤及内容

(一)任务一

任务要求:算法

  • 结对实现中缀表达式转后缀表达式的功能并对后缀表达式进行计算

虽然该功能是后续步骤的基础,但在之前的结对项目中已经实现过了,在这里我就再也不多作介绍了,详情请见博客结对编程项目-四则运算阶段性总结
运行结果如图:
编程

(二)任务二

任务要求:数组

  • 客户端中输入中缀表达式,而后将中缀表达式转化为后缀表达式,把后缀表达式经过网络发送给服务器。
  • 服务器接收到后缀表达式后计算后缀表达式的值,并把结果发送给客户端
  • 客户端显示服务器发送过来的结果
    在加密时我选择了3DES,3DES在使用过程当中只需将图示参数设置为“DESede”便可。

步骤:
一、建立数据输入以及输出流对象in和out用于创建链接后的数据传输。
二、客户端建立套接字对象mysocket,并用构造方法Socket(String host,int port)给mysocket建立实体,而后让mysocket调用getInputStream以及getoutputStream方法与服务器端创建链接。服务器端的步骤与客户端相似,但在建立套接字时服务器端先建立一个ServerSocket对象,并用该对象调用accept方法来建立Socket类的实例。
三、客户端与服务器端分别用对象out调用writeUTF方法来发送数据,对象in调用readUTF来接收数据。客户端在输入中缀表达式后转化为后缀表达式并经过out对象发送给服务器,服务器用in对象接收客户端发送过来的后缀表达式进行计算,并将计算结果使用out对象发送给客户端,客户端使用in对象接收客户端发来的数据并输出。
运行结果以下:
安全

任务三

任务要求:服务器

  • 客户端中输入中缀表达式,而后将中缀表达式转化为后缀表达式
  • 客户端使用3DES算法对后缀表达式进行加密,并将加密后的密文发送给服务器
  • 服务器接收到密文后进行解密,并对解密后的明文计算表达式的结果,并把结果发送给客户端,客户端显示服务器发送过来的结果

该任务是在任务二的基础上进行功能拓展,因而本任务中的网络信息收发部分我就再也不介绍,我主要对加密及解密过程进行描述,而生成密钥以及加密解密我都放在了Skey_kb类中,并经过方法来实现功能的调用。
加解密步骤:网络

一、生成密钥并发

  • 获取密钥生成器KeyGeneratorkg=KeyGenerator.getInstance("DESede");
  • 初始化密钥生成器kg.init(168);
  • 生成密钥SecretKeyk=kg.generateKey( );
  • 经过对象序列化方式将密钥保存在文件中FileOutputStream f=new FileOutputStream("key1.dat");ObjectOutputStream b=new ObjectOutputStream(f);b.writeObject(k);

二、改变密钥保存方式
在解密时须要使用字节数组形式的密钥,所以须要将密钥以另外一种方式保存在文件中。less

  • 获取密钥,首先建立文件输入流,而后将其做为参数传递给对象输入流,最后执行对象输入流的readObject( )方法读取密钥对象。因为readObject( )返回的是Object类型,所以须要强制转换成Key类型。
  • 获取主要编码格式,执行SecretKey类型的对象k的getEncoded( )方法,返回的编码放在byte类型的数组中。
  • 保存密钥编码格式,建立文件输出流对象,在其参数中指定文件名,如keykb1.dat。而后执行文件输出流的write( )方法将第2步中获得的字节数组中的内容写入文件。、

三、加密socket

  • 从文件中获取密钥FileInputStream f=new FileInputStream("key1.dat");ObjectInputStream b=new ObjectInputStream(f);Key k=(Key)b.readObject( );
  • 建立密码器(Cipher对象)Cipher cp=Cipher.getInstance("DESede");
  • 初始化密码器cp.init(Cipher.ENCRYPT_MODE, k);
  • 获取等待加密的明文String s="Hello World!";` byte ptext[]=s.getBytes("UTF8");
  • 执行加密byte ctext[]=cp.doFinal(ptext);
  • 处理加密结果FileOutputStream f2=new FileOutputStream("SEnc.dat"); f2.write(ctext);

四、解密

  • 获取密文FileInputStream f=new FileInputStream("SEnc.dat"); int num=f.available(); byte[ ] ctext=new byte[num]; f.read(ctext);
  • 获取密钥
  • 建立密码器
  • 初始化密码器
  • 执行解密

须要注意的是,加密和解密的方法须要分别传入明文以及密文的字符串,并将对应的密文以及明文做为方法的输出。在加密时须要将密文二进制字节数组转化为十六进制后再转化为字符串做为发送数据,在解密时须要将密文转化为二进制后再进行解密。若是不进行数据转化的话在进行密文传输时系统会报错。
运行结果以下:
服务器端:

客户端:

任务四

任务要求:

  • 客户端中输入中缀表达式,而后将中缀表达式转化为后缀表达式
  • 客户端和服务器端使用DH算法生成各自的公钥与私钥,并用本身的私钥以及对方的公钥生成共有密钥
  • 客户端使用3DES算法对后缀表达式进行加密,并将加密后的密文发送给服务器
  • 服务器接收到密文后进行解密,并对解密后的明文计算表达式的结果,并把结果发送给客户端,客户端显示服务器发送过来的结果

该过程是在任务三的基础上进行的,我在这里只介绍DH算法相关的内容。因为生成公共密钥前须要两端交换公钥,而两端在两个不一样的文件夹中,因而我我在调用程序生成两端各自的两个密钥后,使用套接字在客户端与服务器之间进行了沟通,客户端首先会给服务器发送已生成两个密钥钥的信息,服务器在接收到该消息时也已经生成了两个密钥,在这时须要手动将二者的pub.dat文件进行交换,并在交换完成后在服务器端输入准备好了的信息,并发送给客户端,这样一来就能够正常进行加密及解密密钥的生成了。须要注意的是因为咱们使用的3DES是对外公布的限制密钥长度的版本,而DH算法生成的共享密钥有128位,因此须要在生成加密密钥后取得共享密钥的前几位,不然系统会显示密钥长度不合法。
运行结果以下:

任务五

任务要求:

  • 客户端中输入中缀表达式,而后将中缀表达式转化为后缀表达式
  • 客户端使用DH算法生成各自的公钥与私钥,并用本身的私钥以及对方的公钥生成共有密钥
  • 客户端使用MD5算法计算明文的摘要,并将摘要发送给客户端
  • 客户端使用3DES算法对后缀表达式进行加密,并将加密后的密文发送给服务器
  • 服务器接收到密文后进行解密,并对解密后的明文计算其摘要,并与接收到的摘要进行比较,若是相同则计算解密后明文表达式的结果,并把结果发送给客户端,客户端显示服务器发送过来的结果

在这部分中我增长了一次out以及in的调用用于两端传递摘要,MD5建立摘要的过程以下所示:
一、生成MessageDigest对象MessageDigest
二、传入须要计算的字符串m.update(x.getBytes("UTF8" ));
三、 计算消息摘要byte s[ ]=m.digest( );
四、将计算结果s转换为字符串
运行结果如图:
服务器:

客户端:

2、实验时遇到的问题:

  • 问题1:在运行中缀转后缀的过程当中Trans类发送错误。
  • 问题1解决方法:后来发现是结对编程时协调不足,Trans类有误且与封装了计算功能的类重复,没有遵循solid原则。Trans类删除并使用计算功能类中的方法。
  • 问题2:若是将字节数组的密文直接转化为字符串,在传输步骤中程序报错。
  • 问题2解决方法:须要将密文二进制字节数组转化为十六进制,而后再转化为字符串进行传输。
  • 问题3:在使用DH算法生成的密钥进行加密时系统报错:
  • 问题3解决方法:DH算法生成的共享密钥长度为128位,须要咱们对密钥长度进行修改。

3、实验感想

本次实验是网络编程以及Java密码学的一个综合,在实验过程当中遇到的问题使我印象深入,SOLID原则十分重要,它不只能减小代码的数量,更使得程序更加易读,更易于修改,且不容易出错。基于TCP的数据传输也不是为所欲为的,其对传输内容的格式也有要求,若是胡乱对传输内容进行格式转换就极可能出错。而咱们使用的JCE以及JCA都是限制功能的版本,在加密时只能使用很短的密钥,从这也看出发达国家对技术的严格管制。

相关文章
相关标签/搜索