20172302《程序設計與數據結構》實驗五 網絡編程與安全實驗報告

課程:《程序設計與數據結構》

班級: 1723

姓名: 侯澤洋

學號:20172302

實驗教師:王志強老師

實驗日期:2018年6月13日

必修/選修: 必修

1.實驗內容

  • (1)結對實現中綴表達式轉後綴表達式的功能 MyBC.java
    結對實現從上面功能中獲取的表達式中實現後綴表達式求值的功能,調用MyDC.java
    上傳測試代碼運行結果截圖和碼雲連接html

  • (2)結對編程:1人負責客戶端,一人負責服務器
    注意責任歸宿,要會經過測試證實本身沒有問題
    基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
    客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式經過網絡發送給服務器
    服務器接收到後綴表達式,調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
    客戶端顯示服務器發送過來的結果
    上傳測試結果截圖和碼雲連接java

  • (3)加密結對編程:1人負責客戶端,一人負責服務器
    注意責任歸宿,要會經過測試證實本身沒有問題
    基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
    客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密後經過網絡把密文發送給服務器
    服務器接收到後綴表達式表達式後,進行解密(和客戶端協商密鑰,能夠用數組保存),而後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
    客戶端顯示服務器發送過來的結果
    上傳測試結果截圖和碼雲連接git

  • (4)密鑰分發結對編程:1人負責客戶端,一人負責服務器
    注意責任歸宿,要會經過測試證實本身沒有問題
    基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
    客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密經過網絡把密文發送給服務器
    客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
    服務器接收到後綴表達式表達式後,進行解密,而後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
    客戶端顯示服務器發送過來的結果
    上傳測試結果截圖和碼雲連接算法

  • (5)完整性校驗結對編程:1人負責客戶端,一人負責服務器
    注意責任歸宿,要會經過測試證實本身沒有問題
    基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
    客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密經過網絡把密文和明文的MD5値發送給服務器
    客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
    服務器接收到後綴表達式表達式後,進行解密,解密後計算明文的MD5值,和客戶端傳來的MD5進行比較,一致則調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
    客戶端顯示服務器發送過來的結果
    上傳測試結果截圖和碼雲連接編程

2.實驗過程及結果

(1)實驗一

這裏是要求咱們:①結對實現中綴表達式轉後綴表達式的功能 MyBC.java,②結對實現從上面功能中獲取的表達式中實現後綴表達式求值的功能。
由於咱們前面已經作完告終對編程任務——四則運算,這裏作起來就比較簡單,將以前的兩個類調用過來,編寫一個驅動類便可完成實驗一,這裏是驅動類的代碼:數組

public class MyDC
{
    public static void main(String[] args) {
        Questions questions = new Questions();
        String  question = String.valueOf(questions.getQuestion());
        System.out.println("問題:"+question);
        suffix suffix = new suffix();
        String answer = suffix.getAnswer(question);
        System.out.println("後綴:"+answer);
        Calculations calculation = new Calculations();
        String result = calculation.getresult(answer);
        System.out.println("求值:"+result);
    }
}

具體的每一個類的代碼這裏再也不展現,可參見碼雲連接:實驗一
運行的結果截圖如圖:
服務器

(2)實驗二

要求是:①結對編程:一人負責客戶端,另外一人負責服務器;②注意責任歸宿,要會經過測試證實本身沒有問題;③基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP;④客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式經過網絡發送給服務器;⑤服務器接收到後綴表達式,調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端;⑥客戶端顯示服務器發送過來的結果。
這裏是首先須要瞭解Socket通訊是什麼:網絡

網絡上的兩個程序經過一個雙向的通信鏈接實現數據的交換,這個雙向鏈路的一端稱爲一個Socket。Socket一般用來實現客戶方和服務方的鏈接。Socket是TCP/IP協議的一個十分流行的編程界面,一個Socket由一個IP地址和一個端口號惟一肯定。可是,Socket所支持的協議種類也不光TCP/IP一種,所以二者之間是沒有必然聯繫的。在Java環境下,Socket編程主要是指基於TCP/IP協議的網絡編程。數據結構

