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