java-socket简单编程(socket C/S加解密)

好久没更新博客了,最近在帮老师整理项目,本来对socket接触的不多。本次不多说废话,直接说项目

项目要求:1.实现服务端和客户端的传输文件加解密,我这边实现的是服务端传输加密后的文件,客户端收到文件后解密,为了展示方便,我此次采用了AES加密方式,填充方式采用AES/CBC/PKCS5Padding。

                  2.实现客户端验证文件是否为服务端发送的文件,我这边采用的是md5码加密,将服务端的md5码和文件一并发送给客户端,客户端对收到的文件进行md5加密,再将收到的md5和文件加密的md5进行对比。

由于代码比较长,为了方便看,此次,我仅介绍C/S端加解密,代码部分我会拆分了写。

在这里我就不给出import了,都是java的基本库

1.C/S加解密传输

1.1客户端

public class FileTransferClient{
    public static void main(String [] args){
        try{
            Socket s=new Socket("127.0.0.1",9500);//本机地址、端口号
            DataInputStream so=new DataInputStream(s.getInputStream());//输入流创建,接收服务端发送信息
            System.out.println(so.readUTF());
            FileOutputStream f=new FileOutputStream("D:\\test.txt");//文件存储地址
              int p;
            System.out.println("please wait........");

            //写文件
            while((p=so.read())!=-1){
                   f.write(p);
            }

           //打开文件,并解密其中内容,再重写文件
            InputStream fi=new FileInputStream("D:/test.txt");

           //并解密其中内容

            byte[] bytes=MyAESUtils.toByteArray(fi);
            byte[] debytes=MyAESUtils.decrypt(bytes);
            String temp=new String(debytes);
            fi.close();
            System.out.println("解密内容:"+temp);

            //重写并解密文件
            FileOutputStream fos=new FileOutputStream("D:/test.txt");
            fos.write(debytes);
              s.close();
              so.close();
              f.flush();
              f.close();
              System.out.println("complete!");
        }catch(IOException e){
            System.out.println("file transfer failed!");
        }
    }
}

说明:客户端采用的是先接收服务端传送的文件,然后由于接收的文件是密文,所以提取文件中的内容进行解密,解密后重写文件。

注意:如果非txt文件,mp3格式等,由于涉及到文件转换,要讲内容转成byte,所以请自行添加len测量文件的字节数,不然会出现解密后的mp3等文件无法播放的问题。

1.2服务端

public class FileTransferServer{
	private static int port=9500;
	public static void main(String [] args)throws Exception{

			ServerSocket s=new ServerSocket(port);
		try {
			//监听
			Socket s1=s.accept();
			System.out.println("Client connection success!");
			//构建文件输出流
			DataOutputStream so=new DataOutputStream(s1.getOutputStream());

so.writeUTF("FileName:1111.txt"+"\n"+"ServerIp:"+s.getInetAddress()+"\n"+"ServerPort:"+s.getLocalPort());
			//读文件
			FileInputStream f=new FileInputStream("E:/1111.txt");
			//提取文件内容转成密文
			String list=FileUtils.readFileToString(new File("E:/1111.txt"), "UTF-8");
			//System.out.println("原文byte:" + list.length());
			//int len=f.available();
			byte[] bytes=new byte[list.length()];
			bytes=MyAESUtils.encrypt(list);
			so.write(bytes);
		  	  s.close();
		  	  f.close();
		  	  s1.close();
		  	  so.flush();
		  	  so.close();
		} catch (Exception e) {
			e.printStackTrace();
		}{
			
		}
	}
}

说明:服务端需要进行文件的读取,明文转换,发送密文三个步骤,比较简单,因此不多赘述。

注意:如果是大型文件进行加解密,切记要切分文件块,然后再加解密,具体的百度一下,这类切分蛮多的。

1.3 AES加解密

public class MyAESUtils {
	//static SecretKeySpec key = new SecretKeySpec(null, "AES");
	private static final String ENCODING = "UTF-8";
	static String ivstr="abcdefghijklmnop";
	static byte[] iv=ivstr.getBytes();
	public static byte[] encrypt(String content) {
		try {
			//byte[] iv=new byte[10];
			KeyGenerator kgen = KeyGenerator.getInstance("AES");  
			kgen.init(128,new SecureRandom("1234567890123456".getBytes()));
			SecretKey secretKey = kgen.generateKey();
			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
			byte[] byteContent = content.getBytes("utf-8");
			cipher.init(Cipher.ENCRYPT_MODE, secretKey,new IvParameterSpec(iv));
			byte[] result = cipher.doFinal(byteContent);
			return result;
		} catch (Exception e) {
		e.printStackTrace();
		}
		return null;
	}
	
	public static byte[] decrypt(byte[] content) {
		try {
			KeyGenerator kgen=KeyGenerator.getInstance("AES");  
			kgen.init(128, new SecureRandom("1234567890123456".getBytes())); 
			SecretKey secretKey = kgen.generateKey();
			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
			cipher.init(Cipher.DECRYPT_MODE, secretKey,new IvParameterSpec(iv));
			byte[] result = cipher.doFinal(content);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
		}
			return null;
	}
	public static byte[] toByteArray(InputStream in) throws IOException {
		 
	    ByteArrayOutputStream out = new ByteArrayOutputStream();
	    byte[] buffer = new byte[1024 * 4];
	    int n = 0;
	    while ((n = in.read(buffer)) != -1) {
	        out.write(buffer, 0, n);
	    }
	    return out.toByteArray();
	}
}

注意:直接上代码了,AES不需要理解原理,你只需要知道,你要提供一个key通过随机种子生成密钥。在这部分我遇到了个挺麻烦的问题,就是一开始代码是这个样子的

            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);

解密的时候一直提示我解密的密钥错误,我明明把随机种子的key给锁定了的,加解密的密钥却还是不同,最后,查了半天, 才发现原来是我没有锁定初始化变量iv。导致两个端初始化变量iv不同,所以cipher,init()的结果也不同。

工作总结:虽然这是老师的结题项目,但想想确实有点累,做这个花了3天时间,还加了2个通宵,现在仔细想想,其实cocket通信也不难,其实很多东西都是细节问题,就比如刚刚的初始化变量iv,就这个问题卡了我将近2天。好了,问题解决了,可以结题了,也祝大家学习愉快!

你可能感兴趣的:(java-socket简单编程(socket C/S加解密))