再來了解如下Socket通訊的過程是怎樣的:
Server 端Listen(監聽)某個端口是否有鏈接請求,Client端向Server端發出Connect(鏈接)請求,Server端向Client端發回 Accept(接受)消息。一個鏈接就創建起來了。Server端和Client端均可以經過Send,Write等方法與對方通訊。
對於一個功能齊全的Socket,都要包含如下基本結構,其工做過程包含如下四個基本的步驟:
-(1) 建立Socket;
-(2) 打開鏈接到Socket的輸入/出流;
-(3) 按照必定的協議對Socket進行讀/寫操做;
-(4) 關閉Socket.(在實際應用中,並未使用到顯示的close,雖然不少文章都推薦如此,不過在個人程序中,可能由於程序自己比較簡單,要求不高,因此並未形成什麼影響。)多線程

簡單瞭解之後,咱們根據老師所給的初始代碼進行修改,這裏是我充當的角色爲服務器,即需接收客戶端傳來的後綴表達式,並進行計算求值,再將結果返回給客戶端,這裏的代碼見下:

package exp5;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.StringTokenizer;
/**
 * Created by besti on 2018/6/9.
 */
public class SocketServer {
    public static void main(String[] args) throws IOException {
        //1.創建一個服務器Socket(ServerSocket)綁定指定端口
        ServerSocket serverSocket=new ServerSocket(8800);
        //2.使用accept()方法阻止等待監聽,得到新鏈接
        Socket socket=serverSocket.accept();
        //3.得到輸入流
        InputStream inputStream=socket.getInputStream();
        BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
        //得到輸出流
        OutputStream outputStream=socket.getOutputStream();
        PrintWriter printWriter=new PrintWriter(outputStream);
        //4.讀取用戶輸入信息
        String info=null;
        info = bufferedReader.readLine();
        System.out.println("我是20172302侯澤洋,用戶20172308周亞傑發送信息爲:" + info);
        Calculations calculations = new Calculations();
        String reply = calculations.getresult(info);
        //給客戶一個響應
        printWriter.write(reply);
        printWriter.flush();
        //5.關閉資源
        printWriter.close();
        outputStream.close();
        bufferedReader.close();
        inputStream.close();
        socket.close();
        serverSocket.close();
    }
}

客戶端的代碼是歸夥伴負責,這裏將碼雲連接給出:
實驗二

運行結果截圖:

(3)實驗三

題目:①客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密後經過網絡把密文發送給服務器;②服務器接收到後綴表達式表達式後,進行解密(和客戶端協商密鑰,能夠用數組保存),而後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端。

這裏是要求的咱們在實驗二的基礎之上,把傳輸內容進行加密,再也不進行明文傳輸,又須要用到咱們所作的實驗三的密碼學算法的內容,又把以前的內容複習了一遍,關於DES加密的過程這裏再也不進行闡述,可參見實驗三博客內容。
這裏須要傳輸的密文是一個byte型的數組,咱們採用字節流直接對它進行傳輸和接收,我負責的服務器端具體代碼見下:

package exp5;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.StringTokenizer;
import static java.awt.SystemColor.info;
/**
 * Created by besti on 2018/6/9.
 */
