標籤:
課程: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++我們可以進一步擴充密鑰長度,按需求設計出在現有條件下安全的密碼編譯演算法。
java實驗五20135104