2018-2019-2 20175320實驗五《網絡編程與安全》實驗報告

2018-2019-2 20175320實驗五《網絡編程與安全》實驗報告

1、相關介紹

在本次實驗中我主要使用了書本第13章Java網絡編程以及Java密碼學的內容,基於TCP的信息傳輸使用socket進行實現,加密、解密、生成共享密鑰以及進行摘要驗證使用了Java中的JCA以及JCE。html

2、實驗步驟及內容

(一)任務一

任務要求:算法

  • 結對實現中綴表達式轉後綴表達式的功能並對後綴表達式進行計算

雖然該功能是後續步驟的基礎,但在之前的結對項目中已經實現過了,在這裏我就再也不多作介紹了,詳情請見博客結對編程項目-四則運算階段性總結
運行結果如圖:
編程

(二)任務二

任務要求:數組

  • 客戶端中輸入中綴表達式,而後將中綴表達式轉化爲後綴表達式,把後綴表達式經過網絡發送給服務器。
  • 服務器接收到後綴表達式後計算後綴表達式的值,並把結果發送給客戶端
  • 客戶端顯示服務器發送過來的結果
    在加密時我選擇了3DES,3DES在使用過程當中只需將圖示參數設置爲「DESede」便可。

步驟:
一、建立數據輸入以及輸出流對象in和out用於創建鏈接後的數據傳輸。
二、客戶端建立套接字對象mysocket,並用構造方法Socket(String host,int port)給mysocket建立實體,而後讓mysocket調用getInputStream以及getoutputStream方法與服務器端創建鏈接。服務器端的步驟與客戶端相似,但在建立套接字時服務器端先建立一個ServerSocket對象,並用該對象調用accept方法來建立Socket類的實例。
三、客戶端與服務器端分別用對象out調用writeUTF方法來發送數據,對象in調用readUTF來接收數據。客戶端在輸入中綴表達式後轉化爲後綴表達式並經過out對象發送給服務器,服務器用in對象接收客戶端發送過來的後綴表達式進行計算,並將計算結果使用out對象發送給客戶端,客戶端使用in對象接收客戶端發來的數據並輸出。
運行結果以下:
安全

任務三

任務要求:服務器

  • 客戶端中輸入中綴表達式,而後將中綴表達式轉化爲後綴表達式
  • 客戶端使用3DES算法對後綴表達式進行加密,並將加密後的密文發送給服務器
  • 服務器接收到密文後進行解密,並對解密後的明文計算表達式的結果,並把結果發送給客戶端,客戶端顯示服務器發送過來的結果

該任務是在任務二的基礎上進行功能拓展,因而本任務中的網絡信息收發部分我就再也不介紹,我主要對加密及解密過程進行描述,而生成密鑰以及加密解密我都放在了Skey_kb類中,並經過方法來實現功能的調用。
加解密步驟:網絡

一、生成密鑰併發

  • 獲取密鑰生成器KeyGeneratorkg=KeyGenerator.getInstance("DESede");
  • 初始化密鑰生成器kg.init(168);
  • 生成密鑰SecretKeyk=kg.generateKey( );
  • 經過對象序列化方式將密鑰保存在文件中FileOutputStream f=new FileOutputStream("key1.dat");ObjectOutputStream b=new ObjectOutputStream(f);b.writeObject(k);

二、改變密鑰保存方式
在解密時須要使用字節數組形式的密鑰,所以須要將密鑰以另外一種方式保存在文件中。less

  • 獲取密鑰,首先建立文件輸入流,而後將其做爲參數傳遞給對象輸入流,最後執行對象輸入流的readObject( )方法讀取密鑰對象。因爲readObject( )返回的是Object類型,所以須要強制轉換成Key類型。
  • 獲取主要編碼格式,執行SecretKey類型的對象k的getEncoded( )方法,返回的編碼放在byte類型的數組中。
  • 保存密鑰編碼格式,建立文件輸出流對象,在其參數中指定文件名,如keykb1.dat。而後執行文件輸出流的write( )方法將第2步中獲得的字節數組中的內容寫入文件。、