public class SocketServer {
    public static void main(String[] args) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        //1.創建一個服務器Socket(ServerSocket)綁定指定端口
        ServerSocket serverSocket=new ServerSocket(8800);
        //2.使用accept()方法阻止等待監聽,得到新鏈接
        Socket socket=serverSocket.accept();
        //3.得到輸入流
        InputStream inputStream=socket.getInputStream();
        BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
        //得到輸出流
        OutputStream outputStream=socket.getOutputStream();
        PrintWriter printWriter=new PrintWriter(outputStream);
        //4.讀取用戶輸入信息
        byte[] ctext = inputStream.readAllBytes();
        for(int i=0;i<ctext.length;i++){
            System.out.print(ctext[i]+",");
        }
        System.out.println();
        // 獲取密鑰
        FileInputStream  f3=new FileInputStream("keykb1.dat");
        int num2=f3.available();
        byte[] keykb=new byte[num2];
        f3.read(keykb);
        SecretKeySpec k=new  SecretKeySpec(keykb,"DESede");
        // 解密
        Cipher cp=Cipher.getInstance("DESede");
        cp.init(Cipher.DECRYPT_MODE, k);
        byte[] ptext  = cp.doFinal(ctext);
        // 顯示明文
        String p=new String(ptext,"UTF8");
        System.out.println(p);
        Calculations calculations = new Calculations();
        String reply = calculations.getresult(p);
        //給客戶一個響應
        printWriter.write(reply);
        printWriter.flush();
        //5.關閉資源
        printWriter.close();
        outputStream.close();
        bufferedReader.close();
        inputStream.close();
        socket.close();
        serverSocket.close();
    }
}

夥伴負責的是客戶端的部分,碼雲連接爲:實驗三
運行結果截圖:

(4)實驗四

實驗題目:在實驗三基礎上進行客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換,這裏咱們選擇的是DH算法進行AES算法的密鑰交換,
建立DH算法的公鑰和私鑰:

package experiment4;
import javax.crypto.spec.DHParameterSpec;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
public class Key_DH {
    //三個靜態變量的定義從
// C:\j2sdk-1_4_0-doc\docs\guide\security\jce\JCERefGuide.html
// 拷貝而來
// The 1024 bit Diffie-Hellman modulus values used by SKIP
    private static final byte skip1024ModulusBytes[] = {
            (byte)0xF4, (byte)0x88, (byte)0xFD, (byte)0x58,
            (byte)0x4E, (byte)0x49, (byte)0xDB, (byte)0xCD,
            (byte)0x20, (byte)0xB4, (byte)0x9D, (byte)0xE4,
            (byte)0x91, (byte)0x07, (byte)0x36, (byte)0x6B,
            (byte)0x33, (byte)0x6C, (byte)0x38, (byte)0x0D,
            (byte)0x45, (byte)0x1D, (byte)0x0F, (byte)0x7C,
            (byte)0x88, (byte)0xB3, (byte)0x1C, (byte)0x7C,
            (byte)0x5B, (byte)0x2D, (byte)0x8E, (byte)0xF6,
            (byte)0xF3, (byte)0xC9, (byte)0x23, (byte)0xC0,
            (byte)0x43, (byte)0xF0, (byte)0xA5, (byte)0x5B,
            (byte)0x18, (byte)0x8D, (byte)0x8E, (byte)0xBB,
            (byte)0x55, (byte)0x8C, (byte)0xB8, (byte)0x5D,
            (byte)0x38, (byte)0xD3, (byte)0x34, (byte)0xFD,
            (byte)0x7C, (byte)0x17, (byte)0x57, (byte)0x43,
            (byte)0xA3, (byte)0x1D, (byte)0x18, (byte)0x6C,
            (byte)0xDE, (byte)0x33, (byte)0x21, (byte)0x2C,
            (byte)0xB5, (byte)0x2A, (byte)0xFF, (byte)0x3C,
            (byte)0xE1, (byte)0xB1, (byte)0x29, (byte)0x40,
            (byte)0x18, (byte)0x11, (byte)0x8D, (byte)0x7C,
            (byte)0x84, (byte)0xA7, (byte)0x0A, (byte)0x72,
            (byte)0xD6, (byte)0x86, (byte)0xC4, (byte)0x03,
            (byte)0x19, (byte)0xC8, (byte)0x07, (byte)0x29,
            (byte)0x7A, (byte)0xCA, (byte)0x95, (byte)0x0C,
            (byte)0xD9, (byte)0x96, (byte)0x9F, (byte)0xAB,
            (byte)0xD0, (byte)0x0A, (byte)0x50, (byte)0x9B,
            (byte)0x02, (byte)0x46, (byte)0xD3, (byte)0x08,
            (byte)0x3D, (byte)0x66, (byte)0xA4, (byte)0x5D,
            (byte)0x41, (byte)0x9F, (byte)0x9C, (byte)0x7C,
            (byte)0xBD, (byte)0x89, (byte)0x4B, (byte)0x22,
            (byte)0x19, (byte)0x26, (byte)0xBA, (byte)0xAB,
            (byte)0xA2, (byte)0x5E, (byte)0xC3, (byte)0x55,
            (byte)0xE9, (byte)0x2F, (byte)0x78, (byte)0xC7
    };
    // The SKIP 1024 bit modulus
    private static final BigInteger skip1024Modulus
            = new BigInteger(1, skip1024ModulusBytes);
    // The base used with the SKIP 1024 bit modulus
    private static final BigInteger skip1024Base = BigInteger.valueOf(2);
    public static void main(String args[ ]) throws Exception{
        DHParameterSpec DHP=
                new DHParameterSpec(skip1024Modulus,skip1024Base);
        KeyPairGenerator kpg= KeyPairGenerator.getInstance("DH");
        kpg.initialize(DHP);
        KeyPair kp=kpg.genKeyPair();
        PublicKey pbk=kp.getPublic();
        PrivateKey prk=kp.getPrivate();
        // 保存公鑰
        FileOutputStream  f1=new FileOutputStream(args[0]);
        ObjectOutputStream b1=new  ObjectOutputStream(f1);
        b1.writeObject(pbk);
        // 保存私鑰
        FileOutputStream  f2=new FileOutputStream(args[1]);
        ObjectOutputStream b2=new  ObjectOutputStream(f2);
        b2.writeObject(prk);
    }
}

