1. 程式人生 > >java-socket簡單程式設計(socket C/S加解密)

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天。好了,問題解決了,可以結題了,也祝大家學習愉快!