三、加密socket

  • 從文件中獲取密鑰FileInputStream f=new FileInputStream("key1.dat");ObjectInputStream b=new ObjectInputStream(f);Key k=(Key)b.readObject( );
  • 建立密碼器(Cipher對象)Cipher cp=Cipher.getInstance("DESede");
  • 初始化密碼器cp.init(Cipher.ENCRYPT_MODE, k);
  • 獲取等待加密的明文String s="Hello World!";` byte ptext[]=s.getBytes("UTF8");
  • 執行加密byte ctext[]=cp.doFinal(ptext);
  • 處理加密結果FileOutputStream f2=new FileOutputStream("SEnc.dat"); f2.write(ctext);

四、解密

  • 獲取密文FileInputStream f=new FileInputStream("SEnc.dat"); int num=f.available(); byte[ ] ctext=new byte[num]; f.read(ctext);
  • 獲取密鑰
  • 建立密碼器
  • 初始化密碼器
  • 執行解密

須要注意的是,加密和解密的方法須要分別傳入明文以及密文的字符串,並將對應的密文以及明文做爲方法的輸出。在加密時須要將密文二進制字節數組轉化爲十六進制後再轉化爲字符串做爲發送數據,在解密時須要將密文轉化爲二進制後再進行解密。若是不進行數據轉化的話在進行密文傳輸時系統會報錯。
運行結果以下:
服務器端:

客戶端:

任務四

任務要求:

  • 客戶端中輸入中綴表達式,而後將中綴表達式轉化爲後綴表達式
  • 客戶端和服務器端使用DH算法生成各自的公鑰與私鑰,並用本身的私鑰以及對方的公鑰生成共有密鑰
  • 客戶端使用3DES算法對後綴表達式進行加密,並將加密後的密文發送給服務器
  • 服務器接收到密文後進行解密,並對解密後的明文計算表達式的結果,並把結果發送給客戶端,客戶端顯示服務器發送過來的結果

該過程是在任務三的基礎上進行的,我在這裏只介紹DH算法相關的內容。因爲生成公共密鑰前須要兩端交換公鑰,而兩端在兩個不一樣的文件夾中,因而我我在調用程序生成兩端各自的兩個密鑰後,使用套接字在客戶端與服務器之間進行了溝通,客戶端首先會給服務器發送已生成兩個密鑰鑰的信息,服務器在接收到該消息時也已經生成了兩個密鑰,在這時須要手動將二者的pub.dat文件進行交換,並在交換完成後在服務器端輸入準備好了的信息,併發送給客戶端,這樣一來就能夠正常進行加密及解密密鑰的生成了。須要注意的是因爲咱們使用的3DES是對外公佈的限制密鑰長度的版本,而DH算法生成的共享密鑰有128位,因此須要在生成加密密鑰後取得共享密鑰的前幾位,不然系統會顯示密鑰長度不合法。
運行結果以下:

任務五

任務要求:

  • 客戶端中輸入中綴表達式,而後將中綴表達式轉化爲後綴表達式
  • 客戶端使用DH算法生成各自的公鑰與私鑰,並用本身的私鑰以及對方的公鑰生成共有密鑰
  • 客戶端使用MD5算法計算明文的摘要,並將摘要發送給客戶端
  • 客戶端使用3DES算法對後綴表達式進行加密,並將加密後的密文發送給服務器
  • 服務器接收到密文後進行解密,並對解密後的明文計算其摘要,並與接收到的摘要進行比較,若是相同則計算解密後明文表達式的結果,並把結果發送給客戶端,客戶端顯示服務器發送過來的結果

在這部分中我增長了一次out以及in的調用用於兩端傳遞摘要,MD5建立摘要的過程以下所示:
一、生成MessageDigest對象MessageDigest
二、傳入須要計算的字符串m.update(x.getBytes("UTF8" ));
三、 計算消息摘要byte s[ ]=m.digest( );
四、將計算結果s轉換爲字符串
運行結果如圖:
服務器:

客戶端:

2、實驗時遇到的問題:

  • 問題1:在運行中綴轉後綴的過程當中Trans類發送錯誤。
  • 問題1解決方法:後來發現是結對編程時協調不足,Trans類有誤且與封裝了計算功能的類重複,沒有遵循solid原則。Trans類刪除並使用計算功能類中的方法。
  • 問題2:若是將字節數組的密文直接轉化爲字符串,在傳輸步驟中程序報錯。
  • 問題2解決方法:須要將密文二進制字節數組轉化爲十六進制,而後再轉化爲字符串進行傳輸。
  • 問題3:在使用DH算法生成的密鑰進行加密時系統報錯:
  • 問題3解決方法:DH算法生成的共享密鑰長度爲128位,須要咱們對密鑰長度進行修改。

3、實驗感想

本次實驗是網絡編程以及Java密碼學的一個綜合,在實驗過程當中遇到的問題使我印象深入,SOLID原則十分重要,它不只能減小代碼的數量,更使得程序更加易讀,更易於修改,且不容易出錯。基於TCP的數據傳輸也不是爲所欲爲的,其對傳輸內容的格式也有要求,若是胡亂對傳輸內容進行格式轉換就極可能出錯。而咱們使用的JCE以及JCA都是限制功能的版本,在加密時只能使用很短的密鑰,從這也看出發達國家對技術的嚴格管制。

相關文章
相關標籤/搜索