接下來咱們交換了各自產生的公鑰文件,而後將由公鑰私鑰配對產生密鑰的過程放入到咱們的服務器和客戶端的運行過程當中,服務器端完成的代碼見下:

package exp5;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.StringTokenizer;
import static java.awt.SystemColor.info;
/**
 * Created by besti on 2018/6/9.
 */
public class SocketServer {
    public static void main(String[] args) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, ClassNotFoundException {
        //1.創建一個服務器Socket(ServerSocket)綁定指定端口
        ServerSocket serverSocket=new ServerSocket(9901);
        //2.使用accept()方法阻止等待監聽,得到新鏈接
        Socket socket=serverSocket.accept();
        //3.得到輸入流
        InputStream inputStream=socket.getInputStream();
        BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
        //得到輸出流
        OutputStream outputStream=socket.getOutputStream();
        PrintWriter printWriter=new PrintWriter(outputStream);
        //4.讀取用戶輸入信息
        byte[] ctext = inputStream.readAllBytes();
        for(int i=0;i<ctext.length;i++){
            System.out.print(ctext[i]+",");
        }
        System.out.println();
        // 讀取對方的DH公鑰
        FileInputStream f1=new FileInputStream("Apub.dat");
        ObjectInputStream b1=new ObjectInputStream(f1);
        PublicKey pbk=(PublicKey)b1.readObject( );
        //讀取本身的DH私鑰
        FileInputStream f2=new FileInputStream("Bpri.dat");
        ObjectInputStream b2=new ObjectInputStream(f2);
        PrivateKey prk=(PrivateKey)b2.readObject( );
        // 執行密鑰協定
        KeyAgreement ka=KeyAgreement.getInstance("DH");
        ka.init(prk);
        ka.doPhase(pbk,true);
        //生成共享信息
        byte[ ] sb=ka.generateSecret();
        for(int i=0;i<sb.length;i++){
            System.out.print(sb[i]+",");
        }
        SecretKeySpec k=new  SecretKeySpec(sb,0,24,"AES");
        // 解密
        Cipher cp=Cipher.getInstance("AES");
        cp.init(Cipher.DECRYPT_MODE, k);
        byte[] ptext  = cp.doFinal(ctext);
        // 顯示明文
        String p=new String(ptext,"UTF8");
        System.out.println(p);
        Calculations calculations = new Calculations();
        String reply = calculations.getresult(p);
        //給客戶一個響應
        printWriter.write(reply);
        printWriter.flush();
        //5.關閉資源
        printWriter.close();
        outputStream.close();
        bufferedReader.close();
        inputStream.close();
        socket.close();
        serverSocket.close();
    }
}

