课程:Java程序设计 班级:1351 姓名:刘帅 学号:20135104
成绩: 指导教师:娄嘉鹏 实验日期:2015.6.9
实验密级: 预习程度: 实验时间:15:20-18:00
仪器组次:11 必修/选修: 实验序号:5
实验名称: TCP传输及加解密
实验内容:
1.运行教材上TCP代码,结对进行,一人服务器,一人客户端;
2.利用加解密代码包,编译运行代码,一人加密,一人解密;
3.集成代码,一人加密后通过TCP发送;
注:加密使用AES或者DES/AES或者DES加密密钥key并发送,使用服务器的公钥加密/公钥算法使用RSA或DH/检验发送信息的完整性使用MD5或者SHA3;
4.用Git进行版本控制。
5.完成Blog
实验仪器:
名称 |
型号 |
数量 |
PC
|
Macbook Air(win7系统) |
1 |
结对伙伴:20135130王川东
我负责发送文件,他负责接收文件
一、代码:
package chuanwenjian1; import java.io.*; import java.net.ServerSocket; import java.net.Socket;
/** * 发送端 */ public class Client { // 将 int 转成字节 public static byte[] i2b(int i) { return new byte[]{ (byte) ((i >> 24) & 0xFF), (byte) ((i >> 16) & 0xFF), (byte) ((i >> 8) & 0xFF), (byte) (i & 0xFF) }; }
public static void main(String args[]) throws IOException{ //用构造函数构造此类后,发送文件 new Client().sendFile("localhost", 8001, "G://java123//Chuanshu//SEnc.dat"); new Client().sendFile("localhost", 8001, "G://java123//Chuanshu//keykb2.dat");
}
/** * 发送文件。文件大小不能大于 {@link Integer#MAX_VALUE} * * @param hostname 接收端主机名或 IP 地址 * @param port 接收端端口号 * @param filepath 文件路径 * * @throws IOException 如果读取文件或发送失败 */ public void sendFile(String hostname, int port, String filepath) throws IOException { File file = new File(filepath); FileInputStream is = new FileInputStream(filepath); Socket socket = new Socket(hostname, port); DataOutputStream os = new DataOutputStream(socket.getOutputStream()); try { int length = (int) file.length(); System.out.println("发送文件:" + file.getName() + ",长度:" + length); // 将发送文件名和文件内容和写到文件流 writeFileName(file, os); writeFileContent(is, os, length); } finally { os.close(); is.close(); } } // 输出文件内容 private void writeFileContent(InputStream is, DataOutputStream os, int length) throws IOException { // 输出文件长度,将int转化为字节 os.write(i2b(length)); // 输出文件内容 byte[] buffer = new byte[4096]; int size; while ((size = is.read(buffer)) != -1) { os.write(buffer, 0, size); } } // 输出文件名 private void writeFileName(File file, DataOutputStream os) throws IOException { byte[] fn_bytes = file.getName().getBytes(); os.write(i2b(fn_bytes.length)); // 输出文件名长度 os.write(fn_bytes); // 输出文件名 } }
package myRSA;
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.SecureRandom;
import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream;
public class MyRSA { /** * 把成生的一对密钥保存到key.dat文件中 */ public void saveRSAKey() { try { SecureRandom sr = new SecureRandom(); KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA"); kg.initialize(1024, sr); FileOutputStream fos = new FileOutputStream("G://java123//Chuanshu//key.dat"); ObjectOutputStream oos = new ObjectOutputStream(fos); // 生成密钥 oos.writeObject(kg.generateKeyPair()); oos.close(); } catch (Exception e) { e.printStackTrace(); } System.out.println("获取密钥对成功!"); }
/** * 从文件中读取RSA加密密钥和解密密钥。 * * @return KeyPair返回对称密钥 */ public static KeyPair getKeyPair() { // 产生新密钥对 KeyPair kp = null; try { String fileName = "G://java123//Chuanshu//key.dat"; FileInputStream is = new FileInputStream(fileName); ObjectInputStream oos = new ObjectInputStream(is); kp = (KeyPair) oos.readObject(); oos.close(); } catch (Exception e) { e.printStackTrace(); } return kp; //kp是密钥对 }
/** * 文件file进行加密并保存目标文件destFile中 * * @param srcFileName * 要加密的文件 如c:/test/srcFile.txt * @param destFileName * 加密后存放的文件名 如c:/加密后文件.txt */ public static void encryptFile(String srcFileName, String destFileName) throws Exception { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, getKeyPair().getPublic()); //用公钥和加密模式初始化加密器 InputStream is = new FileInputStream(srcFileName); //从源文件中读入 OutputStream out = new FileOutputStream(destFileName); //向目标文件中输出 CipherInputStream cis = new CipherInputStream(is,cipher); //将源文件的输入流和加密器作为参数传给加密输入流 byte[] buffer = new byte[100]; int r; while((r=cis.read(buffer))>=0){ //从加密读入流读取 out.write(buffer,0,r); //将读取到的写到输出流,即写入目标文件 } cis.close(); out.close(); is.close(); System.out.println("文件加密处理结束!"); }
/** * 文件file进行解密并保存目标文件destFile中 * * @param srcFileName * 已加密的文件 如c:/加密后文件.txt * @param destFileName * 解密后存放的文件名 如c:/ test/解密后文件.txt */ public static void decryptFile(String srcFileName, String destFileName) throws Exception { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, getKeyPair().getPrivate()); //同理,只不过这里换成解密模式即可 InputStream is = new FileInputStream(srcFileName); OutputStream out = new FileOutputStream(destFileName); CipherOutputStream cos = new CipherOutputStream(out,cipher); byte[] buffer = new byte[128]; int r; while((r=is.read(buffer))>=0){ cos.write(buffer,0,r); } cos.close(); out.close(); is.close(); System.out.println("文件解密处理结束!"); }
public static void main(String[] args) { MyRSA fileUtils=new MyRSA(); fileUtils.saveRSAKey(); MyRSA.getKeyPair(); try { MyRSA.encryptFile("G://java123//Chuanshu//keykb1.dat", "G://java123//Chuanshu//keykb2.dat"); } catch (Exception e) {
e.printStackTrace(); } /*try { MyRSA.decryptFile("G://java123//Chuanshu//keykb2.dat", "G://java123//Chuanshu//keykb3.dat"); } catch (Exception e) {
e.printStackTrace(); } */ }
}
package Hash;
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.security.*; public class Hash{ public static void main(String args[ ]) throws IOException, NoSuchAlgorithmException { /*原先 String x=args[0];*/ //SEnc.dat从文件中读取密文,并存到ctext数组中 FileInputStream f=new FileInputStream("G://java123//Chuanshu//SEnc.dat"); int num=f.available(); byte[ ] ctext=new byte[num]; f.read(ctext); MessageDigest m=MessageDigest.getInstance("MD5");//初始化摘要器 m.update(ctext);//x是待摘要的字符串,m是生成摘要的工具 byte s[ ]=m.digest( );//将生成的摘要存在byte数组s中 String result=""; for (int i=0; i<s.length; i++){ result+=Integer.toHexString((0x000000ff & s[i]) | 0xffffff00).substring(6); //将s中的十进制数转化十六进制数,存在result字符串中 } System.out.println(result); //result是生成的摘要字符串 } }
package DES;
import java.io.*;
import java.security.*;
//这是DES的加密类
import java.security.*;
import javax.crypto.*;
public class SEnc{
public static void main(String args[]) throws Exception{
String s="若曾素心相赠,何妨咫尺天涯。七月沧海曾经,陌生熟悉愿领。";//待加密的字符串
FileInputStream f=new FileInputStream("key1.dat");
ObjectInputStream b=new ObjectInputStream(f);
Key k=(Key)b.readObject( );//从key1.dat中读取密钥,存在k中
Cipher cp=Cipher.getInstance("DESede");
cp.init(Cipher.ENCRYPT_MODE, k);//初始化加密模式和密钥
//将字符串转化成其ASCII码存放在数组中;这是因为DES加密时是对整数进行操作的
byte ptext[]=s.getBytes("UTF8");//ptext是存放待加密是字符串的byte数组,byte是整型,占一个字节
for(int i=0;i<ptext.length;i++){
System.out.print(ptext[i]+",");
}
System.out.println("");
byte ctext[]=cp.doFinal(ptext); //进行加密,加密结果存放在ctext数组中
for(int i=0;i<ctext.length;i++){
System.out.print(ctext[i] +","); //输出加密后的密文
}
FileOutputStream f2=new FileOutputStream("SEnc.dat");
f2.write(ctext); //将密文存放到SEnc.dat文件中
}
}
二、遇到的问题及怎样解决:
1、将程序包中程序整合时经常容易出现重定义和变量名占用的问题,此时只需要注销掉重复定义的部分或者更改变量名即可,但要注意后来引用部分也需要更改变量名。
2、文件发送后string型数据无法转换为FileOutputStream型数据,无法写入文件。后来问了班里的大神——肖昱同学,得知应该以字节形式写入,依照他的建议进行更正,问题引刃而解。
三、实验体会
1.PSP时间
步骤 |
耗时 |
百分比 |
需求分析 |
1.5h |
21.4% |
设计 |
2h |
28.6% |
代码实现 |
2h |
28.6% |
测试 |
1h |
14.3% |
分析总结 |
0.5h |
7.1% |
2.感想
本次实验是我和搭档结对完成的,让我感到有一个有默契的搭档的重要性。一开始完全没有头绪,后来经过研究与整理思路,基本弄清了实验的方案。后来虽然大部分代码是现成的,但是整合起来却十分的麻烦,要把DES加密、RSA加密的代码整合在一个程序中并且要编译成功是一件十分困难的事情。因此我觉得本次实验并不是简单的编写代码,而是在完成一项工程,我在其中的角色和胶水比较像,就是在将部件进行有效的组合,最终形成能进行网络加密传输的项目。同时我也体会到Java和C++在加密方面的优劣比较,虽然Java有很方便的加密类可以被调用,但美国提供给我们的这些类连计算安全都做不到,但通过C++我们可以进一步扩展密钥长度,按需求设计出在现有条件下安全的加密算法。