客戶端由夥伴完成,碼雲連接:實驗四
運行結果截圖:



(5)實驗五

在實驗四基礎上,服務器接收到後綴表達式表達式後,進行解密,解密後計算明文的MD5值,和客戶端傳來的MD5進行比較,一致則調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端。

仍然須要複習MD5值的加密過程,如下爲MD5加密的代碼過程:

String x = info;
            MessageDigest m2 = MessageDigest.getInstance("MD5");
            m2.update(x.getBytes());
            byte a[] = m2.digest();
            String result = "";
            for (int i = 0; i < a.length; i++) {
                result += Integer.toHexString((0x000000ff & a[i]) | 0xffffff00).substring(6);
            }
            System.out.println(result);
            out.println(result);//經過網絡將明文的Hash函數值傳送到服務器
            str = in.readLine();// 從網絡輸入流讀取結果
            System.out.println("從服務器接收到的結果爲:" + str); // 輸出服務器返回的結果

而後咱們將MD5值以String類型數據進行傳輸,我進行接收,我負責的服務器端的代碼:

package exp5;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.*;
import java.util.StringTokenizer;
import static java.awt.Color.white;
import static java.awt.SystemColor.info;
/**
 * Created by besti on 2018/6/9.
 */
public class SocketServer {
    public static void main(String[] args) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, ClassNotFoundException {
        //1.創建一個服務器Socket(ServerSocket)綁定指定端口
        ServerSocket serverSocket=new ServerSocket(9901);
        //2.使用accept()方法阻止等待監聽,得到新鏈接
        Socket socket=serverSocket.accept();
        //3.得到輸入流
        InputStream inputStream=socket.getInputStream();
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"UTF-8");
        BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
        //得到輸出流
        OutputStream outputStream=socket.getOutputStream();
        PrintWriter printWriter=new PrintWriter(outputStream);
        //4.讀取用戶輸入信息
        String[] array = new String[2];
        String info= null;
        String in =null;
        int i = 0;
        while(!((info = bufferedReader.readLine()) ==null)) {
            array[i] = info;
            i++;
        }
        String ra = array[0];
        StringTokenizer stringTokenizer = new StringTokenizer(ra);
        System.out.println("客戶端傳來的密文:"+ra);
        byte[]  ctext = {-64,-111,-17,100,71,-119,-4,57,-25,-110,-24,-58,-68,48,-124,-126};
        System.out.println();
        String ai = array[1];
        System.out.println("客戶端傳來的MD5值:"+ai);
        System.out.println();
        // 讀取對方的DH公鑰
        FileInputStream f1=new FileInputStream("Apub.dat");
        ObjectInputStream b1=new ObjectInputStream(f1);
        PublicKey pbk=(PublicKey)b1.readObject( );
        //讀取本身的DH私鑰
        FileInputStream f2=new FileInputStream("Bpri.dat");
        ObjectInputStream b2=new ObjectInputStream(f2);
        PrivateKey prk=(PrivateKey)b2.readObject( );
        // 執行密鑰協定
        KeyAgreement ka=KeyAgreement.getInstance("DH");
        ka.init(prk);
        ka.doPhase(pbk,true);
        //生成共享信息
        byte[ ] sb=ka.generateSecret();
        System.out.println("公鑰、私鑰配對產生密鑰爲:");
        for(int x=0;x<sb.length;x++){
            System.out.print(sb[x]+",");
        }
        SecretKeySpec k=new  SecretKeySpec(sb,0,24,"AES");
        // 解密
        Cipher cp=Cipher.getInstance("AES");
        cp.init(Cipher.DECRYPT_MODE, k);
        byte[] ptext  = cp.doFinal(ctext);
        // 顯示明文
        String p=new String(ptext,"UTF8");
        System.out.println();
        System.out.println(p);
        MessageDigest m=MessageDigest.getInstance("MD5");
        m.update(p.getBytes("UTF8"));
        byte s[ ]=m.digest( );
        String result="";
        for (int u=0; u<s.length; u++){
            result+=Integer.toHexString((0x000000ff & s[u]) |
                            0xffffff00).substring(6);
                }
                System.out.println("解密後獲得的後綴表達式的MD5值"+result);
        if (result.equals(ai)){
            System.out.println("明文的MD5和客戶端傳來的MD5值相等,則計算並求值發送給客戶端");
            Calculations calculations = new Calculations();
            String reply = calculations.getresult(p);
            //給客戶一個響應
            printWriter.write(reply);
            printWriter.flush();
        }
        //5.關閉資源
        printWriter.close();
        outputStream.close();
        bufferedReader.close();
        inputStream.close();
        socket.close();
        serverSocket.close();
    }
}

夥伴的代碼見下:

package experiment4;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.Socket;
import java.security.*;
import java.util.Scanner;
/**
 * Created by besti on 2018/6/9.
 */
public class SocketClient {
    public static void main(String[] args) throws IOException, InvalidKeyException, ClassNotFoundException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException {
        //1.創建客戶端Socket鏈接,指定服務器位置和端口
//        Socket socket = new Socket("localhost",8080);
        Socket socket = new Socket("172.16.43.121",9901);
        //2.獲得socket讀寫流
        OutputStream outputStream = socket.getOutputStream();
        //       PrintWriter printWriter = new PrintWriter(outputStream);
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
        //輸入流
        InputStream inputStream = socket.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
        //3.利用流按照必定的操做,對socket進行讀寫操做
        System.out.println("請輸入一個問題:");//輸入中綴
        Scanner scan =new Scanner(System.in);
        String info2 =scan.nextLine();
        suffix suffix = new suffix();
        String info1 = suffix.getAnswer(info2);//轉後綴
        System.out.println("後綴:"+info1);
        System.out.println();
        System.out.println("密鑰:");
        // 讀取對方的DH公鑰
        FileInputStream f1=new FileInputStream("Bpub.dat");
        ObjectInputStream b1=new ObjectInputStream(f1);
        PublicKey  pbk=(PublicKey)b1.readObject( );
//讀取本身的DH私鑰
        FileInputStream f2=new FileInputStream("Apri.dat");
        ObjectInputStream b2=new ObjectInputStream(f2);
        PrivateKey  prk=(PrivateKey)b2.readObject( );
        // 執行密鑰協定
        KeyAgreement ka= KeyAgreement.getInstance("DH");
        ka.init(prk);
        ka.doPhase(pbk,true);
        //生成共享信息
        byte[ ] sb=ka.generateSecret();
        for(int i=0;i<sb.length;i++){
            System.out.print(sb[i]+",");
        }
        SecretKeySpec k=new SecretKeySpec(sb,0,24,"AES");//生成密鑰
        Cipher cp=Cipher.getInstance("AES");
        cp.init(Cipher.ENCRYPT_MODE, k);
        byte ptext[]=info1.getBytes("UTF8");
        for(int i=0;i<ptext.length;i++){
            System.out.print(ptext[i]+",");
        }
        System.out.println("");
        byte ctext[]=cp.doFinal(ptext);
        for(int i=0;i<ctext.length;i++){
            System.out.print(ctext[i] +",");
        }
        System.out.println();
        FileOutputStream f3=new FileOutputStream("SEnc.dat");//密文加密
        f3.write(ctext);
        String x=info1;
        MessageDigest m=MessageDigest.getInstance("MD5");
        m.update(x.getBytes("UTF8"));
        byte s[ ]=m.digest( );
        String result="";
        for (int i=0; i<s.length; i++){
            result+=Integer.toHexString((0x000000ff & s[i]) |
                    0xffffff00).substring(6);
        }
        System.out.println("明文的MD5值:"+result);
        String ai ="";
        for (int i=0;i<ctext.length;i++)
        {
            ai+=ctext[i]+" ";
        }
        System.out.println("密文:"+ai);
        outputStreamWriter.write(ai+"\n"+result);//傳輸密文
        outputStreamWriter.flush();
        socket.shutdownOutput();
        //接收服務器的響應
        String reply = null;
        reply = bufferedReader.readLine();
        System.out.println("結果:"+reply);
        //4.關閉資源
        bufferedReader.close();
        inputStream.close();
        //printWriter.close();
        outputStream.close();
        socket.close();
    }
}

咱們完成的實驗的碼雲連接:實驗五
運行的結果截圖:

3. 實驗過程當中遇到的問題和解決過程

  • 問題1:進行第三個實驗時,咱們遇到了一些問題,即將字節型數組的密文轉換成String類型時,傳輸過來時,老是會出現亂碼,結果致使沒有辦法解密。

  • 問題1解決方案:這裏顯示的密文是不合法的,咱們在這裏卡了好久,最後採用的是再也不進行轉換成String類型的轉換,咱們直接將密文的byte數組使用字節流傳輸,接收時使用一個byte的數組進行接收,這裏就沒有問題了,具體代碼是客戶端是outputStream.write(ctext);outputStream.flush();,服務器是byte[] ctext = inputStream.readAllBytes();,最後就是這樣,將密文傳輸過來,並完成後續步驟。

  • 問題2:實驗四時,咱們一開始採用的用DH算法對DES加密進行產生密文,可是在加密時,這裏的始終是DH算法產生的密鑰格式存在問題,問題具體見圖:

  • 問題2解決方案:最後咱們採用了夥伴提出的使用AES進行加密,可是這裏也遇到了些問題,依舊加密過程存在問題,詢問了餘坤澎他們小組,對一處進行修改後完成,修改的內容爲由SecretKeySpec k=new SecretKeySpec(sb,"AES");改成SecretKeySpec k=new SecretKeySpec(sb,0,24,"AES");,經過查詢API文檔,咱們對這裏有了必定了解。

  • 問題3:實驗5中咱們將byte數組的密文直接轉換成了String類型,傳輸過去就會出現以下圖這樣的一串應密文的數字格式:

  • 問題3解決方案:把兩條數據都寫在一個輸出語句中。但這樣就有兩種作法:一是把字節型的密文轉換成字符串類型;二是把字符串類型的MD5值寫進存放密文的字節數組。咱們選擇了前者,可是致使的問題就是如問題5所敘述的那樣,客戶端輸出的結果是正確無誤的,可是傳到服務器端以後,顯示出來的就是如上圖所示,這個咱們實在是沒有一點辦法,徹底也不懂,最後咱們的解決方案是將byte數組中每一個元素取出,寫入一個String字符串中,而後接收這個字符串後將逐個拿出放入byte數組中,從而實現了密文的傳遞。

其餘(感悟、思考等)

  • 本週的進行的實驗,也是Java程序設計的學習的尾聲了,一個學期下來學會的很多,但沒學會的也有不少。此次的實驗有些懈怠,本身沒有太多的去想遇到的問題的解決辦法,但願下個學期能拿出更加認真的態度去學習每一個知識點,遇到的問題也要更多的去本身去想解決辦法。

參考資料

相關文章
相關標籤/搜索